001: /*
002: * Copyright (C) 2006, 2007 XStream Committers.
003: * All rights reserved.
004: *
005: * The software in this package is published under the terms of the BSD
006: * style license a copy of which has been included with this distribution in
007: * the LICENSE.txt file.
008: *
009: * Created on 08. April 2006 by Joerg Schaible
010: */
011: package com.thoughtworks.acceptance;
012:
013: import com.thoughtworks.xstream.converters.ConversionException;
014: import com.thoughtworks.xstream.core.JVM;
015:
016: import net.sf.cglib.proxy.Callback;
017: import net.sf.cglib.proxy.CallbackFilter;
018: import net.sf.cglib.proxy.Enhancer;
019: import net.sf.cglib.proxy.InvocationHandler;
020: import net.sf.cglib.proxy.MethodInterceptor;
021: import net.sf.cglib.proxy.MethodProxy;
022: import net.sf.cglib.proxy.NoOp;
023:
024: import java.io.Serializable;
025: import java.lang.reflect.Field;
026: import java.lang.reflect.Method;
027: import java.net.MalformedURLException;
028: import java.net.URL;
029: import java.util.HashMap;
030: import java.util.Map;
031:
032: /**
033: * @author Jörg Schaible
034: */
035: public class CglibCompatibilityTest extends AbstractAcceptanceTest {
036:
037: public static class DelegatingHandler implements InvocationHandler,
038: Serializable {
039: private Object delegate;
040:
041: public DelegatingHandler(Object delegate) {
042: this .delegate = delegate;
043: }
044:
045: public Object invoke(Object obj, Method method, Object[] args)
046: throws Throwable {
047: return method.invoke(delegate, args);
048: }
049: }
050:
051: public void testSupportsClassBasedProxiesWithFactory()
052: throws NullPointerException, MalformedURLException {
053: final Enhancer enhancer = new Enhancer();
054: enhancer.setSuperclass(HashMap.class);
055: enhancer.setCallback(new DelegatingHandler(new HashMap()));
056: enhancer.setUseFactory(true); // true by default
057: final Map orig = (Map) enhancer.create();
058: orig.put("URL", new URL("http://xstream.codehaus.org"));
059: final String xml = ""
060: + "<CGLIB-enhanced-proxy>\n"
061: + " <type>java.util.HashMap</type>\n"
062: + " <interfaces/>\n"
063: + " <hasFactory>true</hasFactory>\n"
064: + " <com.thoughtworks.acceptance.CglibCompatibilityTest_-DelegatingHandler>\n"
065: + " <delegate class=\"map\">\n"
066: + " <entry>\n"
067: + " <string>URL</string>\n"
068: + " <url>http://xstream.codehaus.org</url>\n"
069: + " </entry>\n"
070: + " </delegate>\n"
071: + " </com.thoughtworks.acceptance.CglibCompatibilityTest_-DelegatingHandler>\n"
072: + "</CGLIB-enhanced-proxy>";
073:
074: assertBothWays(orig, xml);
075: }
076:
077: public void testSupportsClassBasedProxiesWithoutFactory()
078: throws NullPointerException, MalformedURLException {
079: final Enhancer enhancer = new Enhancer();
080: enhancer.setSuperclass(HashMap.class);
081: enhancer.setCallback(new DelegatingHandler(new HashMap()));
082: enhancer.setUseFactory(false);
083: final Map orig = (Map) enhancer.create();
084: orig.put("URL", new URL("http://xstream.codehaus.org"));
085: final String xml = ""
086: + "<CGLIB-enhanced-proxy>\n"
087: + " <type>java.util.HashMap</type>\n"
088: + " <interfaces/>\n"
089: + " <hasFactory>false</hasFactory>\n"
090: + " <com.thoughtworks.acceptance.CglibCompatibilityTest_-DelegatingHandler>\n"
091: + " <delegate class=\"map\">\n"
092: + " <entry>\n"
093: + " <string>URL</string>\n"
094: + " <url>http://xstream.codehaus.org</url>\n"
095: + " </entry>\n"
096: + " </delegate>\n"
097: + " </com.thoughtworks.acceptance.CglibCompatibilityTest_-DelegatingHandler>\n"
098: + "</CGLIB-enhanced-proxy>";
099:
100: assertBothWays(orig, xml);
101: }
102:
103: public void testSupportForClassBasedProxyWithAdditionalInterface()
104: throws NullPointerException {
105: final Enhancer enhancer = new Enhancer();
106: enhancer.setSuperclass(HashMap.class);
107: enhancer.setCallback(NoOp.INSTANCE);
108: enhancer.setInterfaces(new Class[] { Runnable.class });
109: final Map orig = (Map) enhancer.create();
110: final String xml = "" + "<CGLIB-enhanced-proxy>\n"
111: + " <type>java.util.HashMap</type>\n"
112: + " <interfaces>\n"
113: + " <java-class>java.lang.Runnable</java-class>\n"
114: + " </interfaces>\n"
115: + " <hasFactory>true</hasFactory>\n"
116: + " <net.sf.cglib.proxy.NoOp_-1/>\n"
117: + "</CGLIB-enhanced-proxy>";
118:
119: final Object serialized = assertBothWays(orig, xml);
120: assertTrue(serialized instanceof HashMap);
121: assertTrue(serialized instanceof Map);
122: assertTrue(serialized instanceof Runnable);
123: }
124:
125: public void testSupportsProxiesWithMultipleInterfaces()
126: throws NullPointerException {
127: final Enhancer enhancer = new Enhancer();
128: enhancer.setCallback(NoOp.INSTANCE);
129: enhancer
130: .setInterfaces(new Class[] { Map.class, Runnable.class });
131: enhancer.setUseFactory(true);
132: final Map orig = (Map) enhancer.create();
133: final String xml = "" + "<CGLIB-enhanced-proxy>\n"
134: + " <type>java.lang.Object</type>\n"
135: + " <interfaces>\n"
136: + " <java-class>java.util.Map</java-class>\n"
137: + " <java-class>java.lang.Runnable</java-class>\n"
138: + " </interfaces>\n"
139: + " <hasFactory>false</hasFactory>\n"
140: + " <net.sf.cglib.proxy.NoOp_-1/>\n"
141: + "</CGLIB-enhanced-proxy>";
142:
143: final Object serialized = assertBothWays(orig, xml);
144: assertTrue(serialized instanceof Map);
145: assertTrue(serialized instanceof Runnable);
146: }
147:
148: public void testThrowsExceptionForProxiesWithMultipleCallbacks()
149: throws NullPointerException {
150: final Enhancer enhancer = new Enhancer();
151: enhancer.setCallbacks(new Callback[] { NoOp.INSTANCE,
152: new DelegatingHandler(null), NoOp.INSTANCE });
153: enhancer.setCallbackFilter(new CallbackFilter() {
154: public int accept(Method method) {
155: return 0;
156: }
157: });
158: enhancer.setInterfaces(new Class[] { Runnable.class });
159: final Runnable orig = (Runnable) enhancer.create();
160: try {
161: xstream.toXML(orig);
162: fail("Thrown " + ConversionException.class.getName()
163: + " expected");
164: } catch (final ConversionException e) {
165: assertTrue(e.getMessage().toLowerCase().indexOf(
166: "multiple callbacks") >= 0);
167: }
168: }
169:
170: public void testSupportsSerialVersionUID()
171: throws NullPointerException, NoSuchFieldException,
172: IllegalAccessException {
173: final Enhancer enhancer = new Enhancer();
174: enhancer.setCallback(NoOp.INSTANCE);
175: enhancer.setInterfaces(new Class[] { Runnable.class });
176: enhancer.setSerialVersionUID(new Long(20060804L));
177: final Runnable orig = (Runnable) enhancer.create();
178: final String xml = "" + "<CGLIB-enhanced-proxy>\n"
179: + " <type>java.lang.Object</type>\n"
180: + " <interfaces>\n"
181: + " <java-class>java.lang.Runnable</java-class>\n"
182: + " </interfaces>\n"
183: + " <hasFactory>false</hasFactory>\n"
184: + " <net.sf.cglib.proxy.NoOp_-1/>\n"
185: + " <serialVersionUID>20060804</serialVersionUID>\n"
186: + "</CGLIB-enhanced-proxy>";
187:
188: final Object serialized = assertBothWays(orig, xml);
189: final Field field = serialized.getClass().getDeclaredField(
190: "serialVersionUID");
191: field.setAccessible(true);
192: assertEquals(20060804L, field.getLong(null));
193: }
194:
195: public static class InterceptingHandler implements
196: MethodInterceptor {
197:
198: public Object intercept(Object obj, Method method,
199: Object[] args, MethodProxy proxy) throws Throwable {
200: return proxy.invokeSuper(obj, args);
201: }
202: }
203:
204: private final static String THRESHOLD_PARAM = "$THRESHOLD$";
205: private final static String CAPACITY_PARAM = "$CAPACITY$";
206:
207: public void testSupportsInterceptedClassBasedProxies()
208: throws NullPointerException, MalformedURLException {
209: final Enhancer enhancer = new Enhancer();
210: enhancer.setSuperclass(HashMap.class);
211: enhancer.setCallback(new InterceptingHandler());
212: enhancer.setUseFactory(false);
213: final Map orig = (Map) enhancer.create();
214: orig.put("URL", new URL("http://xstream.codehaus.org"));
215: final StringBuffer xml = new StringBuffer(
216: ""
217: + "<CGLIB-enhanced-proxy>\n"
218: + " <type>java.util.HashMap</type>\n"
219: + " <interfaces/>\n"
220: + " <hasFactory>false</hasFactory>\n"
221: + " <com.thoughtworks.acceptance.CglibCompatibilityTest_-InterceptingHandler/>\n"
222: + " <instance serialization=\"custom\">\n"
223: + " <unserializable-parents/>\n"
224: + " <map>\n"
225: + " <default>\n"
226: + " <loadFactor>0.75</loadFactor>\n"
227: + " <threshold>$THRESHOLD$</threshold>\n"
228: + " </default>\n"
229: + " <int>$CAPACITY$</int>\n"
230: + " <int>1</int>\n"
231: + " <string>URL</string>\n"
232: + " <url>http://xstream.codehaus.org</url>\n"
233: + " </map>\n" + " </instance>\n"
234: + "</CGLIB-enhanced-proxy>");
235:
236: // JDK 1.3 has different threshold and capacity algorithms
237: int idx = xml.toString().indexOf(THRESHOLD_PARAM);
238: xml.replace(idx, idx + THRESHOLD_PARAM.length(),
239: JVM.is14() ? "12" : "8");
240: idx = xml.toString().indexOf(CAPACITY_PARAM);
241: xml.replace(idx, idx + CAPACITY_PARAM.length(),
242: JVM.is14() ? "16" : "11");
243:
244: Map serialized = (Map) assertBothWays(orig, xml.toString());
245: assertEquals(orig.toString(), serialized.toString());
246: }
247:
248: public static class ClassWithProxyMember {
249: Runnable runnable;
250: Map map;
251: };
252:
253: public void testSupportsProxiesAsFieldMember()
254: throws NullPointerException {
255: ClassWithProxyMember expected = new ClassWithProxyMember();
256: xstream.alias("with-proxy", ClassWithProxyMember.class);
257: final Enhancer enhancer = new Enhancer();
258: enhancer.setCallback(NoOp.INSTANCE);
259: enhancer
260: .setInterfaces(new Class[] { Map.class, Runnable.class });
261: enhancer.setUseFactory(true);
262: final Map orig = (Map) enhancer.create();
263: expected.runnable = (Runnable) orig;
264: expected.map = orig;
265: final String xml = ""
266: + "<with-proxy>\n"
267: + " <runnable class=\"CGLIB-enhanced-proxy\">\n"
268: + " <type>java.lang.Object</type>\n"
269: + " <interfaces>\n"
270: + " <java-class>java.util.Map</java-class>\n"
271: + " <java-class>java.lang.Runnable</java-class>\n"
272: + " </interfaces>\n"
273: + " <hasFactory>false</hasFactory>\n"
274: + " <net.sf.cglib.proxy.NoOp_-1/>\n"
275: + " </runnable>\n"
276: + " <map class=\"CGLIB-enhanced-proxy\" reference=\"../runnable\"/>\n"
277: + "</with-proxy>";
278:
279: final Object serialized = assertBothWays(expected, xml);
280: assertTrue(serialized instanceof ClassWithProxyMember);
281: }
282:
283: public void testProxyTypeCanBeAliased()
284: throws MalformedURLException {
285: final Enhancer enhancer = new Enhancer();
286: enhancer.setSuperclass(HashMap.class);
287: enhancer.setCallback(new DelegatingHandler(new HashMap()));
288: enhancer.setUseFactory(true); // true by default
289: final Map orig = (Map) enhancer.create();
290: orig.put("URL", new URL("http://xstream.codehaus.org"));
291: xstream.aliasType("cglib", Map.class);
292: final String expected = ""
293: + "<cglib>\n"
294: + " <type>java.util.HashMap</type>\n"
295: + " <interfaces/>\n"
296: + " <hasFactory>true</hasFactory>\n"
297: + " <com.thoughtworks.acceptance.CglibCompatibilityTest_-DelegatingHandler>\n"
298: + " <delegate class=\"map\">\n"
299: + " <entry>\n"
300: + " <string>URL</string>\n"
301: + " <url>http://xstream.codehaus.org</url>\n"
302: + " </entry>\n"
303: + " </delegate>\n"
304: + " </com.thoughtworks.acceptance.CglibCompatibilityTest_-DelegatingHandler>\n"
305: + "</cglib>";
306: assertEquals(expected, xstream.toXML(orig));
307: }
308: }
|