Generics: Creating parameterized class argument - java

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

Related

Java not allowed to call recursive method with generic type?

public class ResourceAssembler<T extends BasedEntity> {
public Resource<T> toResource(T entity) {
ExtendsBasedEntity e = getExtendsBasedEntity();
toResource(e); //<----compile error
//some other code
}
}
public class ExtendsBasedEntity extends BasedEntity{}
But if you call it from the outside its fine
//some other class
new ResourceAssembler<ExtendsBasedEntity>().toResource(new ExtendsBasedEntity())
Why?
Error:(28, 25) java: incompatible types: spring.BasedEntity cannot be converted to T
T may not be ExtendsBasedEntity, but some other subtype of BaseEntity, hence the compile error.
One way to "fix" the problem, is to use a type token
public class ResourceAssembler<T extends BasedEntity> {
private final Class<T> type;
public ResourceAssembler(Class<T> type) {
this.type = type;
}
public Resource<T> toResource(T entity) {
toResource(type.newInstance());
//some other code
}
}
Assuming that works for you.
Let's create two classes extending BasedEntity and call them EBE1 and EBE2.
Now you create a ResourceAssembly object using EBE1 as the type parameter. But let's say that in the implementation of the toResource method you do something like return toResource(new EBE2());.
So the return type of toResource() is becoming Resource<EBE2> but that is wrong because according to the structure you should return Resource<EBE1>. And that's why the compile time error. And type safety instincts of Java kicks in.
If you want to do return a generic for the toResource method then you either have to pass in the entity object down as it is or change it to the concrete type that you are initializing it within and not use generic (although I don't know why would anyone use the second option, but it's a "solution" to make it "compile").
Also, on the outside when you declare it. You are not specifying the type parameter for ResourceAssembly and hence it's a raw one. Try to do it with a type param. You will have red squiggly lines there as well.
Here is an example:
static class Resource<T> {
}
static class BasedEntity {
}
static class ExtendsBasedEntity1 extends BasedEntity {
}
static class ExtendsBasedEntity2 extends BasedEntity {
}
static public class ResourceAssembler<T extends BasedEntity> {
public Resource<T> toResource(T entity) {
return toResource(new ExtendsBasedEntity1()); //<----compile error
}
}
public static void main(String[] args) {
new ResourceAssembler<ExtendsBasedEntity1>().toResource(new ExtendsBasedEntity1()); // <---- No errors or warnings. This is valid and legal
new ResourceAssembler<ExtendsBasedEntity2>().toResource(new ExtendsBasedEntity1()); // <----- red squiggly lines here
new ResourceAssembler().toResource(new ExtendsBasedEntity2()); // <--compiler warning about raw types but no error
}
If you anyhow need to make it work the way you want it to, then instead of returning Resource<T>, return Resource<ExtendsBasedEntity> because you are recursing inside a generic method and looks like you need an object of concrete type to go in as the parameter for the recursive call. So it would make sense to do so.
Or else, go with #Bohemian's approach and make sure that in the class declaration of the type that you are using, there is a no-args constructor or else you will be having InstantiationException.

Can I force a constructor to put a stricter bound on its generic type?

In java, generic classes have constructors to construct instances of some generic type. This is simple, and callers of the constructor can specify any type that is within bounds.
Is it possible to have a constructor that puts stricter bounds on that generic type?
E.g., have a constructor that forces the generic type to be String.
public class GenericClass<T extends Serializable> {
public GenericClass() {
// normal constructor
}
public GenericClass(String argument) {
// Can I force this constructor to construct a `GenericClass<String>`?
}
}
// The first constructor can have any type
GenericClass<String> stringInstance = new GenericClass<>();
GenericClass<Integer> intInstance = new GenericClass<>();
// The second constructor is limited to `GenericClass<String>`
stringInstance = new GenericClass<>("with generic type String is okay");
intInstance = new GenericClass<>("with other generic type is not okay");
I would like to have the last line fail because of incompatible types.
Is this possible?
public GenericClass(String argument)
The problem with this is how is the compiler supposed to know that String is T? There is no link between the parameter and the generic type parameter and no way to specify one. You could use
public GenericClass(T argument)
and construct it with
new GenericClass<>("foo");
but that would allow GenericClass to be instantiated with an object of any type.
You can achieve roughly what you want using inheritance, though you need to introduce a second class:
class GenericClass<T extends Serializable> {
public GenericClass() {
}
}
class StringClass extends GenericClass<String> {
public StringClass(String argument) {
}
}
You can introduce an interface and have both classes implement that if you want to avoid using inheritance. That's what I'd do.
One way to cause the last line to fail is this:
public class GenericClass<T extends Serializable> {
public GenericClass() {
// normal constructor
}
public GenericClass(T argument) {
}
}
But obviously that doesn't stop people from calling new GenericClass<>(1).
Alternatively, you can write a factory method ofString:
public static GenericClass<String> ofString(String s) {
GenericClass<String> gc = new GenericClass<>();
// do stuff to gc
return gc;
}

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

Avoiding Java Type Erasure

Is there a way one could avoid type erasure and get access to a type parameter?
public class Foo<T extends Enum<?> & Bar> {
public Foo() {
// access the template class here?
// i.e. :
baz(T.class); // obviously doesn't work
}
private void baz(Class<T> qux) {
// do stuff like
T[] constants = qux.getEnumConstants();
...
}
}
I need to know about T, and do things with it. Is it possible, and if so, how can it be done without passing in the class in the constructor or anywhere besides the parameter?
EDIT: The main purpose of this question is to find out if there is any practical way around type erasure.
AFACT, there is no practical way around type erasure because you can't ask for something which the runtime doesn't have access to. Assuming of course you agree that sub-classing generic classes for each enum which implements Bar interface is a practical work around.
enum Test implements Bar {
ONE, TWO
}
class Foo<T> extends FooAbstract<Test> {
public Foo() {
ParameterizedType genericSuperclass =
(ParameterizedType) getClass().getGenericSuperclass();
baz((Class<T>) genericSuperclass.getActualTypeArguments()[0]);
}
private void baz(Class<T> qux) {
T[] constants = qux.getEnumConstants();
System.out.println(Arrays.toString(constants)); // print [ONE, TWO]
}
}
interface Bar {
}
class FooAbstract<T extends Enum<?> & Bar> {
}
If you're willing/able to hand a class token to the constructor:
public Foo(Class<T> clazz) {
baz(clazz);
}
private void baz(Class<T> qux) {
// ...
}
That way, you can produce objects of type T with Class.newInstance(), attempt to cast arbitrary objects to T using Class.cast(), etc.
What do you intend to do in baz()?
As pholser points out in his answer, the only way to achieve this is by passing in the Class object representing the type T. It's because of Type Erasure that something like T.class isn't possible because T is erased before runtime.
You seem resistant against passing in the Class object, but it's the only way to use the method getEnumConstants(). Here is a self contained example:
public class Foo<T extends Enum<?> & Bar> {
final Class<T> clazz;
public Foo(Class<T> clazz) {
this.clazz = clazz;
}
public void baz() {
T[] constants = clazz.getEnumConstants();
System.out.println(Arrays.toString(constants));
}
public static void main(String[] args) {
new Foo<MyEnum>(MyEnum.class).baz(); //prints "[A, B, C, D]"
}
}
public interface Bar { }
public enum MyEnum implements Bar { A, B, C, D; }
Use a super type token as proposed by Neil Gafter and used by libraries like guice for this purpose.
See http://gafter.blogspot.com/2006/12/super-type-tokens.html for the original description and I've check out the guice source for CA radio life working implementation.
there is another q which has an answer with worked example inline here How can I pass a Class as parameter and return a generic collection in Java?
In some cases you can use a workaround suggested by Richard Gomes.
When creating instances of anonymous classes, the type parameter class info is available.
class A<T>
{
A()
{
java.lang.reflect.ParameterizedType parameterizedType = (java.lang.reflect.ParameterizedType) (this.getClass().getGenericSuperclass());
System.out.println(parameterizedType.getActualTypeArguments()[0]);
}
}
public class Example {
public static void main(String[] args) {
A<String> anonymous = new A<String>() {}; // prints java.lang.String
}
}
Note that multiple instances created this way will be of different anonymous classes, and if that's a problem you might want a class A_String_Factory with a createNew() function based on clone to replace the calls to new.

Java: generics method and type identification

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.

Categories

Resources