Skip to content

Commit 1dfce3b

Browse files
authored
Merge pull request #2085 from lprimak/add-shiro-core-classloading
2 parents 03126c4 + a4d63d6 commit 1dfce3b

File tree

2 files changed

+65
-5
lines changed

2 files changed

+65
-5
lines changed

core/src/main/java/org/apache/shiro/mgt/AbstractRememberMeManager.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.apache.shiro.lang.io.Serializer;
3030
import org.apache.shiro.lang.util.ByteSource;
3131
import org.apache.shiro.lang.util.ByteUtils;
32+
import org.apache.shiro.lang.util.ClassUtils;
3233
import org.apache.shiro.subject.PrincipalCollection;
3334
import org.apache.shiro.subject.Subject;
3435
import org.apache.shiro.subject.SubjectContext;
@@ -509,7 +510,12 @@ protected byte[] decrypt(byte[] encrypted) {
509510
* @return the serialized principal collection in the form of a byte array
510511
*/
511512
protected byte[] serialize(PrincipalCollection principals) {
512-
return getSerializer().serialize(principals);
513+
ClassUtils.setAdditionalClassLoader(AbstractRememberMeManager.class.getClassLoader());
514+
try {
515+
return getSerializer().serialize(principals);
516+
} finally {
517+
ClassUtils.removeAdditionalClassLoader();
518+
}
513519
}
514520

515521
/**
@@ -520,7 +526,12 @@ protected byte[] serialize(PrincipalCollection principals) {
520526
* @return the deserialized (reconstituted) {@code PrincipalCollection}
521527
*/
522528
protected PrincipalCollection deserialize(byte[] serializedIdentity) {
523-
return getSerializer().deserialize(serializedIdentity);
529+
ClassUtils.setAdditionalClassLoader(AbstractRememberMeManager.class.getClassLoader());
530+
try {
531+
return getSerializer().deserialize(serializedIdentity);
532+
} finally {
533+
ClassUtils.removeAdditionalClassLoader();
534+
}
524535
}
525536

526537
/**

lang/src/main/java/org/apache/shiro/lang/util/ClassUtils.java

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public final class ClassUtils {
4343
*/
4444
private static final Logger LOGGER = LoggerFactory.getLogger(ClassUtils.class);
4545

46+
private static final ThreadLocal<ClassLoader> ADDITIONAL_CLASS_LOADER = new ThreadLocal<>();
4647

4748
/**
4849
* SHIRO-767: add a map to mapping primitive data type
@@ -75,13 +76,24 @@ protected ClassLoader doGetClassLoader() throws Throwable {
7576
/**
7677
* @since 1.0
7778
*/
78-
private static final ClassLoaderAccessor CLASS_CL_ACCESSOR = new ExceptionIgnoringAccessor() {
79+
private static final ClassLoaderAccessor CLASS_LANG_CL_ACCESSOR = new ExceptionIgnoringAccessor() {
7980
@Override
8081
protected ClassLoader doGetClassLoader() throws Throwable {
8182
return ClassUtils.class.getClassLoader();
8283
}
8384
};
8485

86+
/**
87+
* @since 2.0.4
88+
*/
89+
private static final ClassLoaderAccessor ADDITIONAL_CL_ACCESSOR = new ExceptionIgnoringAccessor() {
90+
@Override
91+
protected ClassLoader doGetClassLoader() throws Throwable {
92+
ClassLoader cl = ADDITIONAL_CLASS_LOADER.get();
93+
return cl != null ? cl : ClassUtils.class.getClassLoader();
94+
}
95+
};
96+
8597
/**
8698
* @since 1.0
8799
*/
@@ -117,7 +129,15 @@ public static InputStream getResourceAsStream(String name) {
117129
LOGGER.trace("Resource [" + name + "] was not found via the thread context ClassLoader. Trying the "
118130
+ "current ClassLoader...");
119131
}
120-
is = CLASS_CL_ACCESSOR.getResourceStream(name);
132+
is = CLASS_LANG_CL_ACCESSOR.getResourceStream(name);
133+
}
134+
135+
if (is == null) {
136+
if (LOGGER.isTraceEnabled()) {
137+
LOGGER.trace("Resource [" + name + "] was not found via the org.apache.shiro.lang ClassLoader. Trying the "
138+
+ "additionally set ClassLoader...");
139+
}
140+
is = ADDITIONAL_CL_ACCESSOR.getResourceStream(name);
121141
}
122142

123143
if (is == null) {
@@ -157,7 +177,15 @@ public static <T> Class<T> forName(String fqcn) throws UnknownClassException {
157177
LOGGER.trace("Unable to load class named [" + fqcn
158178
+ "] from the thread context ClassLoader. Trying the current ClassLoader...");
159179
}
160-
clazz = CLASS_CL_ACCESSOR.loadClass(fqcn);
180+
clazz = CLASS_LANG_CL_ACCESSOR.loadClass(fqcn);
181+
}
182+
183+
if (clazz == null) {
184+
if (LOGGER.isTraceEnabled()) {
185+
LOGGER.trace("Unable to load class named [" + fqcn
186+
+ "] from the org.apache.shiro.lang ClassLoader. Trying the additionally set ClassLoader...");
187+
}
188+
clazz = ADDITIONAL_CL_ACCESSOR.loadClass(fqcn);
161189
}
162190

163191
if (clazz == null) {
@@ -259,6 +287,27 @@ public static List<Method> getAnnotatedMethods(final Class<?> type, final Class<
259287
return methods;
260288
}
261289

290+
/**
291+
* Sets additional ClassLoader for {@link #getResourceAsStream(String)} and {@link #forName(String)} to use
292+
* It is used in addition to the thread context class loader and the system class loader.
293+
294+
* @param classLoader class loader to use
295+
* @since 2.0.4
296+
*/
297+
public static void setAdditionalClassLoader(ClassLoader classLoader) {
298+
ADDITIONAL_CLASS_LOADER.set(classLoader);
299+
}
300+
301+
/**
302+
* Removes the additional ClassLoader set by {@link #setAdditionalClassLoader(ClassLoader)}.
303+
* This must be called to avoid memory leaks.
304+
*
305+
* @since 2.0.4
306+
*/
307+
public static void removeAdditionalClassLoader() {
308+
ADDITIONAL_CLASS_LOADER.remove();
309+
}
310+
262311
/**
263312
* @since 1.0
264313
*/

0 commit comments

Comments
 (0)