1 package com.atlassian.plugin.util;
2
3 import junit.framework.TestCase;
4
5 import java.io.IOException;
6 import java.io.Serializable;
7 import java.net.URL;
8 import java.net.URLClassLoader;
9 import java.util.*;
10
11 import static com.google.common.collect.Sets.newHashSet;
12 import static java.util.Arrays.asList;
13 import static java.util.Collections.singletonList;
14 import static org.mockito.Mockito.mock;
15
16
17
18
19 public class TestClassUtils extends TestCase
20 {
21 public void testFindAllTypes()
22 {
23 assertEquals(newHashSet(
24 List.class,
25 AbstractList.class,
26 Cloneable.class,
27 RandomAccess.class,
28 AbstractCollection.class,
29 Iterable.class,
30 Collection.class,
31 ArrayList.class,
32 Object.class,
33 Serializable.class
34 ), ClassUtils.findAllTypes(ArrayList.class));
35 }
36
37 public void testGetTypeArguments()
38 {
39 assertEquals(asList(String.class), ClassUtils.getTypeArguments(BaseClass.class, Child.class));
40
41 assertEquals(asList(String.class), ClassUtils.getTypeArguments(BaseClass.class, Baby.class));
42
43 assertEquals(singletonList(null), ClassUtils.getTypeArguments(BaseClass.class, ForgotType.class));
44 }
45
46 public void testGetTypeArgumentsDifferentClassloader() throws Exception
47 {
48 ClassLoader cl = Thread.currentThread().getContextClassLoader();
49 try
50 {
51 URL log4jUrl = getClass().getClassLoader().getResource("log4j.properties");
52 URL root = new URL(new URL(log4jUrl.toExternalForm()), ".");
53
54 URLClassLoader urlCl = new URLClassLoader(new URL[] {root}, new FilteredClassLoader(MySuperClass.class));
55 ClosableClassLoader wrapCl = new ClosableClassLoader(getClass().getClassLoader());
56
57 Thread.currentThread().setContextClassLoader(null);
58 Class<?> module = ClassUtils.getTypeArguments((Class<Object>) urlCl.loadClass(MySuperClass.class.getName()),
59 (Class<? extends MySuperClass>) urlCl.loadClass(MySubClass.class.getName())).get(0);
60 assertEquals(MyModule.class.getName(), module.getName());
61
62 ClassLoader urlCl2 = new URLClassLoader(new URL[] {root}, new FilteredClassLoader(MySuperClass.class));
63 assertTrue(wrapCl.loadClass(MySuperClass.class.getName()) == urlCl2.loadClass(MySuperClass.class.getName()));
64 assertTrue(wrapCl.loadClass(MySubClass.class.getName()) != urlCl2.loadClass(MySubClass.class.getName()));
65 assertTrue(wrapCl.loadClass(MySubClass.class.getName()).getSuperclass() == urlCl2.loadClass(MySubClass.class.getName()).getSuperclass());
66
67 wrapCl.setClosed(true);
68
69 Class<?> module2 = ClassUtils.getTypeArguments((Class<Object>) urlCl2.loadClass(MySuperClass.class.getName()),
70 (Class<? extends MySuperClass>) urlCl2.loadClass(MySubClass.class.getName())).get(0);
71 assertEquals(MyModule.class.getName(), module2.getName());
72 assertTrue(module != module2);
73 assertTrue(module != MyModule.class);
74 assertTrue(module2 != MyModule.class);
75 }
76 finally
77 {
78 Thread.currentThread().setContextClassLoader(cl);
79 }
80 }
81
82 public void testGetTypeArgumentsChildNotSubclass()
83 {
84 Class fakeChild = BaseClass.class;
85 try
86 {
87 assertEquals(singletonList(null), ClassUtils.getTypeArguments(Baby.class, (Class<? extends Baby>) fakeChild));
88 fail("Should have failed");
89 }
90 catch (IllegalArgumentException ex)
91 {
92
93 }
94 }
95
96 private static class BaseClass<T> {}
97 private static class Child extends BaseClass<String>{}
98 private static class ForgotType extends BaseClass{}
99
100 private static class Mom<T> extends BaseClass<T>{}
101 private static class Baby extends Mom<String>{}
102
103 private static class ClosableClassLoader extends ClassLoader
104 {
105 private final ClassLoader delegate;
106 private volatile boolean closed;
107
108 public ClosableClassLoader(ClassLoader delegate)
109 {
110 super(null);
111 this.delegate = delegate;
112 }
113
114 @Override
115 public Class<?> loadClass(String name)
116 throws ClassNotFoundException
117 {
118 checkClosed();
119 return delegate.loadClass(name);
120 }
121 @Override
122 public Class<?> loadClass(String name, boolean resolve)
123 throws ClassNotFoundException
124 {
125 checkClosed();
126 return delegate.loadClass(name);
127 }
128
129 private void checkClosed()
130 {
131 if (closed)
132 {
133 throw new IllegalStateException("Closed");
134 }
135 }
136
137 @Override
138 public URL getResource(String name)
139 {
140 checkClosed();
141 return delegate.getResource(name);
142 }
143
144 @Override
145 public Enumeration<URL> getResources(String name)
146 throws IOException
147 {
148 checkClosed();
149 return delegate.getResources(name);
150 }
151
152 public void setClosed(boolean closed)
153 {
154 this.closed = closed;
155 }
156 }
157
158 private static class FilteredClassLoader extends ClassLoader
159 {
160 private final Collection<Class> classes;
161
162 public FilteredClassLoader(Class... classes)
163 {
164 super(null);
165 this.classes = asList(classes);
166 }
167
168 @Override
169 public Class<?> loadClass(String name, boolean resolve)
170 throws ClassNotFoundException
171 {
172 for (Class cls : classes)
173 {
174 if (cls.getName().equals(name))
175 {
176 return cls;
177 }
178 }
179 if (name.startsWith("java."))
180 {
181 return ClassLoader.getSystemClassLoader().loadClass(name);
182 }
183 throw new ClassNotFoundException(name);
184 }
185 }
186 }