简体   繁体   中英

Imitate implementing methods from given interface at runtime

Suppose I have a unknown interface, and I want to be able to construct an object which, when user calls some method from interface on it, returns something specified by that interface. Eg having a Class class object, representing unknown Interface , I want to be able to construct an Object , which behaves like something which correctly implements that Interface . For instance, say I'm working on method

public <E> E myMethod(Class<E> class){
    ...
    return res;
}

Where class is representation of an unknown interface, let for instance

public <E> interface Writer{
    public String write(String s);
}
Class<E> class = Writer.class;

All I want now is that any call like

returnedFromMyMethod.write(s);

actually do the job, eg returns given string I know that there's reflection to be used, because all of that is going on in runtime, we don't know what exactly the interface is. But can't figure it out. Any ideas?

EDIT : To avoid misunderstanding.

  1. That's all going in runtime. I don't know what that interface is. It can be Writer as possibly as Runnable , Comparable or any other. It is for sure one interface.
  2. Our object doesn't exist, it hasn't got any of methods we want. It's like constructing a new object (of parametrized type) from zero.

So question is about creating an object that imitates implementing all methods from given interface

Change your method and interface as

public <E extends Writer> E myMethod(Class<E> clazz) {      
    ...
    return res;
}

public interface Writer {
    public String write(String s);
}

Now you will be able to call write(String s) method on the return value of myMethod(Class<E> clazz) .

Writer w = myMethod(WriterImpl.class);
w.write("any string");

You can put that class into a java decompiler such as javadecompilers.com and then you can find out what interface it extends, or you can go the reflection route like this:

//Assuming the class only extends 1 interface you can do this
Class<?>[] interfaces = class.getClass().getInterfaces();
//Now since we know interfaces[0] is the desired interface, we can get its name
System.out.printLn(intefaces[0].getName()); //You don't have to print the name if you're just going to continue with reflection
//now we're going to define the s variable which will hold what the method returns
String result = "";
//Next using reflection we're going to get the desired method, invoke it, give reflection it's return type and your argument
try {
    result = interfaces([0].getMethod("write").invoke(String.class, args);
    } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException
            | SecurityException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

This is what you could do if you wished to use reflection. On the contrary, if I have miss understood what the question was, any Class that implements an Interface automatically has those methods to be called. Therefore, doing class.write(s); would return a String just like normal.

You can create a dynamic proxy :

@SuppressWarnings("unchecked")
public static <E> E myMethod(Class<E> cls) {
    return (E) Proxy.newProxyInstance(cls.getClassLoader(), new Class[] { cls },
        (Object proxy, Method method, Object[] arguments) -> {
            // handle the invocation of the given method
            return null; // return something actual
        });
}

Writer result = makeProxy(Writer.class); // e.g.

As long as you have a plan for how to handle the invocations. Of course there is no way to do that out 'automagically'.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM