Java: generics method and type identification - java

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.

Related

Using self-referential generic types in Java

Consider the following Java method:
<T extends List<T>> List<T> getMyList() {
return Collections.emptyList();
}
I can assign its output to a variable with a raw type, like so:
List x = getMyList();
List<List> y = getMyList();
But, I can't think of any way to assign its output to a fully parameterized type. In particular, I can't think of a non-raw, concrete type T that would satisfy List<T> z = getMyList();
Can we create such a T ?
If not, why not?
For context, I created this question while trying to understand how Enums are implemented in Java.
Here's an example of a concrete type that both works and starts to hint at a possible use-case (registration of some sort). The type consists acts like both an instance of some type, and as a container for all instances of that type.
public class WeirdEnum extends AbstractList<WeirdEnum> {
private static List<WeirdEnum> underlyingList = new ArrayList<>();
#Override
public WeirdEnum get(int index) { return underlyingList.get(index); }
#Override
public int size() { return underlyingList.size(); }
static <T extends List<T>> List<T> getAList() {
return Collections.emptyList();
}
public WeirdEnum() {
underlyingList.add(this); // Sufficient for our example but not a good idea due to concurrency concerns.
}
static List<WeirdEnum> foo = WeirdEnum.getAList();
}
Not sure if I fully understand your question, but here's an example:
class Example<T> implements List<Example<T>> {
...
}
...
List<Example<String>> list = getMyList();
Every enum in Java extends from the base-enum-class Enum<T extends Enum<T>>, where T is the actual type of the implementing enum.
When writing SomeClass<T extends SomeClass<T>> you can enforce that the type-parameter is always the implementing class itself.
Let's say you have this interface:
public interface MyInterface<T extends MyInterface<T>> {
T getSelf();
}
And this implementing class:
public class MyClass implements MyInterface<MyClass> {
public MyClass getSelf() {
return this;
}
}
In MyClass it is not possible to use any other type-parameter than MyClass itself.

Java generic interface calling with abstract parameter

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);

Parameterized classes and methods: making a method returns a correct type with java generics

I have a class AbstractExtractionRules which constructor receives a ParserAPI object. The AbstractExtractionRules will be implemented using many different Parser APIs and each uses its own abstraction of 'Document'.
ParserAPI class has a parameterized type that represents the return type for the method parseDocument.
I want a way to use the ParserAPI in AbstractExtractionRules subclasses without the need of cast, leaving it in a more natural way.
I think with java generics, perhaps modifying the constructor parameter accordingly or modifying the call for getParserAPI().parseDocument(htmlCode) I can reach this, but I do not know how to do.
#FunctionalInterface
public interface ExtractionRules<T> {
List<T> extract(String htmlCode);
}
public interface ParserAPI<T> {
T parseDocument(String htmlCode);
}
public abstract class AbstractExtractionRules <T> implements ExtractionRules <T> {
private ParserAPI<?> parserAPI;
public AbstractExtractionRules(ParserAPI<?> parserAPI) {
this.parserAPI = parserAPI;
}
public ParserAPI<?> getParserAPI() {
return parserAPI;
}
}
public class RibeiraoVisitorRule extends AbstractExtractionRules <String> {
public RibeiraoVisitorRule(ParserAPI<Document> parserAPI) {
super(parserAPI);
}
#Override
public List extract(String htmlCode) {
List<String> list = new ArrayList<>();
Document doc = (Document) getParserAPI().parseDocument(htmlCode);
Elements submenu = doc.select("a.new_sub_menu");
submenu.forEach(element1 -> {
String href = element1.attr("abs:href");
list.add(href.concat("&pageNum=VER-TUDO"));
});
return list;
}
}
You can pass type from AbstractExtractionRules to ParserAPI:
public abstract class AbstractExtractionRules<A, T> implements ExtractionRules<T> {
private ParserAPI<A> parserAPI;
Then you can call it without cast in concrete implementation class:
public class RibeiraoVisitorRule extends AbstractExtractionRules<Document, String> {
#Override
public List<String> extract(String htmlCode) {
...
Document doc = getParserAPI().parseDocument("");
}
Note that I also added passing type T to ExtractionRules interface. It affects the return type of extract() method. In your example you did not pass the type so return type of the method was List.

Generics: Creating parameterized class argument

How does one get a parameterized Class object to be used as a method argument?
class A<T>
{
public A(Class<T> c)
{
}
void main()
{
A<String> a1 = new A<String>(String.class); // OK
A<List<String>> a2 = new A<List<String>>(List<String>.class); // error
A<List<String>> a3 = new A<List<String>>(Class<List<String>>); // error
}
}
Why do I want to do that, you may ask? I have a parameterized class whose type is another parameterized class, and whose constructor requires that other class type as an argument. I understand that runtime classes have no information on their type parameters, but that shouldn't prevent me from doing this at compile time. It seems that I should be able to specify a type such as List<String>.class. Is there another syntax to do this?
Here is my real usage case:
public class Bunch<B>
{
Class<B> type;
public Bunch(Class<B> type)
{
this.type = type;
}
public static class MyBunch<M> extends Bunch<List<M>>
{
Class<M> individualType;
// This constructor has redundant information.
public MyBunch(Class<M> individualType, Class<List<M>> listType)
{
super(listType);
this.individualType = individualType;
}
// I would prefer this constructor.
public MyBunch(Class<M> individualType)
{
super( /* What do I put here? */ );
this.individualType = individualType;
}
}
}
Is this possible?
How about just cast?
super((Class<List<M>>)List.class);
Class literals are not going to have the type parameters that you want.
Remember you will NOT get a List as a class in runtime, and the right approach would probably be using TypeToken as BalusC told you. Without TypeToken, you can't cast to List, but you can create something like this:
public static class MyBunch2<List_M extends List<M>, M> extends Bunch<List_M>
{
Class<M> individualType;
#SuppressWarnings("unchecked")
public MyBunch2(Class<M> individualType)
{
super((Class<List_M>) List.class);
this.individualType = individualType;
}
}
Since List_M extends List<M> this is not as typesafe as you may wish, but maybe is nice enough. Creating an instance will be as ugly as writing
MyBunch2<List<String>, String> a = new MyBunch2<List<String>, String>(String.class);
but you can improve it with a factory method
public static <M2> MyBunch2<List<M2>, M2> of(Class<M2> individualType){
return new MyBunch2<List<M2>, M2>(individualType);
}
and then write
MyBunch2<List<String>, String> b = MyBunch2.of(String.class);
If you are using eclipse, code assist will help you writing the ugly class MyBunch2, String>
Of course, in runtime, this.type will be java.util.List, not java.util.List
To get it right, go for TypeToken.
---Continuation---
You can even make another class
public static class MyBunch3<M> extends MyBunch2<List<M>, M>
{
public MyBunch3(Class<M> individualType) {
super(individualType);
}
}
And then create instances as
MyBunch3<String> c = new MyBunch3<String>(String.class);
There must be a way to do that in just one class...but I can't figure it out

How to return a Vector of inheriting classes?

I'm looking for a solution to instantiate and return a Vector (or sth comparable) of classes.
My attempt looks like this (Heritage extends SuperClass):
public Vector<? extends SuperClass> getAssignableClasses()
{
Vector<? extends SuperClass> out = new Vector<SuperClass>();
out.add(Heritage.class); //does NOT work, IDE shows error message
return out;
}
The list's declaration seems to be erroneous.
I suppose by this I can only add objects to a list, but how can I add classes using generics?
Thanks in advance!
I have not done this for a while, but isn't 'super' the keyword to use when you need to add stuff? :)
Here is a tutorial :)
You are trying to add an instance of Class - that is, Heritage.class. Your Vector only allows subclasses of SuperClass.
You need to add a new Heritage() object, however you construct one of those.
The problem is, you are trying to add a class to the Vector (Heritage.class) instead of an object with the appropriate class. Something as follows should work:
public Vector<? extends SuperClass> getAssignableClasses()
{
Vector<? extends SuperClass> out = new Vector<SuperClass>();
out.add(new Heritage()); //this line is changed
//add appropriate constructor parameters as necessary
return out;
}
Update I re-read your question. To return the concrete classes, you will need something as follows (I did not try this):
public Vector<? extends SuperClass.class> getAssignableClasses()
{
Vector<? extends SuperClass> out = new Vector<SuperClass>();
out.add(Heritage.class); //does NOT work, IDE shows error message
return out;
}
Or -as others have pointed out- you have to add an instance of Heritage: new Heritage()...
Or you have to declare correctly the Vector in order to store classes instead of instances:
Vector<Class<? extends SuperClass>>
Class<? extends SuperClass> means SuperClass.class or any descendant...
Important: Use List instead of Vector. It's the recomended list interface since Java 1.3 :)
Added: I've checked the code in your comment and it seems to compile ok:
import java.util.Vector;
public class SuperClass {
public static void main() throws Exception {
Vector<Class<? extends SuperClass>> vector = new Vector<Class<? extends SuperClass>>();
vector.add(SuperClass.class);
vector.add(Heritage.class);
}
public Vector<Class<? extends SuperClass>> getAssignableClasses() {
Vector<Class<? extends SuperClass>> out = new Vector<Class<? extends SuperClass>>();
out.add(Heritage.class);
return out;
}
}
class Heritage extends SuperClass {
}
Vector is an old, somewhat deprecated class. I'll use a generic list version instead:
public static List<Class<?>> getAssignableClasses(final Object o){
final List<Class<?>> list;
if(o == null){
list = Collections.emptyList();
} else{
list = new ArrayList<Class<?>>();
Class<?> tmp = o.getClass();
do{
list.add(tmp);
tmp = tmp.getSuperclass();
} while(tmp != null);
}
return list;
}
And as a bonus, here is a method that gathers all assignable interfaces based on the above method:
public static List<Class<?>> getAssignableInterfaces(final Object o){
final List<Class<?>> result;
final List<Class<?>> assignableClasses = getAssignableClasses(o);
if(assignableClasses.isEmpty()){
result = Collections.emptyList();
} else{
final Set<Class<?>> interfaces =
new LinkedHashSet<Class<?>>(assignableClasses.size() * 2);
for(final Class<?> clazz : assignableClasses){
interfaces.addAll(Arrays.asList(clazz.getInterfaces()));
}
result = new ArrayList<Class<?>>(interfaces);
}
return result;
}
Test:
public static void main(final String[] args){
final Map<String, String> map =
new ConcurrentHashMap<String, String>();
System.out.println(getAssignableClasses(map));
System.out.println(getAssignableInterfaces(map));
}
Output:
[class java.util.concurrent.ConcurrentHashMap, class java.util.AbstractMap, class java.lang.Object]
[interface java.util.concurrent.ConcurrentMap, interface java.io.Serializable, interface java.util.Map]
I think the problem is that you tell java to make a vector with Objects of a type derived from Superclass. And then you add a class not an object.
A dirty solution would be to make a vector of Class and test while adding if it's a subclass.

Categories

Resources