View Javadoc
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              //Thread.currentThread().setContextClassLoader(urlCl2);
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              // this is good
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 }