There is an interface with a method that returns a Class, like so.
public interface MyInterface {
public Class<? extends Object> returnsSomething ();
}
I have to create a class which implements the interface, like so.
public class MyClass implements MyInterface {
public Class<? extends Object> returnsSomething () {
return Object; // This is currently an error.
}
}
The return line in the implementation of returnsSomething in MyClass is incorrect. The IDE hints "cannot find symbol Object".
What correction do I need to apply in returnSomething's body to compile successfully?
Object is just the name of the class.
Object.class is the instance of the Class<Object> class that represents the Object class. See Class.
So you need:
return Object.class;
Your return type is incorrect in your method. You need to understand that this '.class' is used in Java for code Reflection. Generally you can gather meta data for your class such as the full qualified class name, list of constants, list of public fields,etc... So in your example you are basically saying that the Class type to be returned for the wildcard used will either be Object or Subclass of object to be returned at Runtime. Note that you want Java to determine the object returned at Runtime.
Related
Given
public class Foo {
public static class FooBuilder { ... }
}
I want to write a method on a third class that returns Foo, given Foo.FooBuilder.class
i.e.
Foo f = x.make(Foo.FooBuilder.class, someData);
Is it possible to declare a signature using generics that can imply the return type? Is there some language feature that lets me say "type U is outer class of type T"?
Obviously, it is possible to specify that type extends, or is the base of, a generic type (U extends T or U super T, respectively) but I am looking for U outer T which is, I think, more than Java can offer, even indirectly, at least in 1.7, which I am targeting.
So far, I have simply declared both inner and outer types, which works but is a wider definition than I am after and looks clumsy too.
public <TYPE,BUILDER> TYPE make(Class<BUILDER> builderClass, Map<String,Object> data) {
// Construct TYPE
}
Is there a way to infer TYPE without explicitly providing a template parameter?
There is a Class#getDeclaringClass method that may work in your case.
Quoting the docs:
If the class or interface represented by this Class object is a member of another class, returns the Class object representing the class in which it was declared.
EDIT:
After the clarification of OP, here is the new suggestion:
You create an generic interface to mark all your nested classes:
public interface Nested<P> {
}
Then you apply it to your Foo.Bar class like this:
public class Foo {
public static class Bar implements Nested<Foo> {
}
}
Then in your factory you can have the following:
public <P> P make(Class<? extends Nested<P>> clazz, Map<String, Object> someData) {
// do whatever you need to do
return (P) clazz.getDeclaringClass();
}
However, with this construct, there is not way to validate it your nested class is the real class, declared when implementing the generic interface.
I have a generic repository class that looks like this:
public class HibernateRepository<E extends Object, EId>
implements EntityRepository<E, EId> {
// Many things that are working fine
#Override
public E getById(EId id) {
return entityManager.getReference(E.class, id); // <<< Error here!
}
}
The method getById() is supposed to return a certain entity instance given its Id. Something very trivial in many other situations, but not in this one, since the compiler returns:
Illegal class literal for the type parameter E
Notice that I don't want to pass the desired class to the method, since I already did that in the class definition.
The usage for this class could be:
public class MyClassRepositoryHibernate
extends HibernateRepository<MyClass, Long> {
}
Now this new repository works on MyClass instances and the Id is typed with Long.
Is that possible in Java?
You will have to pass the actual class type to the constructor of your HibernateRepository and use that throughout your methods. The JVM has no knowledge of what "E" is at runtime hence you need to provide the concrete class type.
You can ensure you don't instantiate the object incorrectly by using the Generic parameter type in the constructor, like this:
public class HibernateRepository<E extends Object, EId>
implements EntityRepository<E, EId> {
private Class<E> clazz;
public HibernateRepository(Class<E> clazz) {
this.clazz = clazz;
}
#Override
public E getById(EId id) {
return entityManager.getReference(clazz, id); // <<< Error here!
}
}
A pain, but a necessity due to type erasure.
The type will be erased after compilation and thus is not available. This is called Type Erasure. You have to pass the Class object somewhere.
Is there anyway to get a generic type in a class constructor in order to pass it to a parent constructor?
Given base class:
public class BaseSupport<T>{
private Class<T> type;
public BaseSupport(Class<T> type){
this.type = type;
}
}
Is there anyway to create a subclass to do this?
public class Support<T> extends BaseSupport<T> {
public Support() {
// is there anyway to know what "T" is here?
super( T.class );
}
}
And then finally, I would simply be able to create a class like:
public class MyClass extends Support<OtherClass>{
// no need to explicitly define a constructor here since the Support class handles it
}
I know Guava has TypeToken to help with retrieve generic type information, but given that super() must be the first method called in a constructor, I can't use it to extract the type information to pass to the parent class.
I suspect that this isn't feasible, but thought I would ask to see if there are any features/tricks that I don't know about in Java 7 since 'T' would be available at compile time.
Did you see the option mentioned in the TypeToken docs?
Capture a generic type with a (usually anonymous) subclass and resolve it against a context class that knows what the type parameters are. For example:
abstract class IKnowMyType<T> {
TypeToken<T> type = new TypeToken<T>(getClass()) {};
}
new IKnowMyType<String>() {}.type => String
You could effectively do this.
public class MyClass extends Support<OtherClass>{
// no need to explicitly define a constructor here since the Support class handles it
public MyClass() {
super(OtherClass.class);
}
}
And in support, have a constructor that accept a Class type and call the super keyword as I have done above (eliminating T.class all together).
Update: Alternatively, you can use Reflection to get ParameterizedType on your BaseSupport class and not need to provide an argument to your BaseSupport public constructor.
Resource:
Reflecting Generics.
Related Answer on StackOverflow.
I'm using Guava TypeToken class in my project, but I'm getting an unexpected result.
I have MyGenericClass<T>:
public class MyGenericClass<T> implements MyInterface {
private TypeToken<T> recordType;
public MyGenericClass(String name) {
this.recordType = new TypeToken<T>(getClass()) {};
// ...
}
// ...
#SuppressWarnings("unchecked")
protected Class<T> getRecordType() {
return (Class<T>) recordType.getRawType();
}
}
So if I instantiate an object via new MyGenericClass<String>() and then invoke getRecordType() I expect to get java.lang.String, instead I'm getting java.lang.Object.
But, if I extend generic class:
public class MyStringImpl extends MyGenericClass<String> {
// ...
}
and instantiate this new class: new MyStringImpl() then I get the correct result.
Why is this happening? Is this the expected behaviour of TypeToken?
To add some boring details to Ian's answer: It would be nice if TypeToken worked the way you expected, but this is impossible. When you declare
public class MyGenericClass<T> implements MyInterface {...}
the JVM sees something like
public class MyGenericClass<Object> implements MyInterface {...}
due to erasure.
But when you declare
public class MyStringImpl extends MyGenericClass<String> {...}
then in the definition of MyStringImpl the generics used are recorded and can be obtained via Class#getGenericSuperclass(). That's (a part of) the magic behind TypeToken.
To make this work you need the same anonymous subclass trick when you instantiate MyGenericClass:
new MyGenericClass<String>() {}
If you do that then you will get String returned by getRecordType. The reason why this is necessary is explained in the JavaDocs for that TypeToken constructor.
Clients create an empty anonymous subclass. Doing so embeds the type parameter in the anonymous class's type hierarchy so we can reconstitute it at runtime despite erasure.
I have a class defined as follows:
public class MultiFacilitySearchDataProvider <T extends Facility & MilepostValue & Copyable<T>>
The class has this method:
protected T getFacility(final FacilityInstance instance) {
final MultiFacilitySearchDAO dao = new MultiFacilitySearchDAO(instance);
ENM.execute(dao);
return dao.getResultModel(); // Compile error here
}
The DAO method called above looks like this:
public MultiFacilitySearchModel getResultModel() {
return resultModel;
}
And MultiFacilitySearchModel is defined as follows:
public class MultiFacilitySearchModel implements Copyable<MultiFacilitySearchModel>, Facility,
Serializable, MilepostValue, MenuDisplayValues
The problem is that the line return dao.getResultModel() generates a compile error "Type mismatch: cannot convert from MultiFacilitySearchModel to T". I don't understand why I'm getting this error, since MultiFacilitySearchModel implements the three interfaces specified for the generic type T. What am I missing?
You can specify any class that meets the prequesites as type parameter. Therefore T need not be a supertype of MultiFacilitySearchModel. That means however, that
return dao.getResultModel()
may not return an object of a type that extends T. Java doesn't allow you to do this.
The method MultiFacilitySearchDAO.getResultModel() has no generic type and will allways return MultiFacilitySearchModel instead of T.
Although MultiFacilitySearchModel can be used as T in some class that extends MultiFacilitySearchDataProvider.
In your class MultiFacilitySearchDAO you have the method
public MultiFacilitySearchModel getResultModel()
which is obviously returning an instance of MultiFacilitySearchModel. There is nothing generic here. The return type is fix.
Your class MultiFacilitySearchDataProvider on the other hand declares the method
protected T getFacility(final FacilityInstance instance)
The type variable T is constrained to implement the three interfaces Facility & MilepostValue & Copyable. This is much less then being a MultiFacilitySearchModel.
I could easily create a class
public MyFacilitySearchModel implements Copyable<MyFacilitySearchModel>, Facility, MilepostValue
and then use a
MultiFacilitySearchDataProvider<MyFacilitySearchModel>
The result type of getResultModel() would still be MultiFacilitySearchModel which can't be casted to MyFacilitySearchModel.
Maybe you DAO class should also be generic. Or declare the method as
protected MultiFacilitySearchModel getFacility(final FacilityInstance instance)