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.
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 am trying decouple a third party library's abstract class. I want to expose a new abstract class which will be exposed to the users rather than the library provided class.
I initially tried using an adapter but that stills add the import for the third party lib in the adapter class.
I added code below explaining my new approach.
// third party lib
abstract class ThirdParty<S> {
public abstract S doAction(S s);
}
// my goal here is to expose a different abstract class which is decoupled from third party lib
// exposed to other modules, rather than exposing the third party lib
abstract class ExposedAbstractClass<S> {
public abstract S doAction(S source);
// get hold of type using guava lib
private final TypeToken<S> typeToken = new TypeToken<S>(getClass()) { };
public Class<S> getSourceClass() { return (Class<S>) typeToken.getClass()
}
// internal class
class Builder<S> extends ThirdPartyLib<S> {
ExposedAbstractClass exposed;
public Builder(ExposedAbstractClass exposed) {
this.exposed = exposed;
}
#Override
public S doAction(S s) {
return (S) exposed.doAction(s);
}
}
//my approach breaks here when i try to invoke builder
class InvokeThirdParty {
public void invoke (ExposedAbstractClass exposed) {
Class type = exposed.getSourceClass();
Builder<type> builder = new Builder(exposed); //doesn't work since Class is runtime type, and T is compile time type
}
}
Any guidance in terms of which design pattern to follow here would be very helpful.
I agree with GuaravJ answer, you could isolate the third party dependency and use an Adaptor or Bridge pattern to invoke the third party library from there. I believe this would be an adequate decoupled solution.
However, it would seem your intent is to remove the import, hence the dependency?
As an alternative, how about implementing Reflection on the ThirdParty class?
Java is compatible with Reflection-oriented-programming. This lets you inspect and examine classes and invoke their methods dynamically at runtime. It would eliminate the dependency and the import statement for the ThirdParty class.
In general terms, with Reflection, you have to locate the class and inspect its methods. In this case I'm assuming knowledge of the doAction() method from ThirdPartyClass.
A simple Java reflection example following the idea of your code excerpt:
Not using reflection
// import ThirdPartyLibrary statement somewhere here
// Instantiating object with concrete class that implements methods from ThirdParty. From your code now, it would be "Builder".
ThirdParty<S> thirdPartyObject = new ThirdPartyImp<S>();
// Invoking doAction method which returns an S object
S foo = thirdPartyObject.doAction();
Using reflection
// Inspect the class finding it using its path and instantiating an object
ThirdParty<S> thirdPartyObject = Class.forName("classpath.to.ThirdPartyImp").newInstance(); // Using a concrete class to instantiate.
// Finding the doAction method. This is assuming we have knowledge that a method with this name exists. Reflection could go as deep as not knowing the methods and having some control structure inspecting them.
Method doAction = thirdPartyObject.getClass().getDeclaredMethod("doAction", new Class<?>[0]);
// Do action is invoked and it returns an object S.
S foo = thirdPartyObject.invoke(thirdPartyObject);
Further reading and notes
Oracle Java official documentation on reflection
Java Reflection example tutorial
Wikipedia Reflection (Computer Science) definition and examples
I'm writing a lib and I need to create proxies for some objects. Since some classes don't implement any interfaces then I decided to use CGLIB to create proxies instead of JDK proxy. But I faced with situation when some classes don't have default constructor and CGLIB fails to create proxies for those types, i.e. CGLIB throws exception with message: Superclass has no null constructors but no arguments were given. How I can solve this problem, is there some way to add default constructor in runtime using cglib/asm or some another instrument? Thanks.
Use http://objenesis.org/. One of its typical use cases exactly addresses your problem:
Proxies, AOP Libraries and Mock Objects - Classes can be subclassed
without needing to worry about the super() constructor.
I'll just copy and paste the solution from the blog post provided in the comments to another answer to preserve it. It combines Objenesis and CGLIB and it really works.
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.objenesis.ObjenesisHelper;
public class ProxyPlayground {
public static void main(final String[] args) {
final MethodInterceptor hashCodeAlwaysNull = new MethodInterceptor() {
#Override
public Object intercept(final Object object, final Method method,
final Object[] args, final MethodProxy methodProxy)
throws Throwable {
if ("hashCode".equals(method.getName())) {
return 0;
}
return methodProxy.invokeSuper(object, args);
}
};
final Foo proxy = createProxy(Foo.class, hashCodeAlwaysNull);
System.out.println(proxy.hashCode()); // prints 0
}
#SuppressWarnings("unchecked")
private static <T> T createProxy(final Class<Foo> classToMock,
final MethodInterceptor interceptor) {
final Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(classToMock);
enhancer.setCallbackType(interceptor.getClass());
final Class<?> proxyClass = enhancer.createClass();
Enhancer.registerCallbacks(proxyClass, new Callback[] { interceptor });
return (T) ObjenesisHelper.newInstance(proxyClass);
}
}
It's possible, below code reference from objenesis.
ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();
Constructor<?> constructor = reflectionFactory.newConstructorForSerialization(YourObject.class, Object.class.getConstructor((Class[]) null));
Object instance = constructor.newInstance();
What you assume to be express as byte code, cannot be done as it would be rejected by the JVM' verifier. As pointed out by the other answer, you should consider using a library such as Objenesis. However, note that Objenesis makes use of JVM-internal APIs what will not longer be possible using Java 9 when project Jigsaw is introduced.
For this reason, you might rather approach the matter differently. Cglib merely copies all constructors of the super class. You want to call any constructor of which you know it is side effect free. Simply pass null values or 0 values for primitives. As long as you intercept all methods, the object state does not matter anyways as none of the real methods are ever invoked.
I'm digging through a web application in an effort to fix some problems. The application uses Tomcat, Jersey and Guice. One of the issues is occurring in a MethodInterceptor used for authorization purposes. Here's the method, trimmed to the relevant part:
public Object invoke(MethodInvocation invoc) throws Throwable {
// ...
//Check that the annotation actually exists
if(! invoc.getMethod().getDeclaringClass().isAnnotationPresent(Tool.class))
{
throw new BaseException("...");
}
// ...
}
Now the problem is that some of the "web-facing" methods are inherited from a parent class without being overridden in the child. If I understand getDeclaringClass() correctly, it will return the parent class in this case, but what we really want here is the child class. Some testing seems to confirm this--if I override the method in the child class everything is fine, but if I don't put in the override the exception is thrown.
So, given a MethodInvocation object, is there a way to trace it back to the "actual" class instantiated, rather than the class where the method was declared? Or is some other approach necessary? Worst-case, I could just annotate each method as necessary rather than annotating the class.
Sorry if this is a long-winded question for an easy answer - my Java is pretty rusty.
Simple enough, needed to use getThis().getClass() on the MethodInvocation instead of getMethod().getDeclaringClass():
if(! invoc.getThis().getClass().isAnnotationPresent(Tool.class))
{
throw new BaseException("...");
}
Although in my case, Guice complicated things a bit by putting in an auto-generated child class (e.g., a class name ending in "$$EnhancerByGuice..." That was fixed by moving one up the tree with getSuperclass():
if(! invoc.getThis().getClass().getSuperclass().isAnnotationPresent(Tool.class))
{
throw new BaseException("...");
}
It looks like that the answer is No. I created simple test to check it:
class Run implements Runnable {
#Override
public void run() {
}
}
class Run2 extends Run{}
Method method = Run2.class.getMethods()[0];
System.out.println(method);
As we can see in debug window method doesn't have any information of class Run2:
I guess it would be better to stick on actual methods with its annotations rather then on actual class instances where these methods get invoked.
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