2

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.

2
  • You can create a proxy by yourself. I think that's the only solution besides using a different library. Commented Dec 4, 2014 at 20:12
  • I thought about that, but I would find a library that was well tested instead of creating my own. Commented Dec 5, 2014 at 7:12

4 Answers 4

4

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for your answer. Does this library modify source class or creates new or just allows instantiate new instances ?
objenesis is only used for creating new instances. So you should combine cglib and objenesis. Here is a blog entry that describes it pretty well: brixomatic.wordpress.com/2012/12/22/dynamic-proxies-for-classes
3

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);
    }
}

Comments

3

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();

1 Comment

A new constructor is created here every time, so you need to cache or use the objenesis API.
2

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.