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