Reputation: 612
Consider the following code:
public class Context {
private final Class<?> clazz;
private final String resource;
private final com.thirdparty.Context context;
public Context(final String resource, final Class<?> clazz) {
this.clazz = clazz;
this.resource = resource;
this.context = com.thirdparty.Context.newInstance(this.clazz);
}
public String marshall(final Object element) {
return this.context.marshall(element);
}
public Object unmarshall(final String element) {
return this.context.unmarshall(element);
}
}
Context context = new Context("request.xsd", Request.class);
// Marshall
Request request = new Request();
String xml = context.marshall(request);
// Unmarshall
Request roundTrip = Request.cast(context.unmarshall(xml));
I am trying to replace it with a generics version of the Context class:
public class Context<T> {
private final Class<T> clazz;
private final String resource;
private final com.thirdparty.Context context;
public Context(final String resource) {
this.clazz = initHere(); // <== HOW ??
this.resource = resource;
this.context = com.thirdparty.Context.newInstance(this.clazz);
}
public String marshall(final T element) {
return this.context.marshall(element);
}
public T unmarshall(final String element) {
return this.clazz.cast(this.context.unmarshall(element));
}
}
Context<Request> context = new Context<>("request.xsd");
// Marshall
Request request = new Request();
String xml = context.marshall(request);
// Unmarshall
Request roundTrip = context.unmarshall(xml);
Thus I do not pass a .class as a parameter to the constructor, and the unmarshall method automatically casts the return object.
I need to know the Class of T to pass to the newInstance() method, and to invoke the cast() method. i.e. T.class or T.getClass().
In my example I am attempting to initialise the clazz member, during the constructor, so that I can use it in both locations.
I have tried the following:
this.clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
However getClass().getGenericSuperclass() returns an object which cannot be cast into a ParameterizedType. I cannot use any third party reflection libraries, I need to stick to the standard mechanisms inside the Jdk.
Upvotes: 5
Views: 551
Reputation: 2809
Actually you are extremely close to the actual solution... your first version of the code is quite close to what you need:
From:
public Context(final String resource, final Class<?> clazz) {
//...
}
To:
public Context(final String resource, final Class<T> clazz) {
// ...
}
A single ?
to T
change would do the trick.
Upvotes: 1
Reputation: 827
You can't do that. In your case, the Generic Type T is linked to your instance. Reflection data are bound to Class, and your class doesn't define the type T.
The code you are trying to use works only if you define a class where T is set up.
public class RequestContext extends Context<Request> {}
If you use an instance of this class, then your code should work.
Upvotes: 4
Reputation: 2691
You can't do this in the constructor. If you don't pass a Class
instance to the constructor, there is no way for the Context
class what kind of object it is dealing with.
Have a look here: http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html#Reflection
To determine the type and the generic type, you need an object. And you don't have an object.
Is there a specific reason why you can't add a Class
parameter to the constructor? If there is, you example doesn't make it clear.
Upvotes: 3