Skip to content

Commit b43e23a

Browse files
committed
Merge pull request #854 from lufe66/master
issue #624 - adding possibility of using provided ClassLoader on TypeFactory
2 parents 3781142 + 55c5d1a commit b43e23a

3 files changed

Lines changed: 204 additions & 12 deletions

File tree

pom.xml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,19 @@ javax.xml.datatype, javax.xml.namespace, javax.xml.parsers
8080
<!-- and for testing we need a few libraries
8181
libs for which we use reflection for code, but direct dep for testing
8282
-->
83-
83+
<!-- Mock -->
84+
<dependency>
85+
<groupId>org.powermock</groupId>
86+
<artifactId>powermock-module-junit4</artifactId>
87+
<version>1.6.2</version>
88+
<scope>test</scope>
89+
</dependency>
90+
<dependency>
91+
<groupId>org.powermock</groupId>
92+
<artifactId>powermock-api-mockito</artifactId>
93+
<version>1.6.2</version>
94+
<scope>test</scope>
95+
</dependency>
8496
<!-- For testing TestNoClassDefFoundDeserializer -->
8597
<dependency>
8698
<groupId>javax.measure</groupId>

src/main/java/com/fasterxml/jackson/databind/type/TypeFactory.java

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ public final class TypeFactory
9898
protected final TypeModifier[] _modifiers;
9999

100100
protected final TypeParser _parser;
101+
102+
/**
103+
* ClassLoader used by this factory (Issue #624)
104+
*/
105+
protected final ClassLoader _classLoader;
101106

102107
/*
103108
/**********************************************************
@@ -108,22 +113,32 @@ public final class TypeFactory
108113
private TypeFactory() {
109114
_parser = new TypeParser(this);
110115
_modifiers = null;
116+
_classLoader = null;
111117
}
112118

113119
protected TypeFactory(TypeParser p, TypeModifier[] mods) {
120+
this(p, mods, null);
121+
}
122+
123+
protected TypeFactory(TypeParser p, TypeModifier[] mods, ClassLoader classLoader) {
114124
_parser = p;
115125
_modifiers = mods;
126+
_classLoader = classLoader;
116127
}
117128

118129
public TypeFactory withModifier(TypeModifier mod)
119130
{
120-
if (mod == null) { // mostly for unit tests
121-
return new TypeFactory(_parser, _modifiers);
122-
}
123-
if (_modifiers == null) {
124-
return new TypeFactory(_parser, new TypeModifier[] { mod });
125-
}
126-
return new TypeFactory(_parser, ArrayBuilders.insertInListNoDup(_modifiers, mod));
131+
if (mod == null) { // mostly for unit tests
132+
return new TypeFactory(_parser, _modifiers, _classLoader);
133+
}
134+
if (_modifiers == null) {
135+
return new TypeFactory(_parser, new TypeModifier[] { mod }, _classLoader);
136+
}
137+
return new TypeFactory(_parser, ArrayBuilders.insertInListNoDup(_modifiers, mod), _classLoader);
138+
}
139+
140+
public TypeFactory withClassLoader(ClassLoader classLoader) {
141+
return new TypeFactory(_parser, _modifiers, classLoader);
127142
}
128143

129144
/**
@@ -147,6 +162,13 @@ public void clearCache() {
147162
_typeCache.clear();
148163
}
149164

165+
/*
166+
* Getters
167+
*/
168+
public ClassLoader getClassLoader() {
169+
return _classLoader;
170+
}
171+
150172
/*
151173
/**********************************************************
152174
/* Static methods for non-instance-specific functionality
@@ -198,17 +220,19 @@ public Class<?> findClass(String className) throws ClassNotFoundException
198220
}
199221
// Two-phase lookup: first using context ClassLoader; then default
200222
Throwable prob = null;
201-
ClassLoader loader = Thread.currentThread().getContextClassLoader();
202-
223+
ClassLoader loader = this.getClassLoader();
224+
if (loader == null) {
225+
loader = Thread.currentThread().getContextClassLoader();
226+
}
203227
if (loader != null) {
204228
try {
205-
return Class.forName(className, true, loader);
229+
return classForName(className, true, loader);
206230
} catch (Exception e) {
207231
prob = ClassUtil.getRootCause(e);
208232
}
209233
}
210234
try {
211-
return Class.forName(className);
235+
return classForName(className);
212236
} catch (Exception e) {
213237
if (prob == null) {
214238
prob = ClassUtil.getRootCause(e);
@@ -219,6 +243,15 @@ public Class<?> findClass(String className) throws ClassNotFoundException
219243
}
220244
throw new ClassNotFoundException(prob.getMessage(), prob);
221245
}
246+
247+
protected Class<?> classForName(String name, boolean initialize,
248+
ClassLoader loader) throws ClassNotFoundException {
249+
return Class.forName(name, true, loader);
250+
}
251+
252+
protected Class<?> classForName(String name) throws ClassNotFoundException {
253+
return Class.forName(name);
254+
}
222255

223256
protected Class<?> _findPrimitive(String className)
224257
{
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
package com.fasterxml.jackson.databind.type;
2+
3+
import static org.mockito.Mockito.*;
4+
5+
import org.junit.Test;
6+
import org.junit.runner.RunWith;
7+
import org.mockito.Mock;
8+
import org.powermock.core.classloader.annotations.PrepareForTest;
9+
import org.powermock.modules.junit4.PowerMockRunner;
10+
11+
import com.fasterxml.jackson.databind.ObjectMapper;
12+
13+
import org.junit.After;
14+
import org.junit.Assert;
15+
import org.junit.Before;
16+
import org.junit.BeforeClass;
17+
18+
@RunWith(PowerMockRunner.class)
19+
@PrepareForTest(TypeFactory.class)
20+
21+
public class TestTypeFactoryWithClassLoader {
22+
@Mock
23+
private TypeModifier typeModifier;
24+
private static ClassLoader classLoader;
25+
private static ClassLoader threadClassLoader;
26+
private static String aClassName;
27+
private ObjectMapper objectMapper;
28+
29+
@BeforeClass
30+
public static void beforeClass() {
31+
classLoader = AClass.class.getClassLoader();
32+
aClassName = AClass.getStaticClassName();
33+
threadClassLoader = Thread.currentThread().getContextClassLoader();
34+
Assert.assertNotNull(threadClassLoader);
35+
}
36+
37+
@Before
38+
public void before() {
39+
objectMapper = new ObjectMapper();
40+
}
41+
42+
@After
43+
public void after() {
44+
Thread.currentThread().setContextClassLoader(threadClassLoader);
45+
objectMapper = null;
46+
}
47+
48+
@Test
49+
public void testUsesCorrectClassLoaderWhenThreadClassLoaderIsNull() throws ClassNotFoundException {
50+
Thread.currentThread().setContextClassLoader(null);
51+
TypeFactory spySut = spy(objectMapper.getTypeFactory().withModifier(typeModifier).withClassLoader(classLoader));
52+
Class<?> clazz = spySut.findClass(aClassName);
53+
verify(spySut).getClassLoader();
54+
verify(spySut).classForName(any(String.class), any(Boolean.class), eq(classLoader));
55+
Assert.assertNotNull(clazz);
56+
Assert.assertEquals(classLoader, spySut.getClassLoader());
57+
Assert.assertEquals(typeModifier,spySut._modifiers[0]);
58+
Assert.assertEquals(null, Thread.currentThread().getContextClassLoader());
59+
}
60+
61+
@Test
62+
public void testUsesCorrectClassLoaderWhenThreadClassLoaderIsNotNull() throws ClassNotFoundException {
63+
TypeFactory spySut = spy(objectMapper.getTypeFactory().withModifier(typeModifier).withClassLoader(classLoader));
64+
Class<?> clazz = spySut.findClass(aClassName);
65+
verify(spySut).getClassLoader();
66+
verify(spySut).classForName(any(String.class), any(Boolean.class), eq(classLoader));
67+
Assert.assertNotNull(clazz);
68+
Assert.assertEquals(classLoader, spySut.getClassLoader());
69+
Assert.assertEquals(typeModifier,spySut._modifiers[0]);
70+
}
71+
72+
@Test
73+
public void testCallingOnlyWithModifierGivesExpectedResults(){
74+
TypeFactory sut = objectMapper.getTypeFactory().withModifier(typeModifier);
75+
Assert.assertNull(sut.getClassLoader());
76+
Assert.assertEquals(typeModifier,sut._modifiers[0]);
77+
}
78+
79+
@Test
80+
public void testCallingOnlyWithClassLoaderGivesExpectedResults(){
81+
TypeFactory sut = objectMapper.getTypeFactory().withClassLoader(classLoader);
82+
Assert.assertNotNull(sut.getClassLoader());
83+
Assert.assertArrayEquals(null,sut._modifiers);
84+
}
85+
86+
@Test
87+
public void testDefaultTypeFactoryNotAffectedByWithConstructors() {
88+
TypeFactory sut = objectMapper.getTypeFactory().withModifier(typeModifier).withClassLoader(classLoader);
89+
Assert.assertEquals(classLoader, sut.getClassLoader());
90+
Assert.assertEquals(typeModifier,sut._modifiers[0]);
91+
Assert.assertNull(objectMapper.getTypeFactory().getClassLoader());
92+
Assert.assertArrayEquals(null,objectMapper.getTypeFactory()._modifiers);
93+
}
94+
95+
@Test
96+
public void testSetsTheCorrectClassLoderIfUsingWithModifierFollowedByWithClassLoader() {
97+
TypeFactory sut = objectMapper.getTypeFactory().withModifier(typeModifier).withClassLoader(classLoader);
98+
Assert.assertNotNull(sut.getClassLoader());
99+
}
100+
101+
@Test
102+
public void testSetsTheCorrectClassLoderIfUsingWithClassLoaderFollowedByWithModifier() {
103+
TypeFactory sut = objectMapper.getTypeFactory().withClassLoader(classLoader).withModifier(typeModifier);
104+
Assert.assertNotNull(sut.getClassLoader());
105+
}
106+
107+
@Test
108+
public void testThreadContextClassLoaderIsUsedIfNotUsingWithClassLoader() throws ClassNotFoundException {
109+
TypeFactory spySut = spy(objectMapper.getTypeFactory());
110+
Assert.assertNull(spySut.getClassLoader());
111+
Class<?> clazz = spySut.findClass(aClassName);
112+
Assert.assertNotNull(clazz);
113+
verify(spySut).classForName(any(String.class), any(Boolean.class), eq(threadClassLoader));
114+
}
115+
116+
@Test
117+
public void testUsesFallBackClassLoaderIfNoThreadClassLoaderAndNoWithClassLoader() throws ClassNotFoundException {
118+
Thread.currentThread().setContextClassLoader(null);
119+
TypeFactory spySut = spy(objectMapper.getTypeFactory());
120+
Assert.assertNull(spySut.getClassLoader());
121+
Assert.assertArrayEquals(null,spySut._modifiers);
122+
Class<?> clazz = spySut.findClass(aClassName);
123+
Assert.assertNotNull(clazz);
124+
verify(spySut).classForName(any(String.class));
125+
}
126+
127+
public static class AClass
128+
{
129+
private String _foo, _bar;
130+
protected final static Class<?> thisClass = new Object() {
131+
}.getClass().getEnclosingClass();
132+
133+
public AClass() { }
134+
public AClass(String foo, String bar) {
135+
_foo = foo;
136+
_bar = bar;
137+
}
138+
public String getFoo() { return _foo; }
139+
public String getBar() { return _bar; }
140+
141+
public void setFoo(String foo) { _foo = foo; }
142+
public void setBar(String bar) { _bar = bar; }
143+
public static String getStaticClassName() {
144+
return thisClass.getCanonicalName().replace("."+thisClass.getSimpleName(), "$"+thisClass.getSimpleName());
145+
}
146+
}
147+
}

0 commit comments

Comments
 (0)