У меня есть экземпляр объекта, для которого мне нужно создать прокси для перехвата одного из методов:
- Объект реализует интерфейс, но мне нужно прокси полного типа, а не просто реализовать интерфейс.
- Я не знаю точный тип объекта, только его интерфейсный класс.
- Нет доступных конструкторов publi c.
- Объект Serializable.
- У меня есть полная доступность для чтения кода библиотеки, но нет возможности изменить какой-либо из них.
Так что мне нужно сделать что-то вроде:
TheObject obj = library.getObject();
TheObject proxy = createProxyObject(obj);
library.doSomethingWith(proxy);
Мне кажется, что теоретически это должно быть возможно, поскольку объект является Сериализуемым, но я не могу найти какой-либо способ его использования.
Обратите внимание на следующее: я пытался используя cglib, но я не привязан к этому вообще. Если это возможно в asm, javaassist или любой другой библиотеке, которая подойдет.
Что я имею до сих пор с cglib, так это то, что я могу проксировать простой объект с помощью конструктора publi c:
public class SimpleObject {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
// return a random number
public int getRandom() {
return (int)(Math.random() * 100);
}
}
public void testCglibEnhancer() throws Exception {
SimpleObject object = new SimpleObject();
object.setName("object 1");
System.out.println(object.getName() + " -> " + object.getRandom());
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(object.getClass());
// intercept getRandom and always return 32
ProxyRefDispatcher passthrough = proxy -> object;
MethodInterceptor fixedRandom = (obj, method, args, proxy) -> 32;
enhancer.setCallbacks(new Callback[]{passthrough, fixedRandom});
enhancer.setCallbackFilter(method -> method.getName().equals("getRandom") ? 1 : 0);
SimpleObject proxy = (SimpleObject)enhancer.create();
System.out.println(proxy.getName() + " -> " + proxy.getRandom()); // always 32
}
Но мне не удалось воспроизвести это, используя объект без конструктора publi c:
public static class ComplexObject implements Serializable {
public static ComplexObject create() {
return new ComplexObject();
}
private String name;
private ComplexObject() {
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public int getRandom() {
return (int)(Math.random() * 100);
}
}
ComplexObject proxy = (ComplexObject)enhancer.create();
// throws IllegalArgumentException: No visible constructors
Поскольку объект является сериализуемым, я могу его клонировать:
public static <T extends Serializable> T cloneViaSerialization(T source) throws IOException, ClassNotFoundException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bos);
out.writeObject(source);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream in = new ObjectInputStream(bis);
return (T)in.readObject();
}
public void testClone() throws Exception {
ComplexObject object1 = ComplexObject.create();
object1.setName("object 1");
ComplexObject object2 = cloneViaSerialization(object1);
object2.setName("object 2");
System.out.println(object1.getName() + " -> " + object1.getRandom());
System.out.println(object2.getName() + " -> " + object2.getRandom());
}
Так есть ли способ заставить cglib (или любую библиотеку) использовать этот подход?
ComplexObject object = library.getObject();
ObjectInputStream in = ... // serialised version of object
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(object.getClass());
// add callbacks etc.
// note createFromSerialized is not a existing method of
// Enhancer - it is what I'm trying to synthesise somehow
ComplexObject proxy = (ComplexObject)enhancer.createFromSerialized(in);
Спасибо