Proxying with Generics - java

I use java.lang.reflect.Proxy to proxy objects.
I have this class:
public class TransportableImpl extends Transportable{
public class OrderInvoker extends InvocationHandler{
...
}
}
Here i build the Proxy:
Transportable t = new TransportableImpl();
Order myOrder = new OrderImpl();
Class proxyClass = Proxy.getProxyClass(getClass().getClassLoader(), Transportable.class, Order.class);
Object serializable = proxyClass.getConstructor(new Class[]{InvocationHandler.class}).newInstance(t.new OrderInvoker(myOrder));
Problem is: Class is raw type and
Class<? extends Order & Transportable> proxyClass =
(Class<? extends Order & Transportable>)
Proxy.getProxyClass(getClass().getClassLoader(),
Transportable.class, Order.class);
is hard to read.
Any ideas?

The Proxy#getProxyClass(ClassLoader, Class) method is declared as
public static Class<?> getProxyClass(ClassLoader loader,
Class<?>... interfaces)
Its return type is therefore Class<?>. The normal syntax would be
Class proxyClass<?> = Proxy.getProxyClass(getClass().getClassLoader(), Transportable.class, Order.class);
Technically you could do (with a warning)
public <T extends Order & Transportable> void doSomething() {
Class<T> proxyClass = (Class<T>) Proxy.getProxyClass(Driver.class.getClassLoader(),
Transportable.class, Order.class);
}
but that gains you nothing as you will pretty much never need to use that T variable. The Class class provides very little methods that makes use of it, namely getConstructor(Class...) and newInstance(). But again, the whole point of reflection is that you only know the class types at run time, not at compile time where generics are useful.

Related

Can't figure out how to instantiate generic class returned from function with condition like <S, T extends S>

Can't figure out how to get this work:
//Have a tiny CustomServiceLoader implementation
public class MyServiceLoader {
static private Map<Class<?>, Class<?>> CONTENTS = new HashMap<>();
static public <S, T extends S> void registerClassForInterface(Class<T> c, Class<S> i) {
if (c == null) {
CONTENTS.remove(i);
} else {
CONTENTS.put(c, i);
}
}
static public <S, T extends S> Class<T> getClassForInterface(Class<S> i) {
return (Class<T>)CONTENTS.get(i);
}
}
Usage:
// classes registration works perfect event check for interface conformance (e.g. T extends S really works here!):
MyServiceLoader.registerClassForInterface(Model.class, APIAsyncLoaderTask.class);
// but I can't figure out how to instantiate a class returned from my service loader:
Class c = GiftdServiceLoader.getClassForInterface(APIAsyncLoaderTask.class);
mLoaderTask = c.newInstance(); // 'new c();' also couldn't work
And compiler error:
also I have a strange tip for that method which is
public final Class<T> extends Object implements Serializable, AnnotatedElement, GenericDeclaration, Type
But I cannot see my interface there. I'm getting same when using both: abstract class + class and interface + class
How do I make it work properly? I'm wondering is it at least possible?
You're using the raw type Class.
Class c = GiftdServiceLoader.getClassForInterface(APIAsyncLoaderTask.class);
All generatic types and generic type parameters in any method invoked on such a reference are erased.
Parameterize it correctly
Class<APIAsyncLoaderTask> c = MyServiceLoader.getClassForInterface(APIAsyncLoaderTask.class);
Note that you should use only the interface type if you aren't sure of what you'll be receiving from the call to getClassForInterface.
For example, I can do
MyServiceLoader.registerClassForInterface(NotModel.class, APIAsyncLoaderTask.class);
// but I can't figure out how to instantiate a class returned from my service loader:
Class<Model> c = MyServiceLoader.getClassForInterface(APIAsyncLoaderTask.class);
Model mLoaderTask = c.newInstance(); // 'new c();' also couldn't work
and it will fail with a ClassCastException.
Generics are not powerful enough to prevent this.
I believe you meant to have
CONTENTS.put(i, c);
in your registerClassForInterface method.
You have the raw form of the Class class in the preceding line:
Class c = GiftdServiceLoader.getClassForInterface(APIAsyncLoaderTask.class);
Therefore, the newInstance() method returns an Object, which can't be assigned to an APIAsyncLoaderTask.
But coming out of a Map<Class<?>, Class<?>>, the best you can do with generics is Class<?> c = ..., and newInstance still returns an Object. You don't have the information at compile time to determine if the Class c represents an APIAsyncLoaderTask.
However, you can enforce an upper bound on the value of the HashMap.
static private Map<Class<?>, Class<? extends APIAsyncLoaderTask>> CONTENTS = new HashMap<>();
Your registerClassForInterface method will need that upper bound also.
static public <S extends APIAsyncLoaderTask, T extends S> void registerClassForInterface(
Class<T> c, Class<S> i) {
Then you can get a Class<? extends APIAsyncLoaderTask> out of the HashMap, and newInstance() will return the erasure of the upper bound -- an APIAsyncLoaderTask.

Passing generic subtype class information to superclass in Java

I've long used an idiom in Java for using the class information of a (non-abstract) class in the methods of its (generally abstract) ancestor class(es) (unfortunately I can't find the name of this pattern):
public abstract class Abstract<T extends Abstract<T>> {
private final Class<T> subClass;
protected Abstract(Class<T> subClass) {
this.subClass = subClass;
}
protected T getSomethingElseWithSameType() {
....
}
}
An example of a subclass thereof:
public class NonGeneric extends Abstract<NonGeneric> {
public NonGeneric() {
super(NonGeneric.class);
}
}
However, I'm having trouble defining a subclass of Abstract which has its own generic parameters:
public class Generic<T> extends Abstract<Generic<T>> {
public Generic() {
super(Generic.class);
}
}
This example is not compilable; likewise, it is not possible to specify the generic types using e.g. Generic<T>.class or even to use a wildcard like Generic<?>.
I also tried replacing the declaration of generic type T in the superclass to ? extends T, but that isn't compilable either.
Is there any way I can get this pattern to work with generic base classes?
The "pattern" (idiom) of passing an instance of Class<T> (typically to the constructor) is using Class Literals as Runtime-Type Tokens, and is used to keep a runtime reference to the generic type, which is otherwise erased.
The solution is firstly to change the token class bound to:
Class<? extends T>
and then to put a similar requirement on your generic subclass as you did with your super class; have the concrete class pass a type token, but you can type it properly as a parameter:
These classes compile without casts or warnings:
public abstract class Abstract<T extends Abstract<T>> {
private final Class<? extends T> subClass;
protected Abstract(Class<? extends T> subClass) {
this.subClass = subClass;
}
}
public class NonGeneric extends Abstract<NonGeneric> {
public NonGeneric() {
super(NonGeneric.class);
}
}
public class Generic<T> extends Abstract<Generic<T>> {
public Generic(Class<? extends Generic<T>> clazz) {
super(clazz);
}
}
And finally at the concrete class, if you declare the usage as its own class, it doesn't require a cast anywhere:
public class IntegerGeneric extends Generic<Integer> {
public IntegerGeneric() {
super(IntegerGeneric.class);
}
}
I haven't figured out how to create an instance of Generic (anonymous or not) without a cast:
// can someone fill in the parameters without a cast?
new Generic<Integer>(???); // typed direct instance
new Generic<Integer>(???) { }; // anonymous
I don't think it's possible, but I welcome being shown otherwise.
The major problem you have got here is, there is no class literal for concrete parameterized type. And that makes sense, since parameterized types don't have any runtime type information. So, you can only have class literal with raw types, in this case Generic.class.
Reference:
Java Generics FAQs
Why is there no class literal for concrete parameterized types? :
Well, that's fine, but Generic.class gives you a Class<Generic> which is not compatible with Class<Generic<T>>. A workaround is to find a way to convert it to Class<Generic<T>>, but that too you can't do directly. You would have to add an intermediate cast to Class<?>, which represents the family of all the instantiation of Class. And then downcast to Class<Generic<T>>, which will remove the compiler error, though you will an unchecked cast warning. You can annotate the constructor with #SuppressWarnings("unchecked") to remove the warning.
class Generic<T> extends Abstract<Generic<T>> {
public Generic() {
super((Class<Generic<T>>)(Class<?>)Generic.class);
}
}
There is no need in Class<T> subClass argument. Change:
protected Abstract(Class<T> subClass) {
this.subClass = subClass;
}
to:
protected Abstract(Class subClass) {
this.subClass = subClass;
}
and everything will compile.

An interface has two type parameters. Can I implement the interface with the two types being the same, such that they are then compatible?

This is an existing interface:
public interface MyInterface<T, U> {
public T foo(U u);
}
I want to implement this interface under the assumption that T and U are the same type. I thought maybe I could leave the type parameters in as they are, and then as long as I only ever instantiate this particular implementation with two of the same type, that it might work:
public class MyOuterClass<A> {
public class MyClass<T, U> implements MyInterface<T, U> {
#Override
public T foo(U u) {
return u; //error here
}
//even though in the only instantiation of MyClass, T and U are the same
private MyClass<A, A> myInstance = new MyClass<A, A>();
}
But, perhaps unsurprisingly, this doesn't work, as types T and U are incompatible.
So then I thought maybe I could change MyClass to specify that its types would always be the same, by changing it to something like MyClass<A, A> implements MyInterface<A, A> or similar, but I get errors saying that T is already defined.
Is there a way to implement MyClass so that its two types will be the same?
(I'm more of a C++ guy than Java, so sorry if I'm missing something fundamental about Java's generic's here.)
Your myclass needs to look like this:
public class MyClass<T> implements MyInterface<T, T> {
#Override
public T foo(T in) {
return in;
}
}
Let's review what your suggested class definition does:
public class MyClass<T, U> implements MyInterface<T, U>
In this code, T and U do two things each:
in the first occurance they define a type variable of your MyClass class
in the second occurance they specify the concrete type of the MyInterface class
Since inside the body of your class T and U are unbounded type variables (i.e. nothing is known about the actual types), they are assumed to be incompatible.
By having only a single type variable in your MyClass you make your assumption explicit: there's only a single type, and I'm using it for both types of the interface.
Last but not least: remember that the compilation of a type is complete once the source is fully handled. In other words: contrary to what C++ does, "instantiation" of a generic type ("template type" or similar in C++; Sorry for my rusty terminology) does not handle. MyClass<Foo> and MyClass<Bar> are the same type, as far as the JVM is concerned (only the compiler actually distinguishes them).
Define a single type parameter for MyClass:
class MyOuterClass<A> {
public class MyClass<T> implements MyInterface<T, T> {
public T foo(T u) {
return u;
}
}
// Need only one 'A' here.
private MyClass<A> myInstance = new MyClass<A>();
}
When you say
public class MyClass<T> implements MyInterface<T, T> {
... you are defining one generic variable for MyClass and you are saying that it fulfills both the roles T and U in MyInterface.

Difference between Java Generic Parameters

What is the difference between passing in generic parameter some generic class with and without his generic parameter?
Example:
Simple Generic class:
public class Foo<T> { /*...*/ }
Simple class that extend simple generic class setting the generic parameter to some irrelevant type:
public class FooFoo extends Foo<Type1> { /*...*/ }
Another generic class
public class Bar<T> extends FooFoo { /*...*/ }
Our base class that as generic parameter need something that extends class Foo
public class TestFooClass<T extends Foo<?>> { /*...*/ }
And the question what is the deference between this two parameters
public class BarTestOne extends TestFooClass<Bar> { /*...*/ }
public class BarTestTwo extends TestFooClass<Bar<?>> { /*...*/ }
Problem
Class<T> class = (Class<T>) ((Foo)getClass().getGenericSuperclass()).getActualTypeArguments()[0];
In the first case code works in the second doesn't.
It looks like you are trying to determine the actual type that the TestFooClass is parameterized with?
In that context, the difference between using generic class with and without its generic parameter is that getActualTypeArguments()[0] will:
In the first case provide an instance of Class representing the raw type
In the second case provide an instance of ParameterizedType (thus one may get ClassCastException). If you call getRawType() on that ParameterizedType, you will get Class representing the raw type.
This:
BarTestOne one = new BarTestOne();
BarTestTwo two = new BarTestTwo();
Class<?> clazz1 = (Class<?>) ((ParameterizedType) one.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
Class<?> clazz2 = (Class<?>) ((ParameterizedType) ((ParameterizedType) two.getClass().getGenericSuperclass()).getActualTypeArguments()[0]).getRawType();
System.out.println(clazz1.equals(clazz2));
This will return true.
Alas, any deeper answer is beyond my knowledge of generics.
Bar means Bar<Object> and Bar<?> doesn't. For example, if you have a List, you can add to it, if you have a List<?> you can't, because the compiler doesn't know if your object is compatible with the "actual generic type" of the object.
As for the reflection code, I don't know. It says getClass(), which depends on the object you call it on; in this case the object is obviously this... From where is this code called?

Getting the class of a Java generic, and interface implementation of generics

I'd like to make a class that looks basically like this:
public class MyClass<T implements Serializable) {
void function() {
Class c = T.class;
}
}
Two errors:
- I cannot call T.class, even though I can do that with any other object type
- I cannot enforce that T implements Serializable in this way
How do I solve my two generics problems?
Cheers
Nik
You can't get the type.
Generics are implemented using something called type-erasure.
When a generic type is instantiated,
the compiler translates those types by
a technique called type erasure — a
process where the compiler removes all
information related to type parameters
and type arguments within a class or
method. Type erasure enables Java
applications that use generics to
maintain binary compatibility with
Java libraries and applications that
were created before generics.
The essence of this is that the type information is used by the compiler and discarded, hence not available at runtime.
With regards to the enforcing T implements Serializable, you just need the following:
public class MyClass<T extends Serializable>)
{
public void function(T obj)
{
...
}
}
This is simply referring to the is a relationship, so an class that implements Serializable, is a Serializable and can be passed to function.
you do this:
public class MyClass<T implements Serializable) {
void function(Class<T> tc) {
...
}
}
Basically, you have to pass in the class at run time in order to see it. You could also do something like this:
public class MyClass<T implements Serializable) {
Class<T> ct;
public MyClass(Class<T> ct){this.ct = ct;}
void function() {
... //you know what the class is here
}
}
It's kind of annoying, but not really that big of a hassle overall.
Something along these lines should do it.
private Class<T> dataType;
Type type = getClass().getGenericSuperclass();
if (type instanceof ParameterizedType) {
ParameterizedType paramType = (ParameterizedType) type;
dataType = (Class<T>) paramType.getActualTypeArguments()[0];
} else if (type instanceof Class) {
dataType = (Class<T>) type;
}
You can't do T.class because java does not actually know which class T is at runtime.
All that information is lost at compilation.
To get the class object for T you can either call getClass() on an instance of T (if you have access to one) or require the user to pass the class object as an argument to function, like:
void function(Class<T> c)
This is not possible without tricks.
The Java Generics FAQ provides an idea for a workaround.

Categories

Resources