/* * 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" + " 0.75\n" + " $THRESHOLD$\n" + " \n" + " $CAPACITY$\n" + " 1\n" + " URL\n" + " http://xstream.codehaus.org\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" + " \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)); } }