/*
* Copyright (C) 2006, 2007 XStream Committers.
* All rights reserved.
*
* The software in this package is published under the terms of the BSD
* style license a copy of which has been included with this distribution in
* the LICENSE.txt file.
*
* Created on 08. April 2006 by Joerg Schaible
*/
package com.thoughtworks.acceptance;
import com.thoughtworks.xstream.converters.ConversionException;
import com.thoughtworks.xstream.core.JVM;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.InvocationHandler;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.proxy.NoOp;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
/**
* @author Jörg Schaible
*/
public class CglibCompatibilityTest extends AbstractAcceptanceTest {
public static class DelegatingHandler implements InvocationHandler, Serializable {
private Object delegate;
public DelegatingHandler(Object delegate) {
this.delegate = delegate;
}
public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
return method.invoke(delegate, args);
}
}
public void testSupportsClassBasedProxiesWithFactory() throws NullPointerException, MalformedURLException {
final Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(HashMap.class);
enhancer.setCallback(new DelegatingHandler(new HashMap()));
enhancer.setUseFactory(true); // true by default
final Map orig = (Map)enhancer.create();
orig.put("URL", new URL("http://xstream.codehaus.org"));
final String xml = ""
+ "\n"
+ " java.util.HashMap\n"
+ " \n"
+ " true\n"
+ " \n"
+ " \n"
+ " \n"
+ " URL\n"
+ " http://xstream.codehaus.org\n"
+ " \n"
+ " \n"
+ " \n"
+ "";
assertBothWays(orig, xml);
}
public void testSupportsClassBasedProxiesWithoutFactory() throws NullPointerException, MalformedURLException {
final Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(HashMap.class);
enhancer.setCallback(new DelegatingHandler(new HashMap()));
enhancer.setUseFactory(false);
final Map orig = (Map)enhancer.create();
orig.put("URL", new URL("http://xstream.codehaus.org"));
final String xml = ""
+ "\n"
+ " java.util.HashMap\n"
+ " \n"
+ " false\n"
+ " \n"
+ " \n"
+ " \n"
+ " URL\n"
+ " http://xstream.codehaus.org\n"
+ " \n"
+ " \n"
+ " \n"
+ "";
assertBothWays(orig, xml);
}
public void testSupportForClassBasedProxyWithAdditionalInterface() throws NullPointerException {
final Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(HashMap.class);
enhancer.setCallback(NoOp.INSTANCE);
enhancer.setInterfaces(new Class[]{Runnable.class});
final Map orig = (Map)enhancer.create();
final String xml = ""
+ "\n"
+ " java.util.HashMap\n"
+ " \n"
+ " java.lang.Runnable\n"
+ " \n"
+ " true\n"
+ " \n"
+ "";
final Object serialized = assertBothWays(orig, xml);
assertTrue(serialized instanceof HashMap);
assertTrue(serialized instanceof Map);
assertTrue(serialized instanceof Runnable);
}
public void testSupportsProxiesWithMultipleInterfaces() throws NullPointerException {
final Enhancer enhancer = new Enhancer();
enhancer.setCallback(NoOp.INSTANCE);
enhancer.setInterfaces(new Class[]{Map.class, Runnable.class});
enhancer.setUseFactory(true);
final Map orig = (Map)enhancer.create();
final String xml = ""
+ "\n"
+ " java.lang.Object\n"
+ " \n"
+ " java.util.Map\n"
+ " java.lang.Runnable\n"
+ " \n"
+ " false\n"
+ " \n"
+ "";
final Object serialized = assertBothWays(orig, xml);
assertTrue(serialized instanceof Map);
assertTrue(serialized instanceof Runnable);
}
public void testThrowsExceptionForProxiesWithMultipleCallbacks() throws NullPointerException {
final Enhancer enhancer = new Enhancer();
enhancer.setCallbacks(new Callback[]{NoOp.INSTANCE, new DelegatingHandler(null), NoOp.INSTANCE});
enhancer.setCallbackFilter(new CallbackFilter() {
public int accept(Method method) {
return 0;
}
});
enhancer.setInterfaces(new Class[]{Runnable.class});
final Runnable orig = (Runnable)enhancer.create();
try {
xstream.toXML(orig);
fail("Thrown " + ConversionException.class.getName() + " expected");
} catch (final ConversionException e) {
assertTrue(e.getMessage().toLowerCase().indexOf("multiple callbacks") >= 0);
}
}
public void testSupportsSerialVersionUID()
throws NullPointerException, NoSuchFieldException, IllegalAccessException {
final Enhancer enhancer = new Enhancer();
enhancer.setCallback(NoOp.INSTANCE);
enhancer.setInterfaces(new Class[]{Runnable.class});
enhancer.setSerialVersionUID(new Long(20060804L));
final Runnable orig = (Runnable)enhancer.create();
final String xml = ""
+ "\n"
+ " java.lang.Object\n"
+ " \n"
+ " java.lang.Runnable\n"
+ " \n"
+ " false\n"
+ " \n"
+ " 20060804\n"
+ "";
final Object serialized = assertBothWays(orig, xml);
final Field field = serialized.getClass().getDeclaredField("serialVersionUID");
field.setAccessible(true);
assertEquals(20060804L, field.getLong(null));
}
public static class InterceptingHandler implements MethodInterceptor {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
return proxy.invokeSuper(obj, args);
}
}
private final static String THRESHOLD_PARAM = "$THRESHOLD$";
private final static String CAPACITY_PARAM = "$CAPACITY$";
public void testSupportsInterceptedClassBasedProxies() throws NullPointerException, MalformedURLException {
final Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(HashMap.class);
enhancer.setCallback(new InterceptingHandler());
enhancer.setUseFactory(false);
final Map orig = (Map)enhancer.create();
orig.put("URL", new URL("http://xstream.codehaus.org"));
final StringBuffer xml = new StringBuffer(""
+ "\n"
+ " java.util.HashMap\n"
+ " \n"
+ " false\n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ "");
// JDK 1.3 has different threshold and capacity algorithms
int idx = xml.toString().indexOf(THRESHOLD_PARAM);
xml.replace(idx, idx + THRESHOLD_PARAM.length(), JVM.is14() ? "12" : "8");
idx = xml.toString().indexOf(CAPACITY_PARAM);
xml.replace(idx, idx + CAPACITY_PARAM.length(), JVM.is14() ? "16" : "11");
Map serialized = (Map)assertBothWays(orig, xml.toString());
assertEquals(orig.toString(), serialized.toString());
}
public static class ClassWithProxyMember {
Runnable runnable;
Map map;
};
public void testSupportsProxiesAsFieldMember() throws NullPointerException {
ClassWithProxyMember expected = new ClassWithProxyMember();
xstream.alias("with-proxy", ClassWithProxyMember.class);
final Enhancer enhancer = new Enhancer();
enhancer.setCallback(NoOp.INSTANCE);
enhancer.setInterfaces(new Class[]{Map.class, Runnable.class});
enhancer.setUseFactory(true);
final Map orig = (Map)enhancer.create();
expected.runnable = (Runnable)orig;
expected.map = orig;
final String xml = ""
+ "\n"
+ " \n"
+ " java.lang.Object\n"
+ " \n"
+ " java.util.Map\n"
+ " java.lang.Runnable\n"
+ " \n"
+ " false\n"
+ " \n"
+ " \n"
+ " ";
final Object serialized = assertBothWays(expected, xml);
assertTrue(serialized instanceof ClassWithProxyMember);
}
public void testProxyTypeCanBeAliased() throws MalformedURLException {
final Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(HashMap.class);
enhancer.setCallback(new DelegatingHandler(new HashMap()));
enhancer.setUseFactory(true); // true by default
final Map orig = (Map)enhancer.create();
orig.put("URL", new URL("http://xstream.codehaus.org"));
xstream.aliasType("cglib", Map.class);
final String expected = ""
+ "\n"
+ " java.util.HashMap\n"
+ " \n"
+ " true\n"
+ " \n"
+ " \n"
+ " \n"
+ " URL\n"
+ " http://xstream.codehaus.org\n"
+ " \n"
+ " \n"
+ " \n"
+ "";
assertEquals(expected, xstream.toXML(orig));
}
}