You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by pa...@apache.org on 2017/04/05 12:55:10 UTC

wicket git commit: WICKET-6353: override resolveProxyClass to lookup classes in Wicket's ClassResolver

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 <pa...@apache.org>
Authored: Wed Apr 5 14:54:28 2017 +0200
Committer: Emond Papegaaij <pa...@apache.org>
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.