CGLib Enhancer with anonymous class - java

I'm using CGLib to proxy classes. I've hit a problem where I can not enhance anonymous classes because they don't have a default constructor.
My code looks like this:
Enhancer enhancer = new Enhancer();
enhancer.setCallback(new MethodInterceptor() { .... });
enhancer.setSuperclass(type); // type is the Class I'm trying to enhance
enhancer.create();
However this throws the following exception if the enhanced class is anonymous (no default constructor).
java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
Is there a way to go around this?

A JVM's verifier assures that you call a valid constructor chain. The only way around this is to disable the verifier by command line when starting up the JVM and this is nothing you generally want to do as it introduces several insecurities to your application.
Thus, you will have to call a valid constructor of your anonymous class which is imitated by the subclass that is created by cglib. This class's constructor thus takes an instance of its enclosing class as its argument. If you use cglib to create a pure proxy that never calls a real method, you can consider handing null to this constructor but you still need to select the right constructor before handing the argument.
You can achieve this by calling:
enhancer.create(new Class<?>[] {type.getEnclosingClass()}, new Object[] {null})
where the above call selects the correct constructor and initializes the anonymous class's outer instance field with a null value.
Alternatively, you could use the internal OpenJDK class ReflectionFactory in order to create an instance without calling any constructor. This is possible after calling enhancer.createClass(). This requires however additional preparation as you need to specify a different callback.
However, you might just want to drop cglib alltogether. As a disclaimer, I am the author of an alternative library I want to recommend to you. Using Byte Buddy, you have more freedom in creating classes and it is easier to define your logic using it. Using Byte Buddy, you can write
new ByteBuddy()
.subclass(type)
.method(any()).intercept(MethodDelegation.to(new Object() {
#RuntimeType
public Object intercept(#SuperCall Callable<?> c,
#Origin Method m,
#AllArguments Object[] a) throws Exception {
// implement your interception logic
}
}).make();
and achieve the same logic. Simply remove the (annotated) arguments you do not need for calling your interception.

Related

How to create a instance in Java when we have object of type Class

I am currently working on using annotations in my Spring Boot Application. Where I am getting a successful annotation class in the below way:
Class s = applicationContext.getType(beanName);
After which I also able to get annotated method (with some if checks)
Method[] methods = s.getMethods();
I would like to invoke a particular method
Object result = method.invoke(?, args);
However the signature of invoke requires instance of the Class passed to it. I am not sure how I can get instance or object of that class?
You don't really want a Class instance there: you either want the actual instance on which the method is to be invoked (if it's an instance method), or null (if it's a static method).
It's not entirely clear what you intend to do, but if method is an instance method, you need an instance of s on which to invoke it. If s has a no-arg constructor, then you can do
Object result = method.invoke(s.getConstructor().newInstance(), args);
For constructors with other signatures, provide the type of the parameters to getConstructor() and the values for the parameters to newInstance().

Calling a method with an generic parameter with Java reflection

I need to call this method : public T unwrap(Class iface) from a class that I can't import.
I'm trying to do this :
Class jbossWrappedSt = Class.forName("org.jboss.jca.adapters.jdbc.jdk6.WrappedPreparedStatementJDK6");
Method metodoUnwrap = jbossWrappedSt.getDeclaredMethod ("unwrap", new Class[]{Class.class});
Object val = metodoUnwrap.invoke (st, new Object[] {PreparedStatement.class});
But fails with a NoSuchMethodException exception:
java.lang.NoSuchMethodException:
org.jboss.jca.adapters.jdbc.jdk6.WrappedPreparedStatementJDK6.unwrap(java.lang.Class)
Class javadoc :
https://repository.jboss.org/nexus/content/unzip/unzip/org/jboss/ironjacamar/jdbc-local/1.0.28.Final/jdbc-local-1.0.28.Final-javadoc.jar-unzip/org/jboss/jca/adapters/jdbc/JBossWrapper.html#unwrap%28java.lang.Class%29
Update: I forgot to say that we are using Java 1.5 (Yeah! I know).
You are asking for a declared method which precludes the possibility to receive an inherited method. So if WrappedPreparedStatementJDK6 inherits the method from JBossWrapper or some other class in the class hierarchy instead of declaring it itself, the lookup will fail. You should use getMethod which will provide you the method regardless of where in the class hierarchy it is defined, provided the method is public which is the case here.
Nevertheless, since it’s defined in standard Java API Wrapper interface, there is no need to use Reflection at all. If the compile-time type of st is not already PreparedStatement, you can simply invoke ((Wrapper)st).unwrap(PreparedStatement.class).
The class in the Javadoc is
org.jboss.jca.adapters.jdbc.JBossWrapper
however the class you are looking at is a different class.
The class you are look at doesn't have an unwrap method.
https://repository.jboss.org/nexus/content/unzip/unzip/org/jboss/ironjacamar/jdbc-local/1.0.28.Final/jdbc-local-1.0.28.Final-javadoc.jar-unzip/org/jboss/jca/adapters/jdbc/jdk6/WrappedPreparedStatementJDK6.html
getDeclaredmethod doesn't follow the inheritance heirarchy to find a method like getMethod does.
As the method is public, I suggest you use getMethod and you won't need to know the class which actually implements the method.
In fact you should be able to call the public method directly, but I assume there is a reason you have to use reflection.

Can I redefine a method / constructor using reflection in Java?

I have a class called A and I need to create a new object of that class without calling its constructor. I want to set all its attributes through reflection.
Can I redefine the constructor of class A using reflection?
Or is there any way other way to do this?
In the Sun/Oracle JVm you can use Unsafe.allocateInstance(Class). Otherwise you have to generate byte code to create the instance without calling a constructor. You could use ASM for this. You cannot create an instance without a constructor using Reflection alone.
BTW: You can define a new method using byte code manipulation, but to add a constructor, you have to change the class before it is loaded. (This is tricky to do)
Invoke the object with the constructor that takes the least amount of arguments; using dummy arguments. Then proceed to manipulate the object however you like.

Is it possible to call the default-constructor instead of the zero-argument constructor?

I have a util class that is supposed to call a method on a given Class object using reflection.
Right now it creates a new instances using .newInstance() and then calls the method I want to test.
The problem is that the zero-arguement constructor of some of my classes throws an Exception due to missing dependencies and such and keeps me from calling the method I actually want to test.
Is it possible to call the default-constructor of Java to create the instance instead of the custom zero-argument constructor?
You only have a default constructor, if the class has no constructors defined.
The no-arg constructor should only take the dependencies you give it (i.e. none) and it appears you believe you can still use the class without additional dependencies.
In Sun/Oracle JVM you can use Unsafe.allocateInstance(Class) which creates an instance without calling a constructor, but I would try to fix your class design first.
A default constructor is only created, when you don't provide a constructor yourself.
So, as soon as your class has at least one constructor, that default constructor isn't being created.

Javassist: how to create proxy of proxy?

I'm creating proxies with javassist ProxyFactory. When creating a single proxy all works fine.
However, when I pass a proxied object to the proxying mechanism, it fails with
javassist.bytecode.DuplicateMemberException: duplicate method: setHandler in com.mypackage.Bean_$$_javassist_0_$$_javassist_1
I'm creating the proxies with this:
public Object createProxiedInstance(Object originalInstance) throws Exception {
Class<?> originalClass = instance.getClass();
ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(originalClass);
factory.setHandler(new MethodHandler() {..});
Class<T> proxyClass = factory.createClass();
return proxyClass.newInstance();
}
So, how do I create proxies of proxies?
Update: The actual problems is that each proxy implements the ProxyObject which defines setHandler(..) method. So the 2nd proxy is trying to redefine the method, instead of overriding it in the subclass.
The problem was (actually, it's the same with CGLIB - I tried it using commons-proxy) that I should not try to create a proxy class of the proxy class. The second proxy should again be of the original class. So adding the following line resolves the problem:
if (instance instanceof ProxyObject) {
originalClass = originalClass.getSuperclass();
}
And an advice - if you can use some sort of interceptors (like the ones defined in commons-proxy), do it instead of using multiple proxies.
Its a rather late answer but you might still be interested in knowing this:
Javassist proxies are implemented rather naively. In your above code, Javassist will always create a proxy class with the following methods:
A method for any overridable method of the base class
Two methods to (a) get a proxy handler (getHandler) and (b) set a proxy handler (setHandler)
The names of the two latter methods are hardcoded by Javassist and represented by the ProxyObject interface. If you now create a proxy class of a proxy class, Javassist would schedule the creation of ProxyObject's methods twice. Once by the first condition and once by the second condition.
You could avoid this by setting a MethodFilter which specifies to not override the ProxyObject's methods such that javassist would only create the methods by the second condition. However, this would imply that you could not longer set a ProxyObject for the super class proxy without directly accessing the corresponding field via reflection. Therefore, your approach is probably the cleanest.
cglib defines callbacks per class and not per instance such that this problem with cglib is slightly different but results in another conflict.
However, if you want to create proxy classes that do not suffer these shortcomings, you might be interested in my library Byte Buddy which I wrote after getting frustrated working with cglib and javassist when working in corner cases. If you are working with runtime code generation I hope that it might help offer you some flexibility that the other libraries lack.

Categories