aboutsummaryrefslogtreecommitdiffstats
path: root/weaver5/java5-testsrc/org/aspectj/weaver/reflect/ReflectionWorldTest.java
blob: 1108ca13c32a80c849c5872e9d6ce2b27b64263d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
/* *******************************************************************
 * Copyright (c) 2005,2017 Contributors.
 * All rights reserved. 
 * This program and the accompanying materials are made available 
 * under the terms of the Eclipse Public License v1.0 
 * which accompanies this distribution and is available at 
 * http://eclipse.org/legal/epl-v10.html 
 * ******************************************************************/
package org.aspectj.weaver.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
import java.util.Map;

import org.aspectj.bridge.IMessageHandler;
import org.aspectj.weaver.ReferenceType;
import org.aspectj.weaver.ResolvedMember;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.WeakClassLoaderReference;
import org.aspectj.weaver.World;
import org.aspectj.weaver.bcel.BcelWorld;

import junit.framework.TestCase;

/**
 * @author Andy Clement
 * @author Adrian Colyer
 */
public class ReflectionWorldTest extends TestCase {

	public void testDelegateCreation() {
		World world = new ReflectionWorld(getClass().getClassLoader());
		ResolvedType rt = world.resolve("java.lang.Object");
		assertNotNull(rt);
		assertEquals("Ljava/lang/Object;", rt.getSignature());
	}
	
	// Removed for now. In Spring the reflection worlds are customized by introducing new
	// PCD handlers. It means more thought needs to be put into reusing worlds.
	public void xtestReflectionWorldFactory() throws Exception {
		ClassLoader parent = getClass().getClassLoader();
		ClassLoader cl1 = new URLClassLoader(new URL[] {}, parent);
		ClassLoader cl2 = new URLClassLoader(new URL[] {}, parent);

		WeakClassLoaderReference wcl1 = new WeakClassLoaderReference(cl1);
		WeakClassLoaderReference wcl2 = new WeakClassLoaderReference(cl2);
		ReflectionWorld a = ReflectionWorld.getReflectionWorldFor(wcl1);

		ResolvedType stringClass1 = a.resolve(String.class);
		assertNotNull(stringClass1);
		
		ReflectionWorld b = ReflectionWorld.getReflectionWorldFor(wcl1);
		
		// They should be the same because the classloader has not gone away
		assertTrue(a==b);
		
		cl1 = null;
		for (int i=0;i<100;i++) {
			System.gc(); // How robust is it that this should be causing the reference to be collected?
		}
		b = ReflectionWorld.getReflectionWorldFor(wcl1);
		
		assertFalse(a==b);
		
		cl1 = new URLClassLoader(new URL[] {}, parent);
		wcl1 = new WeakClassLoaderReference(cl1);
		a = ReflectionWorld.getReflectionWorldFor(wcl1);
		b = ReflectionWorld.getReflectionWorldFor(wcl2);
		assertFalse(a==b);
		
		Field declaredField = ReflectionWorld.class.getDeclaredField("rworlds");
		declaredField.setAccessible(true);
		Map worlds = (Map)declaredField.get(null);
		assertEquals(2, worlds.size());
		
		cl2 = null;
		for (int i=0;i<100;i++) {
			System.gc(); // How robust is it that this should be causing the reference to be collected?
		}
		ReflectionWorld.getReflectionWorldFor(wcl1); // need to call this to trigger tidyup
		assertEquals(1, worlds.size());

		cl1 = null;
		for (int i=0;i<100;i++) {
			System.gc(); // How robust is it that this should be causing the reference to be collected?
		}
		ReflectionWorld.getReflectionWorldFor(wcl1); // need to call this to trigger tidyup
		assertEquals(0, worlds.size());
		
		cl1 = new URLClassLoader(new URL[] {}, parent);
		wcl1 = new WeakClassLoaderReference(cl1);
		ReflectionWorld reflectionWorldFor = ReflectionWorld.getReflectionWorldFor(wcl1);
		assertEquals(1, worlds.size());
		ReflectionWorld.cleanUpWorlds();		
		assertEquals(0, worlds.size());
	}

	public void testArrayTypes() {
		IReflectionWorld world = new ReflectionWorld(getClass().getClassLoader());
		String[] strArray = new String[1];
		ResolvedType rt = world.resolve(strArray.getClass());
		assertTrue(rt.isArray());
	}

	public void testPrimitiveTypes() {
		IReflectionWorld world = new ReflectionWorld(getClass().getClassLoader());
		assertEquals("int", UnresolvedType.INT, world.resolve(int.class));
		assertEquals("void", UnresolvedType.VOID, world.resolve(void.class));
	}
	
	static class AbstractSuperClass<A,B> {}
	static interface InterfaceOne {}
	static interface InterfaceTwo<A> {}
	static class ID {}
	static abstract class AbstractTestClass<T> extends AbstractSuperClass<T,ID> implements InterfaceOne, InterfaceTwo<T> {

	}
	static class TestType {}
//	static class ConcreteClass extends AbstractTestClass<TestType> {
	static class ConcreteClass extends AbstractTestClass<List<TestType>> {
	}
	
	static class Bar extends ConcreteClass {}
	
	public void testGenerics() {
		ReflectionWorld world = new ReflectionWorld(getClass().getClassLoader());
//		world.lookupOrCreateName(UnresolvedType.forName(AbstractTestClass.class.getName()));
//		ResolvedType resolvedType = world.resolve(AbstractTestClass.class);
		JavaLangTypeToResolvedTypeConverter converter = new JavaLangTypeToResolvedTypeConverter(world);
		ResolvedType resolvedType2 = converter.fromType(ConcreteClass.class);
	}

	public void testTypeConversions_509327() throws Exception {
		ReflectionWorld rWorld = new ReflectionWorld(getClass().getClassLoader());
		JavaLangTypeToResolvedTypeConverter converter = new JavaLangTypeToResolvedTypeConverter(rWorld);

		// Check basic conversion of String to String
		Method method = TestClass.class.getDeclaredMethod("m");
		Type stringType = method.getGenericReturnType();
		assertEquals("java.lang.String",stringType.getTypeName());
		ResolvedType stringResolvedType = converter.fromType(stringType);
		assertEquals("java.lang.String",stringResolvedType.getName());
		
		// public String m() { return ""; }
		method = TestClass2.class.getDeclaredMethod("m");
		stringType = method.getGenericReturnType();
		assertEquals("java.lang.String",stringType.getTypeName());
		stringResolvedType = converter.fromType(stringType);
		assertEquals("java.lang.String",stringResolvedType.getName());
		
		// Verify that the conversion process creates the same thing as the bcel unpacking

		// Here the return type is a non-static inner of a generic class
		// public Inner m2() { return null; }
		method = TestClass2.class.getDeclaredMethod("m2");
		Type innerType = method.getGenericReturnType();
		assertEquals("org.aspectj.weaver.reflect.ReflectionWorldTest.org.aspectj.weaver.reflect.ReflectionWorldTest$TestClass2<T>.Inner",innerType.getTypeName());
		ResolvedType rType_Inner = converter.fromType(innerType);
		assertEquals("Lorg/aspectj/weaver/reflect/ReflectionWorldTest$TestClass2$Inner;",rType_Inner.getSignature());
		assertEquals(UnresolvedType.TypeKind.SIMPLE,rType_Inner.getTypekind());
		ResolvedType rType_Outer = rType_Inner.getOuterClass();
		assertEquals("Lorg/aspectj/weaver/reflect/ReflectionWorldTest$TestClass2;",rType_Outer.getSignature());
		
		BcelWorld bWorld = new BcelWorld(getClass().getClassLoader(), IMessageHandler.THROW, null);
		bWorld.setBehaveInJava5Way(true);
		UnresolvedType javaUtilHashMap = UnresolvedType.forName("java.util.HashMap");
		ReferenceType rawType = (ReferenceType) bWorld.resolve(javaUtilHashMap);
		assertNotNull(rawType);
		
		// Now use bcel to resolve the same m2 method, and compare the signatures of the return types
		ResolvedType bResolved_TestClass2 = bWorld.resolve(UnresolvedType.forName(TestClass2.class.getName()));
		assertNotNull(bResolved_TestClass2);
		ResolvedMember bMethod_m2 = findMethod(bResolved_TestClass2,"m2");
		ResolvedType bType_Inner = (ResolvedType) bMethod_m2.getReturnType();
		assertEquals("Lorg/aspectj/weaver/reflect/ReflectionWorldTest$TestClass2$Inner;",bType_Inner.getSignature());
		assertEquals(UnresolvedType.TypeKind.SIMPLE,bType_Inner.getTypekind());
		ResolvedType bType_Outer = bType_Inner.getOuterClass();
		assertEquals("Lorg/aspectj/weaver/reflect/ReflectionWorldTest$TestClass2;",bType_Outer.getSignature());

		assertEquals(bType_Inner.getSignature(),rType_Inner.getSignature());
		assertEquals(bType_Outer.getSignature(),rType_Outer.getSignature());
	}
	

	public void testTypeConversions_509327_2() throws Exception {
		ReflectionWorld world = new ReflectionWorld(getClass().getClassLoader());
		JavaLangTypeToResolvedTypeConverter converter = new JavaLangTypeToResolvedTypeConverter(world);
		BcelWorld bWorld = new BcelWorld(getClass().getClassLoader(), IMessageHandler.THROW, null);
		bWorld.setBehaveInJava5Way(true);
		
		// Slightly more advanced, now the method is returning a parameterized form of the outer
		// generic class
		
		// public TestClass2<String>.Inner m3() { return new TestClass2<String>.Inner("Foo"); }
		Method method = TestClass2.class.getDeclaredMethod("m3");
		Type type_ParameterizedInner = method.getGenericReturnType();
		assertEquals("org.aspectj.weaver.reflect.ReflectionWorldTest.org.aspectj.weaver.reflect.ReflectionWorldTest$TestClass2<java.lang.String>.Inner",type_ParameterizedInner.getTypeName());
		ResolvedType rType_ParameterizedInner = converter.fromType(type_ParameterizedInner);
		// NOTE: DECLARED PARAMETERIZATION OF OUTER IS LOST
		assertEquals("Lorg/aspectj/weaver/reflect/ReflectionWorldTest$TestClass2$Inner;",rType_ParameterizedInner.getSignature());

		ResolvedType bResolved_TestClass2 = bWorld.resolve(UnresolvedType.forName(TestClass2.class.getName()));
		assertNotNull(bResolved_TestClass2);
		ResolvedMember bMethod_m3 = findMethod(bResolved_TestClass2,"m3");
		ResolvedType bType_Inner = (ResolvedType) bMethod_m3.getReturnType();
		// NOTE: DECLARED PARAMETERIZATION OF OUTER IS LOST
		assertEquals("Lorg/aspectj/weaver/reflect/ReflectionWorldTest$TestClass2$Inner;",bType_Inner.getSignature());

		assertEquals(UnresolvedType.TypeKind.SIMPLE,bType_Inner.getTypekind());
		ResolvedType bType_Outer = bType_Inner.getOuterClass();
			
		// Fields seem to lose it too, although the backinggenericmember has the info
//		ResolvedMember bField_f = findField(bResolved_TestClass2,"f");
//		ResolvedMember backingGenericMember = bField_f.getBackingGenericMember();
//		System.out.println(backingGenericMember);
//		System.out.println(backingGenericMember.getGenericReturnType());
//		System.out.println(bField_f);
//		System.out.println(bField_f.getSignature());
//		System.out.println(bField_f.getGenericReturnType());
	}
	
//	public void testbar() throws Exception {
//		ReflectionWorld world = new ReflectionWorld(getClass().getClassLoader());
//		JavaLangTypeToResolvedTypeConverter converter = new JavaLangTypeToResolvedTypeConverter(world);
//		
//		// public TestClass2<String>.Inner m3() { return new TestClass2<String>.Inner("Foo"); }
//		Method method = TestClass2.class.getDeclaredMethod("m3");
//		Type type_ParameterizedInner = method.getGenericReturnType();
//		assertEquals("org.aspectj.weaver.reflect.ReflectionWorldTest.org.aspectj.weaver.reflect.ReflectionWorldTest$TestClass2<java.lang.String>.Inner",type_ParameterizedInner.getTypeName());
//		ResolvedType rType_ParameterizedInner = converter.fromType(type_ParameterizedInner);
//		System.out.println(rType_ParameterizedInner);	
//		System.out.println(type_ParameterizedInner.getTypeName());
//	}
//	
//	public void testfoo() {
//		ReflectionWorld world = new ReflectionWorld(getClass().getClassLoader());
//		JavaLangTypeToResolvedTypeConverter converter = new JavaLangTypeToResolvedTypeConverter(world);
//		BcelWorld bWorld = new BcelWorld(getClass().getClassLoader(), IMessageHandler.THROW, null);
//		bWorld.setBehaveInJava5Way(true);
//		
//
//		ResolvedType bResolved_TestClass2 = bWorld.resolve(UnresolvedType.forName(TestClass2.class.getName()));
//		ResolvedMember bField_f = findField(bResolved_TestClass2,"f");		
//		System.out.println(bField_f);
//		System.out.println(bField_f.getGenericReturnType());
//		System.out.println(bField_f.getReturnType());
//		System.out.println(bField_f.getBackingGenericMember().getGenericReturnType());
//	}

	static class TestClass {
		public String m() { return ""; }
	}
	
	static class TestClass2<T> {
		class Inner {
			T t;
			Inner(T t) {
				this.t = t;
			}
		}
		public String m() { return ""; }
		public Inner m2() { return null; }
		public TestClass2<String> f;
		public TestClass2<String>.Inner m3() { return new TestClass2<String>.Inner("Foo"); }
	}

	private ResolvedMember findMethod(ResolvedType resolvedType, String methodName) {
		for (ResolvedMember method: resolvedType.getDeclaredMethods()) {
			if (method.getName().equals(methodName)) {
				return method;
			}
		}
		return null;
	}
	
	private ResolvedMember findField(ResolvedType resolvedType, String fieldName) {
		for (ResolvedMember field: resolvedType.getDeclaredFields()) {
			if (field.getName().equals(fieldName)) {
				return field;
			}
		}
		return null;
	}

}