13

The JDK Proxy class only accepts interfaces in the factory method newProxyInstance().

Is there a workaround available, or alternative implementations? The use cases are limited if I have to extract methods to an interface in order to enable them for use with a proxy. I would like to wrap them to apply annotation based actions during runtime.

public static <T> T getProxy(T obj) {
   InvocationHandler ih = new InjectProxy( obj );
   ClassLoader classLoader = InjectProxy.class.getClassLoader();
   return (T) Proxy.newProxyInstance( classLoader, obj.getClass().getInterfaces(), ih );
                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  
}
5
  • 1
    Well, in principle you can use a bytecode library like ASM to create a class-based proxy yourself. Commented Dec 10, 2010 at 16:49
  • @Krik, some unit test mock libraries do this. You need to create a derived class which overrides the methods you want. (either automatically or manually) Commented Dec 10, 2010 at 16:53
  • Have you considered Aspect-J which is designed to do this sort of thing? Commented Dec 10, 2010 at 16:54
  • 1
    @Peter Lawrey I hoped for a solution using core java. Commented Dec 10, 2010 at 17:10
  • you can create the code for the derive class and compile/load it at runtime. You can use the Compiler API to do this. Commented Dec 10, 2010 at 18:27

3 Answers 3

17
+50

You can use cglib like this:

import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;


public class AbstractFactory {

    @SuppressWarnings("unchecked")
    public static <A> A createDefaultImplementation(Class<A> abstractClass) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(abstractClass);
        enhancer.setCallback(new MethodInterceptor() {
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                if (!Modifier.isAbstract(method.getModifiers())) {
                    return methodProxy.invokeSuper(proxy, args);
                } else {
                    Class type = method.getReturnType();
                    if (type.isPrimitive() && !void.class.equals(type)) {
                        return Array.get(Array.newInstance(type, 1), 0);
                    } else {
                        return null;
                    }
                }
            }
        });
        return (A) enhancer.create();
    }

    @SuppressWarnings("unchecked")
    public static <A> A createDefaultImplementation(String className) throws ClassNotFoundException{
        return (A) createDefaultImplementation(Class.forName(className));
    }
}

This for example lets you build abstract classes with a default implementation method. But you can change the enhancer to what ever you want.

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

Comments

5

Is there a workaround available..?

Yeah. There is. Extract interface from existing classes.

upd

If you need it for some specific classes, you can write smt like

//interface that already exists
public interface IDomain {
    String foo();
}
//your class
public class Domain implements IDomain{
    public String foo(){
        return "domain foo";
    }
//method that doesn't placed in IDomain
    public String bar(){
        return "domain bar";   
    }
}
//So you need create new interface with bar()
//it can extend IDomain 
public interface ExtendedIDomain extends IDomain {
    public String bar();
}
//than your wrapper factory will be like this
public class Proxifier {
    public static  ExtendedIDomain getProxy(Domain obj) {
       InvocationHandler ih = new InjectProxy( obj );
       ClassLoader classLoader = InjectProxy.class.getClassLoader();
       return (ExtendedIDomain) Proxy.newProxyInstance( classLoader, new Class[]{ExtendedIDomain.class}, ih );
    }

    static class InjectProxy implements InvocationHandler {
        private final Domain domain;
        private InjectProxy(Domain domain){
            this.domain = domain;
        }

        public String invoke(Object proxy, Method method, Object[] args) throws Throwable{
            for(Method m : domain.getClass().getMethods()){
                //TODO: check signature(name, args etc) or implement some logic with annotations
                if(m.getName().equals(method.getName())){
                    return "wrapped " + m.invoke(domain, args);
                }
            }
            throw new IllegalArgumentException();
        }
    }
}
//test
    public static void main(String[] args) {
        ExtendedIDomain d = Proxifier.getProxy(new Domain());
        System.out.println(d.foo());
        System.out.println(d.bar());
    }

If you need some "universal" stuff you should use AOP as @Peter Lawrey allready said.

2 Comments

Thanks, but as I already mentioned: "The use cases are limited if I have to extract methods to an interface in order to enable them for use with a proxy"
@stacker, it seems that you don't need some util, only solve concrete problem.. I've updated my post for this purpose.
2

or alternative implementations

You can use cglib.

Similar posts on alternatives to cglib : Are there alternatives to cglib?

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.