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.AbstractCollection;
10 import java.util.AbstractList;
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.Enumeration;
14 import java.util.List;
15 import java.util.RandomAccess;
16
17 import static com.google.common.collect.Sets.newHashSet;
18 import static java.util.Arrays.asList;
19 import static java.util.Collections.singletonList;
20
21
22
23
24 public class TestClassUtils extends TestCase {
25 public void testFindAllTypes() {
26 assertEquals(newHashSet(
27 List.class,
28 AbstractList.class,
29 Cloneable.class,
30 RandomAccess.class,
31 AbstractCollection.class,
32 Iterable.class,
33 Collection.class,
34 ArrayList.class,
35 Object.class,
36 Serializable.class
37 ), ClassUtils.findAllTypes(ArrayList.class));
38 }
39
40 public void testGetTypeArguments() {
41 assertEquals(asList(String.class), ClassUtils.getTypeArguments(BaseClass.class, Child.class));
42
43 assertEquals(asList(String.class), ClassUtils.getTypeArguments(BaseClass.class, Baby.class));
44
45 assertEquals(singletonList(null), ClassUtils.getTypeArguments(BaseClass.class, ForgotType.class));
46 }
47
48 public void testGetTypeArgumentsDifferentClassloader() throws Exception {
49 ClassLoader cl = Thread.currentThread().getContextClassLoader();
50 try {
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 } finally {
76 Thread.currentThread().setContextClassLoader(cl);
77 }
78 }
79
80 public void testGetTypeArgumentsChildNotSubclass() {
81 Class fakeChild = BaseClass.class;
82 try {
83 assertEquals(singletonList(null), ClassUtils.getTypeArguments(Baby.class, (Class<? extends Baby>) fakeChild));
84 fail("Should have failed");
85 } catch (IllegalArgumentException ex) {
86
87 }
88 }
89
90 private static class BaseClass<T> {
91 }
92
93 private static class Child extends BaseClass<String> {
94 }
95
96 private static class ForgotType extends BaseClass {
97 }
98
99 private static class Mom<T> extends BaseClass<T> {
100 }
101
102 private static class Baby extends Mom<String> {
103 }
104
105 private static class ClosableClassLoader extends ClassLoader {
106 private final ClassLoader delegate;
107 private volatile boolean closed;
108
109 public ClosableClassLoader(ClassLoader delegate) {
110 super(null);
111 this.delegate = delegate;
112 }
113
114 @Override
115 public Class<?> loadClass(String name)
116 throws ClassNotFoundException {
117 checkClosed();
118 return delegate.loadClass(name);
119 }
120
121 @Override
122 public Class<?> loadClass(String name, boolean resolve)
123 throws ClassNotFoundException {
124 checkClosed();
125 return delegate.loadClass(name);
126 }
127
128 private void checkClosed() {
129 if (closed) {
130 throw new IllegalStateException("Closed");
131 }
132 }
133
134 @Override
135 public URL getResource(String name) {
136 checkClosed();
137 return delegate.getResource(name);
138 }
139
140 @Override
141 public Enumeration<URL> getResources(String name)
142 throws IOException {
143 checkClosed();
144 return delegate.getResources(name);
145 }
146
147 public void setClosed(boolean closed) {
148 this.closed = closed;
149 }
150 }
151
152 private static class FilteredClassLoader extends ClassLoader {
153 private final Collection<Class> classes;
154
155 public FilteredClassLoader(Class... classes) {
156 super(null);
157 this.classes = asList(classes);
158 }
159
160 @Override
161 public Class<?> loadClass(String name, boolean resolve)
162 throws ClassNotFoundException {
163 for (Class cls : classes) {
164 if (cls.getName().equals(name)) {
165 return cls;
166 }
167 }
168 if (name.startsWith("java.")) {
169 return ClassLoader.getSystemClassLoader().loadClass(name);
170 }
171 throw new ClassNotFoundException(name);
172 }
173 }
174 }