Repository: wicket Updated Branches: refs/heads/classloadingfix [created] 5b7ff7d03
WICKET-6353: override resolveProxyClass to lookup classes in Wicket's ClassResolver Project: http://git-wip-us.apache.org/repos/asf/wicket/repo Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/5b7ff7d0 Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/5b7ff7d0 Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/5b7ff7d0 Branch: refs/heads/classloadingfix Commit: 5b7ff7d03a9a4fe1ec20a7021ab7ec46ef2fbca8 Parents: 137fa9e Author: Emond Papegaaij <[email protected]> Authored: Wed Apr 5 14:54:28 2017 +0200 Committer: Emond Papegaaij <[email protected]> Committed: Wed Apr 5 14:54:28 2017 +0200 ---------------------------------------------------------------------- .../wicket/serialize/java/JavaSerializer.java | 111 ++++++++++++++++--- 1 file changed, 98 insertions(+), 13 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/wicket/blob/5b7ff7d0/wicket-core/src/main/java/org/apache/wicket/serialize/java/JavaSerializer.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/serialize/java/JavaSerializer.java b/wicket-core/src/main/java/org/apache/wicket/serialize/java/JavaSerializer.java index 1ca239b..39c09ce 100644 --- a/wicket-core/src/main/java/org/apache/wicket/serialize/java/JavaSerializer.java +++ b/wicket-core/src/main/java/org/apache/wicket/serialize/java/JavaSerializer.java @@ -25,6 +25,10 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamClass; import java.io.OutputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Proxy; import org.apache.wicket.Application; import org.apache.wicket.ThreadContext; @@ -188,45 +192,126 @@ public class JavaSerializer implements ISerializer protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { - String className = desc.getName(); - try { return super.resolveClass(desc); } - catch (ClassNotFoundException ex1) + catch (ClassNotFoundException cnfEx) { // ignore this exception. - log.debug("Class not found by the object outputstream itself, trying the IClassResolver"); + log.debug( + "Class not found by the object outputstream itself, trying the IClassResolver"); + + Class< ? > candidate = resolveClassInWicket(desc.getName()); + if (candidate == null) + { + throw cnfEx; + } + return candidate; } + } + private Class< ? > resolveClassByName(String className) throws ClassNotFoundException + { + try + { + return Class.forName(className, false, latestUserDefinedLoader()); + } + catch (ClassNotFoundException cnfEx) + { + Class< ? > ret = resolveClassInWicket(className); + if (ret == null) + throw cnfEx; + return ret; + } + } - Class<?> candidate = null; + private Class< ? > resolveClassInWicket(String className) throws ClassNotFoundException + { + Class< ? > candidate; try { - // Can the application always be taken?? - // Should be if serialization happened in thread with application set - // (WICKET-2195) Application application = Application.get(); ApplicationSettings applicationSettings = application.getApplicationSettings(); IClassResolver classResolver = applicationSettings.getClassResolver(); candidate = classResolver.resolveClass(className); - if (candidate == null) - { - candidate = super.resolveClass(desc); - } } catch (WicketRuntimeException ex) { if (ex.getCause() instanceof ClassNotFoundException) { - throw (ClassNotFoundException)ex.getCause(); + throw (ClassNotFoundException) ex.getCause(); + } + else + { + ClassNotFoundException wrapperCnf = new ClassNotFoundException(); + wrapperCnf.initCause(ex); + throw wrapperCnf; } } return candidate; } + + @Override + protected Class< ? > resolveProxyClass(String[] interfaces) throws ClassNotFoundException + { + ClassLoader latestLoader = latestUserDefinedLoader(); + ClassLoader nonPublicLoader = null; + boolean hasNonPublicInterface = false; + + // define proxy in class loader of non-public interface(s), if any + Class< ? >[] classObjs = new Class< ? >[interfaces.length]; + for (int i = 0; i < interfaces.length; i++) + { + Class< ? > cl = resolveClassByName(interfaces[i]); + if ((cl.getModifiers() & Modifier.PUBLIC) == 0) + { + if (hasNonPublicInterface) + { + if (nonPublicLoader != cl.getClassLoader()) + { + throw new IllegalAccessError( + "conflicting non-public interface class loaders"); + } + } + else + { + nonPublicLoader = cl.getClassLoader(); + hasNonPublicInterface = true; + } + } + classObjs[i] = cl; + } + try + { + return Proxy.getProxyClass(hasNonPublicInterface ? nonPublicLoader : latestLoader, + classObjs); + } + catch (IllegalArgumentException e) + { + throw new ClassNotFoundException(null, e); + } + } + + private static ClassLoader latestUserDefinedLoader() + { + try + { + Method originalMethod = + ObjectInputStream.class.getDeclaredMethod("latestUserDefinedLoader"); + originalMethod.setAccessible(true); + return (ClassLoader) originalMethod.invoke(null); + } + catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException + | NoSuchMethodException | SecurityException e) + { + // should not happen + throw new WicketRuntimeException(e); + } + } } + /** * Write objects to the wrapped output stream and log a meaningful message for serialization * problems.
