Reputation: 355
I want to implement a generic functionality which would enable that our domain classes are being proxied for the case that its values to be xml compliant (escaping special characters in strings). The domain classes/objects are being generated, so that they can not be changed by me. What I tried to do was following code for the generation of proxies:
public class StringValuesFormatterForXml implements InvocationHandler {
public static interface IA {
String getMa1();
List<? extends IB> getBs();
}
public static class A implements IA {
@Override
public String getMa1() {
return "Ma1";
}
@Override
public List<? extends IB> getBs() {
return Arrays.asList(new B(), new B());
}
}
public static interface IB {
String getMb1();
String getMb2();
}
public static class B implements IB {
@Override
public String getMb1() {
return "Mb1";
}
@Override
public String getMb2() {
return "Mb2";
}
}
Object destObj;
private final Map<String, Method> methods = new HashMap<>();
@SuppressWarnings("unchecked")
public static IA createProxyA(IA destObj) {
return (IA) Proxy.newProxyInstance(destObj.getClass().getClassLoader(), new Class[] {
IA.class
}, new StringValuesFormatterForXml(destObj));
}
@SuppressWarnings("unchecked")
public static Object createProxy(Object destObj, Class<?> clazz) {
return Proxy.newProxyInstance(destObj.getClass().getClassLoader(), new Class[] {
clazz
}, new StringValuesFormatterForXml(destObj));
}
public StringValuesFormatterForXml(Object destObj) {
this.destObj = destObj;
for (Method method : destObj.getClass().getMethods()) {
this.methods.put(method.getName(), method);
}
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getReturnType().isAssignableFrom(List.class)) {
List<Object> elems = (List<Object>) method.invoke(destObj, args);
List<Object> proxyElems = new ArrayList<Object>();
for (Object obj : elems) {
Object proxyObj = createProxy(obj, obj.getClass());
proxyElems.add(proxyObj);
}
return proxyElems;
}
return method.invoke(destObj, args); // Here I will format the output for xml
}
public static void main(String[] args) {
A orig = new A();
IA proxy1 = createProxyA(orig);
A proxy2 = (A) createProxy(orig, orig.getClass());
}
}
Code in createProxy(orig, orig.getClass())
throws following error java.lang.IllegalArgumentException: StringValuesFormatterForXml$A is not an interface
but the code createProxyA(orig)
does not. So it seems that I would need to have a separate creator method for every interface which I use. In our domain model there are many classes and I do not want to create for every class separate creator.
Are there any other ways/frameworks which are better suited for my case of proxying objects.
Upvotes: 0
Views: 1384
Reputation: 645
Your createProxy
method does work, you just have to pass the class of the interface as second parameter:
A orig = new A();
IA proxy1 = (IA) createProxy(orig, IA.class);
In addition I would recomment you to use the createProxy
function as a generic function in order to avoid the obkect cast:
@SuppressWarnings("unchecked")
public static <T> T createProxyB(T destObj, Class<T> clazz) {
return (T) Proxy.newProxyInstance(destObj.getClass().getClassLoader(), new Class[] { clazz },
new StringValuesFormatterForXml(destObj));
}
In this case you can call the function like this:
A orig = new A();
IA proxy1 = createProxyB(orig, IA.class);
Upvotes: 2