I'm trying to create a proxy for a given Runnable object using the following code:
public class WorkInvocationHandler implements InvocationHandler {
public static Runnable newProxyInstance(Runnable work)
{
return (Runnable)java.lang.reflect.Proxy.newProxyInstance(
work.getClass().getClassLoader(),
getInterfacesWithMarker(work),
new WorkInvocationHandler(work));
}
private static Class[] getInterfacesWithMarker(Runnable work)
{
List allInterfaces = new ArrayList();
// add direct interfaces
allInterfaces.addAll(Arrays.asList(work.getClass().getInterfaces()));
// add interfaces of super classes
Class superClass = work.getClass().getSuperclass();
while (!superClass.equals(Object.class))
{
allInterfaces.addAll(Arrays.asList(superClass.getInterfaces()));
superClass = superClass.getClass().getSuperclass();
}
// add marker interface
allInterfaces.add(IWorkProxy.class);
return (Class [])allInterfaces.toArray(new Class[allInterfaces.size()]);
}
}
The proxy should implement all interfaces that the given object implements with the additional marker interface that indicates whether the proxy was already created.
Since I don't know for sure that the given object implements Runnable directly I traverse also on all super classes, however I assume that if it implements another interface that implements Runnable it will work so I don't need to traverse also on interfaces hierarchy.
However, I still get ClassCastException when trying to cast the proxy to Runnable:
java.lang.ClassCastException: $Proxy24 incompatible with java.lang.Runnable
I'm trying to think what could cause this exception. The class hierarchy of the given object is not available.
Any ideas ?
UPDATE removed useless code.
This is not the problem, but you should use a Set<Class<?>> when you gather all the interfaces because you can get duplicates of the same interface in the hierarchy.
Your code to walk the super classes is wrong. Replace
superClass = superClass.getClass().getSuperclass();
with
superClass = superClass.getSuperclass();
Otherwise you'll quickly take a detour to java.lang.Class and then to java.lang.Object.
Related
I have an interface defined as follows:
public interface Cache {
}
Then an abstract class implementing the above:
public abstract class AbstractCache implements Cache {
}
Then a concrete class inheriting from above:
public class RealTimeCache extends AbstractCache {
}
Then another class defined as follows:
public class CacheProbe {
public static <T> T probe(T base) {
return (T) Proxy.newProxyInstance(
base.getClass().getClassLoader(),
new Class[]{Cache.class},
new MethodCountInvocationHandler(base) // I am not mentioning this class as it's irrelevant
);
}
}
I have a class as follows which is using all of the above:
public class CacheLoader<T extends Cache> {
public T load() {
T result = getResult(...);
CacheProbe x = new CacheProbe(result);
return x.probe();
}
}
Lastly, the lines causing the issue (located outside above classes):
final CacheLoader<RealTimeCache> cacheLoader = getNewLoader(); //Method of this method is irrelevant and unchangeable
RealTimeCache x = cacheLoader.load(); //This is the line which is causing a runtime issue
Problem is, at run time the following exception is thrown at the last line mentioned above:
java.lang.ClassCastException: com.sun.proxy.$Proxy57 cannot be cast to RealTimeCache
However I don't see how this is possible because the dynamic proxy class generated is based on Cache.
How do I fix this ?
Please note that I can only change CacheProbe class in order to fix this. Cache, AbstractCache, RealTimeCache, CacheLoader and those last two lines are unchangeable.
However I don't see how this is possible because the dynamic proxy class generated is based on Cache.
Yes, the docs for java.lang.reflect.Proxy say
Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.
(emphasis added)
Thus, you cannot use Proxy to create (an instance of) a subclass of an arbitrary class of your choice.
How do I fix this ?
You can create an ordinary subclass of RealTimeCache, and return an instance of that. Proxy is meant primarily to serve for interfaces that are not known until runtime, and in that case the only way to interact with them anyway is the interface type. That's not your scenario.
If necessary, you can implement such a subclass in terms of a MethodCountInvocationHandler, just as your proxy class uses, but I'm sure it would be easier to implement whatever tooling that is supposed to provide directly.
I made a Dynamic Proxy to be the middle man when handling specific methods in a class. I'm doing this to avoid having to override every single method in each of the interfaces that I need to take control of.
Waffley bit that nobody will understand or care about (but may add more context to the question):
In the example I am going to give, I've tried to make it generic so you can compile it to test and run yourself, but in the real situation, I have something like this:
interface CommandSender
interface ConsoleCommandSender extends CommandSender
interface Player extends CommandSender
If I were to make a proxy of a ConsoleCommandSender instance, the resulting proxy SHOULD be castable to a CommandSender. In reality, ConsoleCommandSender doesn't list all of its interfaces with getInterfaces() and this happens:
java.lang.ClassCastException: $Proxy18 cannot be cast to org.bukkit.command.CommandSender
The Player class does not have this issue, and is always castable to CommandSender.
The real question:
So, using the following code as a starting point, how can one successfully cast the proxy denoted by myProxy to the format desired without having to worry about the ClassCastException?
The following code will successfully compile and run, but hopefully you understand what I'm getting at by casting to a List rather than an ArrayList.
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
public class ProxyClass implements InvocationHandler {
private Object classProxy;
public static void main(String[] args) {
// Example declaration
// (I know the proxy should really be cast as an ArrayList
// but this is my point, it SHOULD work anyway)
ArrayList methodObject = new ArrayList<String>();
List<String> myProxy = (List<String>)ProxyClass.newInstance(methodObject, false);
// Example usage
myProxy.add("Hello World!");
System.out.println(myProxy.get(0));
}
public static Object newInstance(Object proxy, boolean silent) {
return Proxy.newProxyInstance(
proxy.getClass().getClassLoader(),
proxy.getClass().getInterfaces(),
new ProxyClass(proxy));
}
private ProxyClass(Object proxy) {
this.classProxy = proxy;
}
// Is called whenever a method is invoked
public Object invoke(Object p, Method m, Object[] args) throws Throwable {
return m.invoke(classProxy, args);
}
}
On another thread I made about the preliminary part of this issue, one guy commented saying I could use the <T> variable to add another valid interface to the list. I didn't really understand how to implement this though, but it seemed like a good start.
I am not 100% sure I admit I understood your question -
You want to be able to "directly" cast to ArrayList? I mean -
ArrayList<String> myProxy = (ArrayList<String>)ProxyClass.newInstance(methodObject, false);
This just won't work for you. The reason is that the generated object is not an instant of ArrayList. In a sense the behavior resembles decorator.
Is decorator an instance of the object it decorates? No, they conform to the same interface.
What you should do is consider using CGLIB.
CGLIB let's you create proxies (intercepted objects) for classes.
a Proxied object by CGBLib is indeed an instance of the proxied object.
If I remember correctly, Hibernate uses CGLib and ASM in order to proxy the entity objects,
You can see here a link to some experiments I did with CGLIB.
I have a class defined by an interface
public interface Test {
void testMethod();
}
Test test = new TestImpl();
public class TestImpl implements Test {
#Override
public void testMethod() {
//Nothing to do here
}
public void anotherMethod() {
//I am adding this method in the implementation only.
}
}
How can I call anotherMethod?
test.anotherMethod(); //Does not work.
I want to be able to define a few methods in the implementation only because in my production code, the Test interface covers a pretty broad spectrum of classes and is implemented by multiple classes. I use methods defined in the implementation to set dependencies that aren't covered by the DI framework in my unit testing so the methods change from implementation to implementation.
The problem is with the following line:
Test test = new TestImpl();
This tells the compiler to forget that the new object is a TestImpl and treat it as a plain old Test. As you know, Test does not have anotherMethod().
What you did is called "upcasting" (casting an object to a more general type). As another poster has said, you can fix your problem by not upcasting:
TestImpl test = new TestImpl();
If you're sure that a Test object is really a TestImpl, you can downcast it (tell the compiler it is a more specific type):
Test test = new TestImpl();
:
((TestImpl) test).anotherMethod();
This is generally a bad idea, however, since it can cause ClassCastException. Work with the compiler, not against it.
use
TestImpl test = new TestImpl();
then
test.anotherMethod();//It will work now
I think through your Interface reference it is impossible to call any method which is not defined in that interface.
If you want to avoid casting directly to your implementation class, I would create another interface:
public interface SpecificTest extends Test {
void anotherMethod();
}
And then have your TestImpl implement that interface (which means you can declare it as either Test or SpecificTest ):
SpecificTest test = new TestImpl();
test.anotherMethod();
Of course you can access your methods as was answered above, but you should adhere to best practices in programming. So you if you can't add required methods to Interface1 create Interface2 that extends Inteface1 and finally add your methods.
You can call it if you cast to the implementing class, the one that implements that method In short:
Test test = new TestImpl();
// ... and later / somewhere else
((TestImpl) test).anotherMethod();
If you do not want to type cast it to the concrete class then you could make anotherMethod() as private method and call it inside testMethod() based on some logic.
for eg.
testMethod()
{
if(foo)
{
anotherMethod();
}
}
This is a workaround that you can use if you do not want to create new methods in child class , since you cannot call them using a parent class/interface reference.
i'm very confused...
I have a class which directly implements an interface:
public class Device implements AutocompleteResult
{...}
Here is proof that I'm looking at the right variables:
Object match = ...;
log.debug(match.getClass()); // Outputs 'Device'
log.debug(match.getClass().getInterfaces()[0]); // Outputs 'AutocompleteResult'
Yet when I try to cast an instance of the class to the interface:
AutocompleteResult result = (AutocompleteResult) match;
I get a ClassCastException!
ClassCastException: Device cannot be cast to AutocompleteResult
Also, isAssignableFrom returns false and i'm not sure why:
log.debug(AutocompleteResult.class.isAssignableFrom(Device.class));
from the doc:
Determines if the class or interface represented by this Class object is either the same as, or is a superclass or superinterface of, the class or interface represented by the specified Class parameter.
Shouldn't I always be able to cast a object to an interface its class implements?
Thanks.
This can happen if two different classloaders load a class named AutocompleteResult.
These two classes are then treated as entirely different classes, even if they have the same package and name (and even implementation/fields/methods).
A common cause for this is if you use some kind of plugin system and both your base classes and the plugin classes provide the same class.
To check for this issue print the value returned by Class.getClassLoader() on both offending classes (i.e. the class of the interface implemented by Device and the result of AutocompleteResult.class).
AKA when Java apparently doesn't Java.
I hit this problem recently with Play Framework 2.6.3, what helped me was this:
https://www.playframework.com/documentation/2.6.x/ThreadPools#Application-class-loader
I leave this info here for the people that might have the same problem.
To make it clearer, what helps is:
Injecting Application on an Eager Singleton and then using its classloader to load the classes I was having issues with.
To make it clearer
public class Module {
#Override
public void configure {
bind(TheClassLoaderLoader.class).asEagerSingleton()
public static class TheClassLoaderLoader {
#Inject
public TheClassLoaderLoader( Application application) {
ClassLoader classloader = application.classloader();
Class<?> interfaceClass = classloader.loadClass(InterfaceClass.class.getName());
classloader.loadClass(ImplementsInterfaceClass.class.getName()).asSubclass(interfaceClass);
The example here https://playframework.com/documentation/2.6.x/JavaDependencyInjection#Configurable-bindings
That uses Environment often throws a frustrating ClassNotFoundException
Cheers
My factory class has a collection of classes, I don't want that dependency, when I add a subclass of SuperClass I need the factory file to stay unchanged
edit:
My factory class has to return all Superclass's subclasses instances, but I can't have a collections of them (or their names) because that's means I will have to change the Factory file whenever I add a new subclass!
package reflection;
public final class Factory {
private final SuperClass[] subclasses_collection
= {new SubClass1(), new SubClass2() /* ...SubClassN */};
public final SuperClass[] getAllSubClasses() {
return subclasses_collection;
}
}
instead of
new SubClass1()
do something like this
Class clazz = Class.forName("SubClass1");
Object subclass1 = clazz.newInstance();
if you want to pass arguments to the constructor, consult this article, section Creating New Objects
http://java.sun.com/developer/technicalArticles/ALT/Reflection/
To find all the subclasses of a given class, I would check out this java world site. It goes through a package, loads the classes, and tests them to see if there are any subclasses.
If you want to search for all subclasses of a class, you can use reflection, as Jeffrey says. However, rather than writing the code to do that yourself, or copy-and-pasting it from some random article, i would use ResolverUtil from the Stripes web framework, which does exactly what you want (and more!).
An alternative to classpath scanning would be to build up a registry at runtime. You could create a base class like this:
public abstract class SuperClass {
private static final Set<Class<? extends SuperClass>> SUB_CLASSES = new HashSet<Class<? extends SuperClass>>();
/* instance initializer */ {
SUB_CLASSES.put(getClass());
}
}
Every subclass of that which is instantiated will add itself to the set of subclasses. Your factory can then use that set. All you have to do is ensure that all the subclasses are instantiated at some point - perhaps using a configuration file, or through startup actions of other parts of your system.