I know there's many similar question but I had no luck finding a nice and clean solution if it's possible at all.
I'm implementing a generic interface with subclasses of an abstract type. Problem is that when I'm calling them I either must do type cast in a switch/case or cast type in every method inside interface implementations and I can't figure out a nice and clean approach... I'll better just write down a short example.
// An abstract type with 2 implementations...
public abstract class ObjTypeAbstract {}
public class ObjType extends ObjTypeAbstract {}
public class ScriptType extends ObjTypeAbstract {}
Now the processor for both types with an interface
interface ProcessorInterface<T extends ObjTypeAbstract> {
public void abcMethod(T obj);
}
public class ObjProcessor implements ProcessorInterface<ObjType> {
public void abcMethod(ObjType obj) {}
}
public class ScriptProcessor implements ProcessorInterface<ScriptType> {
public void abcMethod(ScriptType obj) {}
}
What I'm struggling with is a way of calling those processors based on ObjAbstractType. I have a single class that servers as middleware?? or how should I call it.:
Idea was to simple get the right processor via a single switch/case:
public class Processor {
private ProcessorInterface objProcessor = new ObjProcessor();
private ProcessorInterface scriptProcessor = new ScriptProcessor();
public methodAbc(ObjAbstractType obj) {
getProcessor(obj).abcMethod(obj);
}
private ProcessorInterface getProcessor(ObjAbstractType obj) {
if (obj instanceof ObjType) {
return objectProcessor;
} else if (obj instanceof ScriptType) {
return scriptProcessor;
}
return nullProcessor;
}
}
This is what I'd like to have, it also takes care of type casting of objAbstract to actual type for abcMethod, problem is that it results in RawType warning which won't break the code, but I'd like to get rid of it.
And thats where I'm stuck... because if I cast processors to specific type like this:
private ProcessorInterface<ObjType> objProcessor = new ObjProcessor();
private ProcessorInterface<ScriptType> scriptProcessor = new ScriptProcessor();
I won't be able to return an abstract one from getProcessor method so I would have to implement those interfaces with an ObjAbstractType with all it's method and have type casting in all methods of every processor like:
public class ScriptProcessor implements ProcessorInterface<ObjAbstractType> {
public void abcMethod(ObjAbstractType obj) {
ScriptType scr = (ScriptType) obj;
}
}
The other solution might be having a switch/case inside Processor middleware class and cast ObjAbstractType in it, but I'd have to write that switch inside abcMethod and all others or from getProcessor method returns both the Processor and casted ObjType... so I'd have to return some dto containing both. :/
Do you have any ideas / patterns that might help me to get rid of RawType call warning without extending the code with more switch/case or type casts?
Wish you a nice day and I'll be glad for any discussion, David.
You need a way to store the mapping between a ObjTypeAbstract class and a ProcessorInterface instance.
You could use a Map that associates ObjTypeAbstracts (as key) to ProcessorInterfaces (as value).
About the raw type issue, you could use ProcessorInterface<? extends ObjTypeAbstract> for the declared variable but you will still need to perform a unsafe cast to ProcessorInterface<ObjTypeAbstract> to be able to invoke ProcessorInterface.abcMethod() with as parameter a ObjTypeAbstract declared type.
This cast is unavoidable with your actual design.
It could give something like :
public class Processor {
private Map<Class<? extends ObjTypeAbstract>, ProcessorInterface<? extends ObjTypeAbstract >> map = new HashMap<>();
public Processor(){
map.put(ObjType.class, new ObjProcessor());
map.put(ScriptType.class, new ScriptProcessor());
}
public void methodAbc(ObjTypeAbstract obj) {
#SuppressWarnings("unchecked")
ProcessorInterface<ObjTypeAbstract> processorInterface = (ProcessorInterface<ObjTypeAbstract>) map.get(obj.getClass());
processorInterface.abcMethod(obj);
}
}
I don't think there is a substantially more elegant way to get around some form of instanceof logic. However, there should not be need for casting, if you add some types to getProcessor.
public <T extends ObjTypeAbstract> ProcessorInterface<T> getProcessor(Class<T> theClass) {
if (theClass.isAssignableFrom(ObjType.class)) {
return objProcessor;
} else if (theClass.isAssignableFrom(ScriptType.class)) {
return scriptProcessor;
}
return null;
}
This can then be called like this:
ProcessorInterface<ScriptType> scriptProcessor = new Processor().getProcessor(ScriptType.class);
ProcessorInterface<ObjType> objProcessor = new Processor().getProcessor(ObjType.class);
Related
I am currently writing an XML converter for a supply chain project. We use Requests and Orders.
The converter has multiple method that currently do same but are separately implements for requests and orders.
I have therefore created an abstract class to improve maintainability of the code and used a generic type:
public abstract class AbstractConverter<T extends BusinessObject>
Then I have the specific implementations for the actual converters
public class OrderConverter extends AbstractConverter<Order>
public class RequestConverter extends AbstractConverter<Request>
As I said, I have several methods in the two specific classes that basically do the same, so I naturally want them in the abstract class. I have now added the following method to the abstract class:
protected Comment createComment(T obj) {
String remark;
if (obj instanceof Order) {
remark = ((Order) obj).getRemark();
} else if (obj instanceof Request) {
remark = ((Request) obj).getRequestRemark();
} else {
throw new IllegalArgumentException("This method does not support objects of the type " + obj.getClass().toString());
}
return new Comment(remark);
}
My question now is: is this the way to go or is there a more elegant way to use generics in this context?
I need this solved but I also want to use good style.
The natural object oriented solution is to make createComment an abstract method
protected abstract Comment createComment(T obj);
and let the subclasses implement it:
public class OrderConverter extends AbstractConverter<Order> {
protected Comment createComment(Order order) {
return new Comment(order.getRemark());
}
}
public class RequestConverter extends AbstractConverter<Request> {
protected Comment createComment(Request request) {
return new Comment(request.getRequestRemark());
}
}
I'd suggest extracting the getRemark method to an interface which both Request and Order implements.
That way you can simply check if the incoming generic object is an instance of the interface.
protected Comment createComment(T obj) {
if (obj instanceof Remarkable) {
return new Comment(((Remarkable) obj).getRemark());
}
throw new IllegalArgumentException("This method does not support objects of the type " + obj.getClass().toString());
}
I have an interface with a type parameter that allows its conversion into the same type with another type parameter. Like this:
interface Interfaze<A> {
public <B> Interfaze<B> convert(java.util.function.Function<A, B> f);
}
I now want to impose a stricter requirement on the return type: I want the convert method to only return the same type as it was called on. Like this:
class GoodInterfaze<A> implements Interfaze<A> {
public <B> Interfaze<B> convert(java.util.function.Function<A, B> f) {
// return new GoodInterfaze<B>(); // I want this to be allowed by compiler
// return new BadInterfaze<B>(); // I want this to be a compilation error
return null;
}
}
class BadInterfaze<A> implements Interfaze<A> {
public <B> Interfaze<B> convert(java.util.function.Function<A, B> f) {
// return new GoodInterfaze<B>(); // I want this to be a compilation error
// return new BadInterfaze<B>(); // I want this to be allowed by compiler
return null;
}
}
The Interfaze interface is under my control, so I can add extra type parameters to it (or its methods) when needed. Do Java generics allow for anything like this?
You can get close by doing this.
public interface Interfaze<T extends Interfaze<T>> {
T convert();
}
Then you can do
public class Main {
public static class Good implements Interfaze<Good> {
#Override
public Good convert() { return new Good(); } // Compiles
}
public static class Bad implements Interfaze<Bad> {
#Override
public Bad convert() { return new Good(); } // Doesn't compile
}
}
This idea of using recursive bounds like this is very common. I personally dislike it as it's very confusing and because it doesn't mix well with inheritance. For example, you can't make a subclass SubGood of Good that implements Interfaze<SubGood> because you can't implement the same generic interface with 2 different type arguments. It only really works if all implementing classes cannot be extended (that's why Enum<E extends Enum<E>> is ok).
I am sorry about putting the error directly as the title, but I couldn't find any better title.
I have an interface defined as following to be used as a blueprint for all my validator classes:
public interface Validator<T> {
public boolean validate(T item);
}
And then I have some classes that would implement it, lets say one of them is this:
public class EmptyStringValidator implements Validator<String> {
private final String _errorMessage;
public EmptyStringValidator() {
this("String cannot be empty.");
}
public EmptyStringValidator(String message) {
this._errorMessage = message;
}
#Override
public String getMessage() {
return this._errorMessage;
}
#Override
public boolean validate(String item) {
return gsi.application.core.Validation.isEmptyString(item);
}
}
I would like to put it all in an array and call it all in one loop. So this is the code I am using:
public List<Validator<? extends Object>> validators;
public FormItem<T> addValidator(Validator<? extends Object> validator) {
this.validators.add(validator);
return this;
}
public boolean validate() {
for (Validator<? extends Object> validator : this.validators)
if (!validator.validate(this.getInputValue())) {
this._errorMessage = validator.getMessage();
return false;
}
return true;
}
However, that code is giving an error at the validate() function, specifically at this part:
validator.validate(this.getInputValue())
It gives me the error that I have mentioned
The method validate(capture#2-of ? extends Object) in the type Validator<capture#2-of ? extends Object> is not applicable for the arguments (String)
which to my understanding doesn't makes sense. To my understanding <? extends Object> should accept anything that derives from the Object class, right?
Could anyone point out what am I doing wrong or point me at the right direction?
Thanks.
As an aside, ? extends Object is no different from saying ?. That isn't the root of your problem, however.
The issue is that validators is a List<Validator<? extends Object>>. In other words, each element can be any kind of Validator<T>, not necessarily a Validator<String>. So you can put a Validator<String> into it, but when you pull an element out you don't know what kind of Validator it is, and so you don't know if it is compatible with the type returned by this.getInputValue().
The simplest fix would be to specify a concrete type (eg: String) for the type parameter. A more complicated fix would be to use a type variable in place of ? extends Object, and have getInputValue()'s type signature use that same type variable. You need to constrain the types such that getInputValue()'s return type is assignable to the parameter of validate().
An even better type for collected validators generally is Validator<? super T>, where T is the input type, in this case String.
This way addValidator(Validator<? super String> validator) accepts Validator<String> but also Validator<CharSequence> and Validator<Object>.
For example:
class LongerThan10 implements Validator<CharSequence> {
#Override
public boolean validate(CharSequence item) {
return item.length() > 10;
}
}
formItem.addValidator(str -> !str.isBlank())
formItem.addValidator(new LongerThan10());
In this specific case it makes not much sense, but it is a good idea to accept validators that work with super types generally.
I'm not very used to generics, so I'm a little confused here about how I'm supposed to solve this problem. I've written a method that tries to call different methods at runtime. But I'm getting a ClassCastException although the code seems syntactically correct.
I have the following classes (some getters and setters were omitted for brevity):
public interface Transporte extends Serializable {
private int id;
private String name;
public abstract int getId() { return this.id; }
public abstract String getName() { return this.name; }
}
public class Barco implements Transporte { /* ... */ }
public class Estacao implements Transporte { /* ... */ }
public class Paragem implements Transporte { /* ... */ }
public class Entidade extends Serializable {
private List<Barco> barcos;
private List<Estacao> estacoes;
private List<Paragem> paragens;
public List<Barco> getBarcos() { return this.barcos; }
public List<Estacao> getEstacoes() { return this.estacoes; }
public List<Paragem> getParagens() { return this.paragens; }
}
And the method I'm trying to implement and have difficulties with:
public <T extends Transporte> List<T> intersectTransportes(Entidade entidade, List<T> transportes) {
if(entidade==null || transportes==null) return null;
T typeOfTransport = (T) new Object(); /* <--- HERE'S THE PROBLEM (?) */
List<T> result = new ArrayList<T>();
List<Integer> ids = null;
if(typeOfTransport instanceof Barco) ids = entidade.getIdBarcos(); else
if(typeOfTransport instanceof Estacao) ids = entidade.getIdEstacoes(); // else ...
// now do the work
for(Transporte t : transportes) {
for(Integer id : ids) {
if(t.getId()==id) result.add((T) t);
}
}
return result;
}
Please notice that I'm using <T extends Transporte> instead of <T implements Transporte> as I'd expect Java to allow. But that latter syntax is invalid, so I have to use implements instead...
The method is being invoked as illustrated here:
List<Estacao> allStations;
List<Estacao> myStations = intersectTransportes(entidade, allStations);
What I'm trying to do here is to identify the actual type used at runtime when invoking the method. In this case, insersectTransportes should be able to recognize the particular List of Transporte-implementing objects I'm using.
I suspect that I'm supposed to use something other than
T typeOfTransporte = (T) new Object();
since obviously that's the line where the runtime exception is being produced. However, I'm not quite sure how to solve this. Any indications to the solution (or specific bibliography approaching this problem) is appreciated.
The problem is:
a) you can't new your generic type - it's erased at runtime
b) Object does not extend Transporte, so it cant be cast to T
You need to pass the class to your method:
public <T extends Transporte> List<T> intersectTransportes(Entidade entidade, List<T> transportes, Class<T> clazz) {
...
T typeOfTransporte = clazz.newInstance();
T typeOfTransport = (T) new Object(); /* <--- HERE'S THE PROBLEM (?) */
The problem is rather obvious, an object is not a "Type of Transport" (does not implement or extends the Transport interface).
You will get the same error with this example:
String myStr = (String) new Object();
T typeOfTransport = (T) new Barco(); //new Barco() or anything that implements Transport interface
You must instantiate a specific class there, but not any class like Object. The class must implement Transport interface.
Of course there is a problem with (T) new Object(). When you call new Object() it creates instance of class Object, thats it. You cant just cast it to something useful.
Try writing your method like this:
public <T extends Transporte> List<T> intersectTransportes(Entidade entidade, List<T> transportes, Class<T> clasz)
and use reflection.
You should pass in a Factory that deals with creating the new Transporte, with a method (probably using a switch) createNew(Class<? extends T> transporteClass).
You should also look into using either commons-collections or the guava libraries, which have the kind of intersection methods you're looking for, saving you the trouble of writing this code.
i've stumbled upon a curiosity in the java inheritance, and I wanted you to ask for better ideas on that:
Assume two interfaces A and A1
Interface A1 extends A
Interface A has a method which returns a generic type.
The generic type would be like GenericType<T>.
A basic idea is now to change this generic return type from
GenericType<Object> in Interface A into
GenericType<String> in Interface A1
Well seems to be easy at first (bad things will come later on)
We declare Interface A like
public interface InterfaceA {
public GenericType<? extends Object> getAGenericType();
}
and Interface A1 like
public interface InterfaceA1 extends InterfaceA
{
#Override
public GenericType<String> getAGenericType();
}
As you see we are forced to write GenericType<? extends Object> in Interface A itself to allow overriding it with generic based "subclasses".
(In fact the generic parameter of the generictype is subclassed not the generic type itself)
Now assume the GenericType has its own method looking like:
public interface GenericType<D>
{
public void doSomethingWith( D something );
}
Now trying to instantiate A1 works great.
Rather trying to instantiate A will suck. To see why look at this "use the interface" class:
public class LookAtTheInstance
{
#SuppressWarnings("null")
public static void method()
{
InterfaceA a = null;
InterfaceA1 a1 = null;
GenericType<String> aGenericType = a1.getAGenericType();
GenericType<? extends Object> aGenericType2 = a.getAGenericType();
Object something = null;
aGenericType2.doSomethingWith( something );
}
}
You ask: "And now?"
It does not work on the last lines. In fact the parameter "something" is not even from type "Object" it is from Type "? extends Object". So you cannot pass the declared "Object" type. You can't pass anything at all.
So you end up declaring nice interfaces which, as it turns out, cannot be instantiated right.
Do you have ideas how to model such a use case, where the subclasses will have to override the return type, while the return type is a generics?
Or how would you go around such a model case?
Or am I just missing a simple point in the generic declaration and my example is possible this way?
----------- (1) edit due to answers -----------
A very good basic idea is making the interface A more abstract! I had exactly the same idea first, but... (this has to come)
Assume doing this:
We introduce a new interface AGeneric
public interface InterfaceAGeneric<T>{
public GenericType<T> getAGenericType();
}
Now we will have to extend A and A1 from this new interface:
public interface InterfaceA extends InterfaceAGeneric<Object>{}
public interface InterfaceA1 extends InterfaceAGeneric<String>{}
That works fine, althought it breaks the path of the original inheritance.
If we want A1 still be extendable from A, we have to change A1 to
public interface InterfaceA1 extends InterfaceA, InterfaceAGeneric<String>{}
and there a problem is again. This does not work, since we extend indirectly the same interface with different generic types. This is unfortunately not allowed.
You see the problem?
-
And to point to another circumstance:
If you cast the GenericType<? extends Object> to GenericType<Object> it obviously works.
Example:
public class LookAtTheInstance
{
public static void main( String[] args )
{
InterfaceA a = new InterfaceA()
{
#Override
public GenericType<? extends Object> getAGenericType()
{
return new GenericType<Object>()
{
#Override
public void doSomethingWith( Object something )
{
System.out.println( something );
}
};
}
};
;
#SuppressWarnings("unchecked")
GenericType<Object> aGenericType2 = (GenericType<Object>) a.getAGenericType();
Object something = "test";
aGenericType2.doSomethingWith( something );
}
}
So it seems for me that the resolving of the parameter type of the method
public interface GenericType<D extends Object>
{
public void doSomethingWith( D something );
}
is wrong.
If D is unified with "? extends Object" why the parameter type is not forced to be "Object"?
Wouldnt this make more sence?
A basic idea is now to change this generic return type from GenericType in Interface A into GenericType in Interface A1
This is not possible, because Java Generics are invariant. [1]
As you found out, you cannot have an interface declaring a method that returns GenericType<Object> and in a sub interface override the method to return GenericType<String>: The latter return type is not a subtype of the former. And for good reason!
You tried to
extend indirectly the same interface with different generic types. This is unfortunately not allowed.
There is no way this could possibly work: E.g. what should be the type of E in public E set(int index, E element) in a class that implemented both List<String> and List<Object>? Your subclassed interface would have to produce a similar hybrid: The return value of getAGenericType in the sub interface would have to implement both the GenericType<String> and the GenericType<Object> interface. And as we saw, this is impossible.
The compiler does not know what you are going to do with the type parameter in GenericType (although it theoretically could find out, it doesn't). If you had a variable of type GenericType<String> and assigned a GenericType<Object> to it, you may very well end up putting a Long instance where a String is expected, and get a ClassCastException where you won't expect one.
In the doSomethingWith method of your variable GenericType<? extends Object> aGenericType2 you can pass one thing: null. null is the only object reference that has a subtype of ? extends Object. The lower bound type of ? extends Object is the null type, which cannot be expressed in Java, and only implicitly exists as the type of the null reference.
[1] http://en.wikipedia.org/wiki/Covariance_and_contravariance_%28computer_science%29#Java
I don't know if this is what you are expecting, but you can declare your interface something like:
public interface Interface <K extends Object> { ... }
While your class might look like:
public class InterfaceImpl implements Interface<String> { ... }
#Override annotation:
When overriding a method, you might
want to use the #Override annotation
that instructs the compiler that you
intend to override a method in the
superclass. If, for some reason, the
compiler detects that the method does
not exist in one of the superclasses,
it will generate an error.
With this annotation you cannot change return type of function.
If you want to override return type, just make interface A more abstract, add generic to this interface:
public interface InterfaceA<T> {
public GenericType<T> getAGenericType();
}
Sample about overriding a generic method in a generic class.
The trouble is that InterfaceA doesn't know what type it's holding. If you get InterfaceA to take a generic argument then you could do this:
public interface InterfaceA<T>
{
public GenericType<T> getAGenericType();
}
public interface InterfaceA1 extends InterfaceA<String>
{
#Override
public GenericType<String> getAGenericType();
}
public class LookAtTheInstance
{
#SuppressWarnings("null")
public static void method()
{
InterfaceA<String> a = null;
InterfaceA1 a1 = null;
GenericType<String> aGenericType = a1.getAGenericType();
GenericType<String> aGenericType2 = a.getAGenericType();
String something = null;
aGenericType2.doSomethingWith( something );
}
}
I'm several years late to the party, but I found this page while searching for a related question and none of the answers really hit on the central issue, which I think is worth clarifying. Let's look at a slightly-more-fleshed-out example:
interface GenericType<D> {
D getAValue();
void doSomethingWith(D value);
}
class StringType implements GenericType<String> {
#Override
public String getAValue() {
return "Hello World";
}
#Override
public void doSomethingWith(final String value) {
System.out.println(value.length());
}
}
interface InterfaceA {
GenericType<? extends Object> getAGenericType();
}
interface InterfaceA1 extends InterfaceA {
#Override
GenericType<String> getAGenericType();
}
class AnActualA1 implements InterfaceA1 {
#Override
public GenericType<String> getAGenericType() {
return new StringType();
}
}
class LookAtTheInstance {
public static void method() {
InterfaceA1 a1 = new AnActualA1();
// 'g1' is a StringType, which implements GenericType<String>; yay!
GenericType<String> g1 = a1.getAGenericType();
// Everything here is fine.
String value = g1.getAValue();
g1.doSomethingWith("Hello World");
// But if we upcast to InterfaceA???
InterfaceA a = (InterfaceA) a1;
// Note: a.getAGenericType() still returns a new StringType instance,
// which is-a GenericType<? extends Object>.
GenricType<? extends Object> g = a.getAGenericType();
// StringType.getAValue() returns a String, which is-an Object; yay!
Object object = g.getAValue();
// StringType.doSomethingWith() method requires a String as the parameter,
// so it is ILLEGAL for us to pass it anything that cannot be cast to a
// String. Java (correctly) prevents you from doing so.
g.doSomethingWith(new Object()); // Compiler error!
}
}
Conceptually, GenericType is NOT a GenericType, since a GenericType can only doSomethingWith() Strings, while a GenericType needs to be able to doSomethingWith() any object. GenericType is a compromise which the compiler allows you to use as a "base class" for any GenericType where D is-an Object, but only allows you to use a reference of that type to call methods that are type-safe for any possible runtime value of '?' (such as getAValue(), whose return value can always be safely cast to an Object since D is-an Object regardless of runtime type).
It's hard to tell what (if anything) the original poster was actually trying to model with this code, and in particular how much of the generic-ness of GenericType was really needed, but perhaps the inheritance should have gone the other way around?
/**
* I can do something with instances of one particular type and one particular
* type only.
*/
interface GenericType<D> {
void doSomethingWith(D value);
}
/**
* I can do something with instances of any type: I am-a GenericType<String>
* because I can totally do something with a String (or any other kind of
* Object).
*/
interface NonGenericType extends GenericType<Object>, GenericType<String> {
#Override
void doSomethingWith(Object value);
}
interface StringHandlerFactory { // nee InterfaceA1
GenericType<String> getAGenericType();
}
/**
* I extend StringHandlerFactory by returning a NonGenericType (which is-a
* GenericType<String>, satisfying the interface contract, but also so much
* more).
*/
interface ObjectHandlerFactory extends StringHandlerFactory { // nee InterfaceA
#Override
NonGenericType getAGenericType();
}
The downside being that there's no good way to express to the java compiler that NonGenericType extends GenericType, even though conceptually it could in this case, since GenericType never uses D as a return value. You have to manually specify each GenericType that you want it to extend. :(
So you end up declaring nice interfaces which, as it turns out, cannot be instantiated right.
I think that the purpose of InterfaceA is not to be instantiated at all, because one of its dependable classes are generic. That's what you meant declaring:
public GenericType<? extends Object> getAGenericType()