Passing parameterized Class instance to the constructor - java

I have lost in the Jungle of Generics, please help me :) I have something like this:
public class BaseClass<TYPE> {
public BaseClass(Class<TYPE> clazz) {};
}
public class FirstLevelClass<REFRESHABLE
extends RefreshableInterface> extends BaseClass<REFRESHABLE> {
public FirstLevelClass(Class<REFRESHABLE> clazz) {
super(clazz);
};
}
public class Argument<T extends AnyOtherClass>
implements RefreshableInterface {
public refresh() {}
}
pulbic class ProblematicClass
extends FirstLevelClass<Argument<AnyOtherClassDescendant>> {
public ProblematicClass() {
//Compiler error: Constructor
//FirstLevelClass<Argument<AnyOtherClassDescendant>>(Class<Argument>) is undefined
super(Argument.class);
}
}
As far as I think, the compiler should accept Argument since it implements RefreshableInterface.
Why do I get this error?
How can I make the ProblematicClass working?
ps: if you have better title for this, please change it. I could not make up better.

Issue is, your constructor expects a Class<T>, and T in your code is inferred as Argument<AnyOtherClassDescendant>.
So, you should pass a Class<Argument<AnyOtherClassDescendant>>, and you're passing Class<Argument>. But you can't pass that Class instance directly, as you cannot do Argument<AnyOtherClassDescendant>.class.
You can however, solve the issue by typecasting the class to required instance:
public ProblematicClass() {
super((Class<Argument<AnyOtherClassDescendant>>)(Class<?>)Argument.class);
}
Note, how you've to typecast Class<Argument> first to Class<?>, and then the resultant type to Class<Argument<AnyOtherClassDescendant>>. There is no simple way to achieve that.
The reason behind this is, there is only a single Class instance for all parameterized instantiation of a generic type, that is associated with the class itself. A single compilation unit of a generic type, compiles to just a single class file. I guess this is different in how C++ implements templates. There you get different machine codes for different instantiation.
So, if you execute the below code, you'll get true as output:
List<String> strList = new ArrayList<String>();
List<Integer> intList = new ArrayList<Integer>();
boolean isSameClassInstance = strList.getClass() == intList.getClass();
System.out.println(isSameClassInstance);

Related

Java generics & incompatible types using <S extends {class}>

abstract class AbsClass {}
class MyAbs extends AbsClass {}
class MyClass<S extends AbsClass> {
S getObj() {
return new MyAbs();
}
}
Getting compiler issue:
Error:(33, 16) java: incompatible types: MyAbs cannot be converted to S
What is the correct way to do this?
Edit:
I was hoping to be able to intialize MyClass{MyAbs} then call getObj() which would return me a MyAbs object. With Andy's answer, I would have to cast the AbsClass to MyAbs or MySecondAbs which was what I was trying to avoid
Andy has described how to fix the problem, I'll try to explain why.
S is not guaranteed to be assignable to MyAbs, only to AbsClass, and each instance will specify a subclass of AbsClass.
Consider:
class MyOtherAbs extends AbsClass {}
MyClass myClass = new MyClass<MyOtherAbsClass>{};
This would conflict with what you have.
UPDATE:
Based on your comments it looks like you want to achieve the above. The challenge is what if MyOtherAbs has a constructor with arguments? Or is implemented as a Singleton (i.e. a private constructor and static getInstance()). In short, there is no guaranteed unified way you can construct these. Further, due to type erasure, at runtime, the concept of S is gone, so you cannot do something like:
return new S();
You basically have two alternatives, one is to use subclassing:
public interface AbsClassFactory<S extends AbsClass>{ //takes the place of MyClass
public S getInstance();
}
MyAbsFactory implements AbsClassFactory<MyAbs>{
public MyAbs getInstance(){
return new MyAbs(); //or however MyAbs is instantiated
}
}
The other option is reflection:
class MyClass {
public <S extends AbsClass> S getObj(Class<S> clazz) throws InstantiationException, IllegalAccessException {
return clazz.newInstance();
}
}
Note that the second assumes there is a no arg constructor available and will throw a runtime exception if one is not.
S extends MyAbs, not the other way around. any object of type S can be cast into MyAbs, but MyAbs cannot be cast into it's derived classes.
Please explain what you are trying to achieve.
From your comment it seems that you can accomplish the same using the Supplier interface:
Supplier<MyAbs> supp = MyAbs::new; // Constructor reference
MyAbs obj = supp.get();
Supplier<MySecondAbs> supp2 = MySecondAbs::new;
MySecondAbs obj2 = supp2.get();

Java nested genericsType

I got an interesting issue. Consider the following code:
public class GenericsTest
{
// An interface with a generic type.
public interface IObject<K>{}
// An class with a generic type
public static class ObjectA<K>
{
// An inner class without generic type, but implementing the interface with generic Type
// When adding a genericType to this class, it will popup the warning: 'hiding'
public class ObjectB implements IObject<K>
{
}
// A getter with the interface as return Type
public IObject<K> getObjectB()
{
return new ObjectB();
}
}
public ObjectA<String> objectA = new ObjectA<String>();
// This field is yelling for an genericType, though it can't get one because the class doesn't support a generic argument.
public ObjectB genericObject = (ObjectB)objectA.getObjectB();
}
So the issue is that my IDE is complaining about a missing genericType of the genericObject field, and that I should add a SupressWarning annotation to the method. (luckily not code breaking, though still pretty annoying).
I could add a generic type to the inner class, though than it would 'hide' a generic argument, meaning I would need to add a SupressWarning annotation there.
A second fix would be to use a second generic type like <S extends K>. In which case I don't need a SupressWarning annotation at the class. Though when I try to use the getter, my IDE is complaining:
The member type GenericsTest.ObjectA.ObjectB<String> must be qualified with a parameterized type, since it is not static.
So basically I can't use the getter, unless I add an argument of the genericType to the method.
My question is, what is the cleanest way to solve this problem without changing the inner class to a nested class?
Here's a short example that compiles with no issues:
public class Test
{
interface K<T> { }
static class A<T>
{
class B implements K<T> { }
public K<T> getK() { return new B(); }
}
A<String> a = new A<String>();
A<String>.B b = (A<String>.B) a.getK();
}
Notice the last line:
A<String>.B b = (A<String>.B) a.getK();
To be honest, I'm not sure how the example you've given even compiles as far as it does - the class 'ObjectB' is not visible from the main 'GenericsTest' scope, it needs to be prefixed with its' parent class.

Java generics puzzler with generic static factory

I recently started writing a generic object mapper for a project and ran into something I don't quite understand. Given the following:
public class G<X> {
public G(Class<X> c) { }
public void m(X x) { }
public static <T> G<T> create(Class<T> c) {
return new G<T>(c);
}
public static void main(String[] args) {
Object o = ""; // irrelevant!
G<?> t = create(o.getClass());
t.m(o);
}
}
I get the following compilation error:
m(capture#402 of ?) in G<capture#402 of ?> cannot be applied to (java.lang.Object)
I can't seem to figure out a way to properly cast t to make this compile. What am I missing? Using JDK 1.6.
EDIT:
This is not an academic question. I'm trying to write a mapper from hibernate objects to their corresponding DTO to be passed around in the REST layer. The assumption is that for each ORM object Foo, there might exist a class FooDTO that has a constructor that takes an instance of Foo as a parameter. The generic class that maps Foo to FooDTO will encapsulate this assumption and throw appropriate exceptions if FooDTO doesn't exist or doesn't have the proper constructor:
class Mapper<Foo,FooDTO> {
private final Constructor<FooDTO> dtoConstructor;
Mapper(Class<Foo> fooClass, Class<FooDTO> fooDTOClass){
// find the constructor of FooDTO or throw ...
}
public FooDTO map(Foo f){
return dtoConstructor.newInstance(f);
}
// this factory is for convenience when we don't know the type of FooDTO:
public static Mapper<X,Object> create(Class<X> fromClass){
Class<Object> dtoClass = // ... find it
return new Mapper<X,Object>(fromClass,dtoClass);
}
}
This seems to break if I pass a generic object class to create.
Note that my actual implementation has all FooDTO classes extends from a generic super class, i.e., the signature of Mapper is actually something like Mapper<Foo,DTO<Foo>>. I don't think that's relevant here.
EDIT 2:
Actually the suggestion of changing the line G<?> t = create(o.getClass()); to G<Object> t = (G<Object>) create(o.getClass()); worked in this context.
Unfortunately I didn't realize that the fact that my class is more complex actually has an impact. Here's a more complete example (I apologize for the piecemeal question):
public class Y<T> {
}
public class G<X, Z extends Y<X>> {
public G(Class<X> c, Class<Z> s) {
}
public void m(X x) {
}
public static <T, S extends Y<T>> G<T, S> create(Class<T> c) {
Class<S> s = null; // find this via some reflection magic
return new G<T, S>(c, s);
}
public static void main(String[] args) {
Object o = ""; // irrelevant!
G<? extends Object, Y<? extends Object>> t = create(o.getClass());
t.m(o);
}
}
In this case the object Class<S> is created using reflection and some conventional location for objects of that type. That part works fine and should be irrelevant to this discussion. The error I am getting now is the following:
inconvertible types
found : G<capture#155 of ? extends java.lang.Object,Y<capture#155 of ? extends java.lang.Object>>
required: G<java.lang.Object,Y<java.lang.Object>>
And if I change the incriminated line to:
G<Object, Y<Object>> t = (G<Object, Y<Object>>) create(o.getClass());
I get a similar error:
java: inconvertible types
required: G<java.lang.Object,Y<java.lang.Object>>
found: G<capture#1 of ? extends java.lang.Object,Y<capture#1 of ? extends java.lang.Object>>
Once again, I apologize for the piecemeal information. I am sorting through this while I am writing.
You have passed the Class object from the getClass() method, which returns a Class<?>, meaning that you had to declare t to be a G<?>.
You cannot call a method with a generic type parameter when the generic type parameter of the variable is a wildcard. The compiler doesn't know which specific class the wildcard really is, so it cannot guarantee type safety when such a method is called. It's the same reason that add can't be called on a List<?>.
To get this to compile, you must use a class literal, to avoid having a Class<?>, and declare t not to have a wildcard.
G<Object> t = create(Object.class);
Then
t.mo(o);
will compile.
What you have here is a consumer. However, the following seems to compile (in Eclipse).
public static class G<X, Z extends Y<X>> {
public G(Class<? extends X> c, Class<Z> s) {}
public void m(X x) {}
public static <T, S extends Y<T>> G<T, S> create(Class<? extends T> c) {
Class<S> s = null; // find this via some reflection magic
return new G<T, S>(c, s);
}
public static void main(String[] args) {
Object o = ""; // irrelevant!
create(o.getClass()).m(o);
}
}
You're creating a G<Object> and then assigning it to a variable of type G<?>. The method invoked takes a variable of the generic type, which won't take anything for <?>. If you change the variable to G<Object> it will work.
Since you are specifying G<?>, javac is expecting to figure out what the generics are (what classes do they represent). Changing the statement to G t = create(o.getClass()); fixes the errors.
capture errors generally mean that the compiler is unable to figure out the classes...
Its not really clear what you are trying to do... Perhaps that information would be useful in helping you more...

Generic(s) confusion: Type of this in generic superclass is not defined at compile time?

Just met this piece of code:
public class Container <T extends Containter<T>> {
protected Map<String, Rule> inspect (T t) {
// ....
}
public boolean isValid () {
// ...
inspect ((T)this);
// ...
}
}
What I'm confused about is the "isValid"-method.
When you replace the line with inspect(this); it won't compile: incompatible types: Container <T> cannot be converted to T.
In subclasses the error does not occur. So I'm asking myself: Could there be a situation where this is of Type other than Container? I mean what would be the type of this in the code above? The explicit cast seems to be unnecessary.
Hope you guys can understand me, I find it hard to explain stuff like that in english.
Thanks!
UPDATE
First, thank you and sorry for letting you wait.
There was confusion about the intention of the inspect method. It is supposed to work on the Container itself (not on the generic Type). Basically only subclasses of Container should be able to use it. So the whole thing is about inheritance.
It's about type safety for sub classes using the inspect method.
Imagine an instantiation like (inside the Container's inspect-method):
List<T> listOfSimilarContainers = new LinkedList<T>();
Now, if there was a subclass like
public class SubContainer extends Container<SubContainer> { }
calling inspect on that class should force the listOfSimilarContainers inside the inspect method to only contain SubContainers.
That is what I wanted to achieve.
Here is a simplified version:
interface Foo<T extends Foo<T>> { }
class Bar implements Foo<Bar> { }
class Baz implements Foo<Bar> { }
Note that Baz inherits from Foo<Bar> and not from Foo<Baz>. The code compiles without any errors.
In other words, the declaration of the interface does not guarantee, that T is the subclass of Foo<T>.
How should work inspect method? If you want to inspect the generic type, then T could be a Class<T> object, else inspect's signature sholud be:
public class Container<T extends Container<T>> {
protected Map<String, String> inspect(Container<T> t) {
}
public boolean isValid() {
// ...
inspect(this);
// ...
}
}

Getting parametrized type of concrete implementation of an interface with bounded type paramter. Java [duplicate]

Say I have a class like the following
public class AtomEntryHandler implements ConsumingHandler<AtomEntry>
{
...
}
Is it possible to get the class object AtomEntry.class from the class object of AtomEntryHandler.class ?
I didn't think it was possible due to erasure, but a friend said it is.
You can get the generic type for both interfaces and direct subclasses, but only for the concrete implementation. For example, if you have a List<T> instance, you have no way of knowing what it's been parameterized to because of type erasure. If the class definition includes parameterized types that are known at compile time (for example, class StringList extends List<String>) then you can retrieve that information.
ParameterizedType pt = (ParameterizedType)AtomEntryHandler.class.getGenericInterfaces()[0];
Class atomEntryClass = (Class)pt.getActualTypeArguments()[0];
I could not figure a way to determine base type parameter in case of interface implementation (which does not mean there is none). But this is as close as it gets to it.
import java.lang.reflect.*;
public class Foo {
static class Bar<T> {
}
static class SubBar extends Bar<Integer> {
}
public static void main(String argv[]) {
ParameterizedType pt = (ParameterizedType)SubBar.class.getGenericSuperclass();
Type[] t = pt.getActualTypeArguments();
for (int i=0;i<t.length;i++) {
System.out.println(t[i]);
}
}
}
Result:
class java.lang.Integer
If you happen to know ConsumingHandler is the only interface AtomEntryHandler implements, and you happen to know it takes just one type argument, you can do this:
interface ConsumingHandler<T> {}
class AtomEntry {}
class AtomEntryHandler implements ConsumingHandler<AtomEntry>
{
public static void main( String[] args )
{
Type[] interfaces = AtomEntryHandler.class.getGenericInterfaces();
ParameterizedType firstInterface = (ParameterizedType) interfaces[0];
Class c = (Class) firstInterface.getActualTypeArguments()[0];
System.out.println(c.getName()); // prints "AtomEntry"
}
}
Otherwise, you can poke around in getGenericInterfaces() and their actualTypeArguments until you find something that looks like what you're looking for.
But if you find yourself needing to do this in real code, either something's probably gone badly wrong in your design, or you're writing some mad genius mock object library and you shouldn't need us to answer these questions.
There is a blog post that goes over it in detail here: Reflecting Generics.

Categories