This is an automated email from the ASF dual-hosted git repository. svenmeier pushed a commit to branch WICKET-6913-wicket-9.x in repository https://gitbox.apache.org/repos/asf/wicket.git
commit 8287aa9f762a08574fe4ff433524aa9f374687fc Author: Sven Meier <[email protected]> AuthorDate: Mon Aug 23 15:02:31 2021 +0200 WICKET-6913 bytebuddy for wicket-9.x optional via system parameter wicket.ioc.proxyfactory --- NOTICE | 7 +- README.md | 3 +- pom.xml | 6 + wicket-examples/src/main/resources/META-INF/NOTICE | 9 +- wicket-ioc/pom.xml | 6 +- wicket-ioc/src/main/java/module-info.java | 1 + .../apache/wicket/proxy/IProxyFactory.java} | 25 +- .../apache/wicket/proxy/IProxyTargetLocator.java | 3 +- .../apache/wicket/proxy/LazyInitProxyFactory.java | 434 ++++++--------------- .../proxy/bytebuddy/ByteBuddyProxyFactory.java | 302 ++++++++++++++ .../ObjenesisByteBuddyInterceptor.java} | 11 +- .../ObjenesisProxyFactory.java} | 25 +- .../ObjenesisProxyReplacement.java | 5 +- .../wicket/proxy/cglib/CglibProxyFactory.java | 155 ++++++++ .../apache/wicket/proxy/jdk/JdkProxyFactory.java | 196 ++++++++++ .../proxy/objenesis/ObjenesisCGLibInterceptor.java | 4 +- .../proxy/objenesis/ObjenesisProxyReplacement.java | 4 +- .../wicket/injection/util/MockDependency.java | 5 +- .../annot/SpringBeanWithGenericsTest.java | 2 +- 19 files changed, 832 insertions(+), 371 deletions(-) diff --git a/NOTICE b/NOTICE index 3e462db..bc97306 100644 --- a/NOTICE +++ b/NOTICE @@ -56,8 +56,11 @@ src/./wicket-examples This product includes software developed by the CGLib Project (http://cglib.sourceforge.net). - This product includes ASM, released under a BSD style license (http://asm.objectweb.org). - Copyright (c) 2000-2005 INRIA, France Telecom + This product includes ASM, released under a BSD style license (https://asm.ow2.io/). + Copyright (c) 2000-2011 INRIA, France Telecom + + This product includes software developed by the ByteBuddy Project + (https://bytebuddy.net/). This product includes jhighlight (https://jhighlight.dev.java.net/) which is released under CDDL 1.0 license (http://www.opensource.org/licenses/cddl1.php). diff --git a/README.md b/README.md index 01e9982..8faa041 100644 --- a/README.md +++ b/README.md @@ -159,7 +159,8 @@ the src/ folder. - wicket-ioc: cglib 3.1 (http://cglib.sourceforge.net/) and - asm-util 5.0.3 (http://asm.objectweb.org/) + asm-util 9.1 (https://asm.ow2.io/) + byte-buddy 1.11.12 (https://bytebuddy.net/) and - wicket-spring: diff --git a/pom.xml b/pom.xml index b4cbc76..589c2a8 100644 --- a/pom.xml +++ b/pom.xml @@ -139,6 +139,7 @@ <assertj-core.version>3.19.0</assertj-core.version> <cdi-unit.version>4.1.0</cdi-unit.version> <cglib.version>3.3.0</cglib.version> + <byte-buddy.version>1.11.12</byte-buddy.version> <commons-collections.version>3.2.2</commons-collections.version> <commons-collections4.version>4.4</commons-collections4.version> <commons-fileupload.version>1.4</commons-fileupload.version> @@ -321,6 +322,11 @@ <optional>true</optional> </dependency> <dependency> + <groupId>net.bytebuddy</groupId> + <artifactId>byte-buddy</artifactId> + <version>${byte-buddy.version}</version> + </dependency> + <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> <version>${commons-collections4.version}</version> diff --git a/wicket-examples/src/main/resources/META-INF/NOTICE b/wicket-examples/src/main/resources/META-INF/NOTICE index 619dd91..3598cb3 100644 --- a/wicket-examples/src/main/resources/META-INF/NOTICE +++ b/wicket-examples/src/main/resources/META-INF/NOTICE @@ -29,8 +29,11 @@ This product includes software developed by the CGLib Project (http://cglib.sourceforge.net). - This product includes ASM, released under a BSD style license (http://asm.objectweb.org). - Copyright (c) 2000-2005 INRIA, France Telecom + This product includes ASM, released under a BSD style license (https://asm.ow2.io/). + Copyright (c) 2000-2011 INRIA, France Telecom + + This product includes software developed by the ByteBuddy Project + (https://bytebuddy.net/). This product includes jhighlight (https://jhighlight.dev.java.net/) which is released under CDDL 1.0 license (http://www.opensource.org/licenses/cddl1.php). @@ -42,4 +45,4 @@ jQuery Foundation, Inc, http://jquery.org/license Contains qunit.css released under a MIT style license. - jQuery Foundation, Inc, http://jquery.org/license \ No newline at end of file + jQuery Foundation, Inc, http://jquery.org/license diff --git a/wicket-ioc/pom.xml b/wicket-ioc/pom.xml index d34c07f..8ccb684 100644 --- a/wicket-ioc/pom.xml +++ b/wicket-ioc/pom.xml @@ -41,9 +41,13 @@ <artifactId>javax.inject</artifactId> </dependency> <dependency> + <groupId>net.bytebuddy</groupId> + <artifactId>byte-buddy</artifactId> + <optional>true</optional> + </dependency> + <dependency> <groupId>org.apache.wicket</groupId> <artifactId>wicket-core</artifactId> - <version>${project.version}</version> </dependency> <dependency> <groupId>org.objenesis</groupId> diff --git a/wicket-ioc/src/main/java/module-info.java b/wicket-ioc/src/main/java/module-info.java index 6f7f7e1..d175804 100644 --- a/wicket-ioc/src/main/java/module-info.java +++ b/wicket-ioc/src/main/java/module-info.java @@ -19,6 +19,7 @@ module org.apache.wicket.ioc { requires org.apache.wicket.util; requires org.apache.wicket.core; requires cglib; + requires net.bytebuddy; requires org.objenesis; exports org.apache.wicket.injection; diff --git a/wicket-ioc/src/main/java/module-info.java b/wicket-ioc/src/main/java/org/apache/wicket/proxy/IProxyFactory.java similarity index 70% copy from wicket-ioc/src/main/java/module-info.java copy to wicket-ioc/src/main/java/org/apache/wicket/proxy/IProxyFactory.java index 6f7f7e1..ef5f638 100644 --- a/wicket-ioc/src/main/java/module-info.java +++ b/wicket-ioc/src/main/java/org/apache/wicket/proxy/IProxyFactory.java @@ -14,14 +14,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package org.apache.wicket.proxy; -module org.apache.wicket.ioc { - requires org.apache.wicket.util; - requires org.apache.wicket.core; - requires cglib; - requires org.objenesis; - - exports org.apache.wicket.injection; - exports org.apache.wicket.proxy; - exports org.apache.wicket.proxy.objenesis; +/** + * A factory of proxies. + */ +public interface IProxyFactory +{ + /** + * Create a proxy. + * + * @param type + * the target type + * @param locator + * the locator of the target + * @return a proxy + */ + public Object createProxy(final Class<?> type, final IProxyTargetLocator locator); } diff --git a/wicket-ioc/src/main/java/org/apache/wicket/proxy/IProxyTargetLocator.java b/wicket-ioc/src/main/java/org/apache/wicket/proxy/IProxyTargetLocator.java index 2b8eb25..6df597e 100644 --- a/wicket-ioc/src/main/java/org/apache/wicket/proxy/IProxyTargetLocator.java +++ b/wicket-ioc/src/main/java/org/apache/wicket/proxy/IProxyTargetLocator.java @@ -16,6 +16,7 @@ */ package org.apache.wicket.proxy; +import org.apache.wicket.proxy.cglib.CglibProxyFactory; import org.apache.wicket.util.io.IClusterable; /** @@ -43,7 +44,7 @@ import org.apache.wicket.util.io.IClusterable; * } * </pre> * - * @see LazyInitProxyFactory#createProxy(Class, IProxyTargetLocator) + * @see CglibProxyFactory#createProxy(Class, IProxyTargetLocator) * * @author Igor Vaynberg (ivaynberg) * diff --git a/wicket-ioc/src/main/java/org/apache/wicket/proxy/LazyInitProxyFactory.java b/wicket-ioc/src/main/java/org/apache/wicket/proxy/LazyInitProxyFactory.java index ccc7769..dc1ae95 100644 --- a/wicket-ioc/src/main/java/org/apache/wicket/proxy/LazyInitProxyFactory.java +++ b/wicket-ioc/src/main/java/org/apache/wicket/proxy/LazyInitProxyFactory.java @@ -18,32 +18,23 @@ package org.apache.wicket.proxy; import java.io.ObjectStreamException; import java.io.Serializable; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.Proxy; import java.util.Arrays; import java.util.List; +import org.apache.wicket.WicketRuntimeException; +import org.apache.wicket.core.util.lang.WicketObjects; +import org.apache.wicket.model.IModel; +import org.apache.wicket.proxy.cglib.CglibProxyFactory; +import org.apache.wicket.proxy.jdk.JdkProxyFactory; +import org.apache.wicket.util.io.IClusterable; + import net.sf.cglib.core.DefaultNamingPolicy; import net.sf.cglib.core.Predicate; -import net.sf.cglib.proxy.Callback; -import net.sf.cglib.proxy.CallbackFilter; -import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import net.sf.cglib.proxy.NoOp; -import org.apache.wicket.Application; -import org.apache.wicket.WicketRuntimeException; -import org.apache.wicket.core.util.lang.WicketObjects; -import org.apache.wicket.model.IModel; -import org.apache.wicket.proxy.objenesis.ObjenesisProxyFactory; -import org.apache.wicket.util.io.IClusterable; -import org.apache.wicket.util.string.Strings; - /** * A factory class that creates lazy init proxies given a type and a {@link IProxyTargetLocator} * used to retrieve the object the proxy will represent. @@ -53,7 +44,7 @@ import org.apache.wicket.util.string.Strings; * forwarded. * <p> * This factory creates two kinds of proxies: A standard dynamic proxy when the specified type is an - * interface, and a CGLib proxy when the specified type is a concrete class. + * interface, and a ByteBuddy proxy when the specified type is a concrete class. * <p> * The general use case for such a proxy is to represent a dependency that should not be serialized * with a wicket page or {@link IModel}. The solution is to serialize the proxy and the @@ -112,16 +103,29 @@ public class LazyInitProxyFactory /** * Primitive java types and their object wrappers */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - private static final List PRIMITIVES = Arrays.asList(String.class, byte.class, Byte.class, + private static final List<Class<?>> PRIMITIVES = Arrays.asList(String.class, byte.class, Byte.class, short.class, Short.class, int.class, Integer.class, long.class, Long.class, float.class, Float.class, double.class, Double.class, char.class, Character.class, boolean.class, Boolean.class); - - private static final int CGLIB_CALLBACK_NO_OVERRIDE = 0; - private static final int CGLIB_CALLBACK_HANDLER = 1; - - private static final boolean IS_OBJENESIS_AVAILABLE = isObjenesisAvailable(); + + private static final IProxyFactory proxyFactory = initProxyFactory(); + + private static IProxyFactory initProxyFactory() { + IProxyFactory proxyFactory = null; + + String factoryName = System.getProperty("wicket.ioc.proxyfactory"); + if (factoryName == null) { + proxyFactory = new CglibProxyFactory(); + } else { + try { + proxyFactory = (IProxyFactory) Class.forName(factoryName).getConstructor().newInstance(); + } catch (Exception e) { + throw new Error(String.format("wicket.ioc.proxyFactory=%s", factoryName), e); + } + } + + return proxyFactory; + } /** * Create a lazy init proxy for the specified type. The target object will be located using the @@ -145,70 +149,14 @@ public class LazyInitProxyFactory } else if (type.isInterface()) { - JdkHandler handler = new JdkHandler(type, locator); - - try - { - return Proxy.newProxyInstance(resolveClassLoader(), - new Class[] { type, Serializable.class, ILazyInitProxy.class, - IWriteReplace.class }, handler); - } - catch (IllegalArgumentException e) - { - /* - * STW: In some clustering environments it appears the context classloader fails to - * load the proxied interface (currently seen in BEA WLS 9.x clusters). If this - * happens, we can try and fall back to the classloader (current) that actually - * loaded this class. - */ - return Proxy.newProxyInstance(LazyInitProxyFactory.class.getClassLoader(), - new Class[] { type, Serializable.class, ILazyInitProxy.class, - IWriteReplace.class }, handler); - } - - } - else if (IS_OBJENESIS_AVAILABLE && !hasNoArgConstructor(type)) - { - return ObjenesisProxyFactory.createProxy(type, locator, WicketNamingPolicy.INSTANCE); - } - else - { - CGLibInterceptor handler = new CGLibInterceptor(type, locator); - - Callback[] callbacks = new Callback[2]; - callbacks[CGLIB_CALLBACK_NO_OVERRIDE] = SerializableNoOpCallback.INSTANCE; - callbacks[CGLIB_CALLBACK_HANDLER] = handler; - - Enhancer e = new Enhancer(); - e.setClassLoader(resolveClassLoader()); - e.setInterfaces(new Class[] { Serializable.class, ILazyInitProxy.class, - IWriteReplace.class }); - e.setSuperclass(type); - e.setCallbackFilter(NoOpForProtectedMethodsCGLibCallbackFilter.INSTANCE); - e.setCallbacks(callbacks); - e.setNamingPolicy(WicketNamingPolicy.INSTANCE); - - return e.create(); - } - } - - private static ClassLoader resolveClassLoader() - { - ClassLoader classLoader = null; - if (Application.exists()) - { - classLoader = Application.get().getApplicationSettings() - .getClassResolver().getClassLoader(); + return new JdkProxyFactory().createProxy(type, locator); } - - if (classLoader == null) { - classLoader = Thread.currentThread().getContextClassLoader(); + else { + return proxyFactory.createProxy(type, locator); } - - return classLoader; } - - /** + + /** * This interface is used to make the proxy forward writeReplace() call to the handler instead * of invoking it on itself. This allows us to serialize the replacement object instead of the * proxy itself in case the proxy subclass is deserialized on a VM that does not have it @@ -229,7 +177,7 @@ public class LazyInitProxyFactory */ Object writeReplace() throws ObjectStreamException; } - + /** * Object that replaces the proxy when it is serialized. Upon deserialization this object will * create a new proxy with the same locator. @@ -237,7 +185,7 @@ public class LazyInitProxyFactory * @author Igor Vaynberg (ivaynberg) * */ - static class ProxyReplacement implements IClusterable + public static class ProxyReplacement implements IClusterable { private static final long serialVersionUID = 1L; @@ -286,6 +234,72 @@ public class LazyInitProxyFactory } /** + * Checks if the method is derived from Object.equals() + * + * @param method + * method being tested + * @return true if the method is derived from Object.equals(), false otherwise + */ + public static boolean isEqualsMethod(final Method method) + { + return (method.getReturnType() == boolean.class) && + (method.getParameterTypes().length == 1) && + (method.getParameterTypes()[0] == Object.class) && method.getName().equals("equals"); + } + + /** + * Checks if the method is derived from Object.hashCode() + * + * @param method + * method being tested + * @return true if the method is defined from Object.hashCode(), false otherwise + */ + public static boolean isHashCodeMethod(final Method method) + { + return (method.getReturnType() == int.class) && (method.getParameterTypes().length == 0) && + method.getName().equals("hashCode"); + } + + /** + * Checks if the method is derived from Object.toString() + * + * @param method + * method being tested + * @return true if the method is defined from Object.toString(), false otherwise + */ + public static boolean isToStringMethod(final Method method) + { + return (method.getReturnType() == String.class) && + (method.getParameterTypes().length == 0) && method.getName().equals("toString"); + } + + /** + * Checks if the method is derived from Object.finalize() + * + * @param method + * method being tested + * @return true if the method is defined from Object.finalize(), false otherwise + */ + public static boolean isFinalizeMethod(final Method method) + { + return (method.getReturnType() == void.class) && (method.getParameterTypes().length == 0) && + method.getName().equals("finalize"); + } + + /** + * Checks if the method is the writeReplace method + * + * @param method + * method being tested + * @return true if the method is the writeReplace method, false otherwise + */ + public static boolean isWriteReplaceMethod(final Method method) + { + return (method.getReturnType() == Object.class) && + (method.getParameterTypes().length == 0) && method.getName().equals("writeReplace"); + } + + /** * Method interceptor for proxies representing concrete object not backed by an interface. These * proxies are represented by cglib proxies. * @@ -331,24 +345,24 @@ public class LazyInitProxyFactory public Object intercept(final Object object, final Method method, final Object[] args, final MethodProxy proxy) throws Throwable { - if (isFinalizeMethod(method)) + if (LazyInitProxyFactory.isFinalizeMethod(method)) { // swallow finalize call return null; } - else if (isEqualsMethod(method)) + else if (LazyInitProxyFactory.isEqualsMethod(method)) { return (equals(args[0])) ? Boolean.TRUE : Boolean.FALSE; } - else if (isHashCodeMethod(method)) + else if (LazyInitProxyFactory.isHashCodeMethod(method)) { return hashCode(); } - else if (isToStringMethod(method)) + else if (LazyInitProxyFactory.isToStringMethod(method)) { return toString(); } - else if (isWriteReplaceMethod(method)) + else if (LazyInitProxyFactory.isWriteReplaceMethod(method)) { return writeReplace(); } @@ -380,16 +394,13 @@ public class LazyInitProxyFactory * * @author Igor Vaynberg (ivaynberg) */ - protected static class CGLibInterceptor extends AbstractCGLibInterceptor + public static class CGLibInterceptor extends AbstractCGLibInterceptor { public CGLibInterceptor(Class<?> type, IProxyTargetLocator locator) { super(type, locator); } - /** - * @see org.apache.wicket.proxy.LazyInitProxyFactory.IWriteReplace#writeReplace() - */ @Override public Object writeReplace() throws ObjectStreamException { @@ -404,214 +415,10 @@ public class LazyInitProxyFactory { private static final long serialVersionUID = 1L; - private static final NoOp INSTANCE = new SerializableNoOpCallback(); - } - - /** - * CGLib callback filter which does not intercept protected methods. - * - * Protected methods need to be called with invokeSuper() instead of invoke(). - * When invoke() is called on a protected method, it throws an "IllegalArgumentException: - * Protected method" exception. - * That being said, we do not need to intercept the protected methods so this callback filter - * is designed to use a NoOp callback for protected methods. - * - * @see <a href="http://comments.gmane.org/gmane.comp.java.cglib.devel/720">Discussion about - * this very issue in Spring AOP</a> - * @see <a href="https://github.com/wicketstuff/core/wiki/SpringReference">The WicketStuff - * SpringReference project which worked around this issue</a> - */ - private static class NoOpForProtectedMethodsCGLibCallbackFilter implements CallbackFilter - { - private static final CallbackFilter INSTANCE = new NoOpForProtectedMethodsCGLibCallbackFilter(); - - @Override - public int accept(Method method) { - if (Modifier.isProtected(method.getModifiers())) - { - return CGLIB_CALLBACK_NO_OVERRIDE; - } - else - { - return CGLIB_CALLBACK_HANDLER; - } - } - } - - /** - * Invocation handler for proxies representing interface based object. For interface backed - * objects dynamic jdk proxies are used. - * - * @author Igor Vaynberg (ivaynberg) - * - */ - private static class JdkHandler - implements - InvocationHandler, - ILazyInitProxy, - Serializable, - IWriteReplace - { - private static final long serialVersionUID = 1L; - - private final IProxyTargetLocator locator; - - private final String typeName; - - private transient Object target; - - /** - * Constructor - * - * @param type - * class of object this handler will represent - * - * @param locator - * object locator used to locate the object this proxy represents - */ - public JdkHandler(final Class<?> type, final IProxyTargetLocator locator) - { - super(); - this.locator = locator; - typeName = type.getName(); - } - - /** - * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, - * java.lang.reflect.Method, java.lang.Object[]) - */ - @Override - public Object invoke(final Object proxy, final Method method, final Object[] args) - throws Throwable - { - if (isFinalizeMethod(method)) - { - // swallow finalize call - return null; - } - else if (isEqualsMethod(method)) - { - return (equals(args[0])) ? Boolean.TRUE : Boolean.FALSE; - } - else if (isHashCodeMethod(method)) - { - return hashCode(); - } - else if (isToStringMethod(method)) - { - return toString(); - } - else if (method.getDeclaringClass().equals(ILazyInitProxy.class)) - { - return getObjectLocator(); - } - else if (isWriteReplaceMethod(method)) - { - return writeReplace(); - } - - if (target == null) - { - - target = locator.locateProxyTarget(); - } - try - { - method.setAccessible(true); - return method.invoke(target, args); - } - catch (InvocationTargetException e) - { - throw e.getTargetException(); - } - } - - /** - * @see org.apache.wicket.proxy.ILazyInitProxy#getObjectLocator() - */ - @Override - public IProxyTargetLocator getObjectLocator() - { - return locator; - } - - /** - * @see org.apache.wicket.proxy.LazyInitProxyFactory.IWriteReplace#writeReplace() - */ - @Override - public Object writeReplace() throws ObjectStreamException - { - return new ProxyReplacement(typeName, locator); - } + public static final NoOp INSTANCE = new SerializableNoOpCallback(); } - - /** - * Checks if the method is derived from Object.equals() - * - * @param method - * method being tested - * @return true if the method is derived from Object.equals(), false otherwise - */ - public static boolean isEqualsMethod(final Method method) - { - return (method.getReturnType() == boolean.class) && - (method.getParameterTypes().length == 1) && - (method.getParameterTypes()[0] == Object.class) && method.getName().equals("equals"); - } - - /** - * Checks if the method is derived from Object.hashCode() - * - * @param method - * method being tested - * @return true if the method is defined from Object.hashCode(), false otherwise - */ - public static boolean isHashCodeMethod(final Method method) - { - return (method.getReturnType() == int.class) && (method.getParameterTypes().length == 0) && - method.getName().equals("hashCode"); - } - - /** - * Checks if the method is derived from Object.toString() - * - * @param method - * method being tested - * @return true if the method is defined from Object.toString(), false otherwise - */ - public static boolean isToStringMethod(final Method method) - { - return (method.getReturnType() == String.class) && - (method.getParameterTypes().length == 0) && method.getName().equals("toString"); - } - - /** - * Checks if the method is derived from Object.finalize() - * - * @param method - * method being tested - * @return true if the method is defined from Object.finalize(), false otherwise - */ - public static boolean isFinalizeMethod(final Method method) - { - return (method.getReturnType() == void.class) && (method.getParameterTypes().length == 0) && - method.getName().equals("finalize"); - } - - /** - * Checks if the method is the writeReplace method - * - * @param method - * method being tested - * @return true if the method is the writeReplace method, false otherwise - */ - public static boolean isWriteReplaceMethod(final Method method) - { - return (method.getReturnType() == Object.class) && - (method.getParameterTypes().length == 0) && method.getName().equals("writeReplace"); - } - - public static final class WicketNamingPolicy extends DefaultNamingPolicy + + public static class WicketNamingPolicy extends DefaultNamingPolicy { public static final WicketNamingPolicy INSTANCE = new WicketNamingPolicy(); @@ -632,25 +439,4 @@ public class LazyInitProxyFactory } } - - private static boolean hasNoArgConstructor(Class<?> type) - { - for (Constructor<?> constructor : type.getDeclaredConstructors()) - { - if (constructor.getParameterTypes().length == 0) - return true; - } - - return false; - } - - private static boolean isObjenesisAvailable() - { - try { - Class.forName("org.objenesis.ObjenesisStd"); - return true; - } catch (Exception ignored) { - return false; - } - } } diff --git a/wicket-ioc/src/main/java/org/apache/wicket/proxy/bytebuddy/ByteBuddyProxyFactory.java b/wicket-ioc/src/main/java/org/apache/wicket/proxy/bytebuddy/ByteBuddyProxyFactory.java new file mode 100644 index 0000000..3274d01 --- /dev/null +++ b/wicket-ioc/src/main/java/org/apache/wicket/proxy/bytebuddy/ByteBuddyProxyFactory.java @@ -0,0 +1,302 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.proxy.bytebuddy; + +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.function.Function; + +import org.apache.wicket.Application; +import org.apache.wicket.WicketRuntimeException; +import org.apache.wicket.proxy.ILazyInitProxy; +import org.apache.wicket.proxy.IProxyFactory; +import org.apache.wicket.proxy.IProxyTargetLocator; +import org.apache.wicket.proxy.LazyInitProxyFactory; +import org.apache.wicket.proxy.LazyInitProxyFactory.IWriteReplace; +import org.apache.wicket.proxy.LazyInitProxyFactory.ProxyReplacement; + +import net.bytebuddy.ByteBuddy; +import net.bytebuddy.NamingStrategy; +import net.bytebuddy.TypeCache; +import net.bytebuddy.description.modifier.Visibility; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.dynamic.loading.ClassLoadingStrategy; +import net.bytebuddy.implementation.FieldAccessor; +import net.bytebuddy.implementation.MethodDelegation; +import net.bytebuddy.implementation.bind.annotation.AllArguments; +import net.bytebuddy.implementation.bind.annotation.Origin; +import net.bytebuddy.implementation.bind.annotation.Pipe; +import net.bytebuddy.implementation.bind.annotation.RuntimeType; +import net.bytebuddy.matcher.ElementMatchers; + +/** + * A factory class that creates bytebuddy proxies. + */ +public class ByteBuddyProxyFactory implements IProxyFactory +{ + /** + * A cache used to store the dynamically generated classes by ByteBuddy. + * Without this cache a new class will be generated for each proxy creation + * and this will fill up the metaspace + */ + private static final TypeCache<TypeCache.SimpleKey> DYNAMIC_CLASS_CACHE = new TypeCache.WithInlineExpunction<>(TypeCache.Sort.SOFT); + + private static final ByteBuddy BYTE_BUDDY = new ByteBuddy().with(WicketNamingStrategy.INSTANCE); + + private static final boolean IS_OBJENESIS_AVAILABLE = isObjenesisAvailable(); + + /** + * Create a lazy init proxy for the specified type. The target object will be located using the + * provided locator upon first method invocation. + * + * @param type + * type that proxy will represent + * + * @param locator + * object locator that will locate the object the proxy represents + * + * @return lazily initializable proxy + */ + @Override + public Object createProxy(final Class<?> type, final IProxyTargetLocator locator) + { + if (IS_OBJENESIS_AVAILABLE && !hasNoArgConstructor(type)) + { + return ObjenesisProxyFactory.createProxy(type, locator); + } + else + { + Class<?> proxyClass = createOrGetProxyClass(type); + + try + { + Object instance = proxyClass.getDeclaredConstructor().newInstance(); + ByteBuddyInterceptor interceptor = new ByteBuddyInterceptor(type, locator); + ((InterceptorMutator) instance).setInterceptor(interceptor); + return instance; + } + catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) + { + throw new WicketRuntimeException(e); + } + } + } + + public static Class<?> createOrGetProxyClass(Class<?> type) + { + ClassLoader classLoader = resolveClassLoader(); + return DYNAMIC_CLASS_CACHE.findOrInsert(classLoader, + new TypeCache.SimpleKey(type), + () -> BYTE_BUDDY + .subclass(type) + .method(ElementMatchers.isPublic()) + .intercept( + MethodDelegation + .withDefaultConfiguration() + .withBinders(Pipe.Binder.install(Function.class)) + .toField("interceptor")) + .defineField("interceptor", ByteBuddyInterceptor.class, Visibility.PRIVATE) + .implement(InterceptorMutator.class).intercept(FieldAccessor.ofBeanProperty()) + .implement(Serializable.class, IWriteReplace.class, ILazyInitProxy.class).intercept(MethodDelegation.toField("interceptor")) + .make() + .load(classLoader, ClassLoadingStrategy.Default.INJECTION) + .getLoaded()); + } + + private static ClassLoader resolveClassLoader() + { + ClassLoader classLoader = null; + if (Application.exists()) + { + classLoader = Application.get().getApplicationSettings() + .getClassResolver().getClassLoader(); + } + + if (classLoader == null) { + classLoader = Thread.currentThread().getContextClassLoader(); + } + + return classLoader; + } + + /** + * An interface used to set the Byte Buddy interceptor after creating an + * instance of the dynamically created proxy class. + * We need to set the interceptor as a field in the proxy class so that + * we could use different interceptors for proxied classes with generics. + * For example: a {@link org.apache.wicket.Component} may need to inject + * two beans with the same raw type but different generic type(s) (<em> + * ArrayList<String></em> and <em>ArrayList<Integer></em>). + * Since the generic types are erased at runtime, and we use caching for the + * dynamic proxy classes we need to be able to set different interceptors + * after instantiating the proxy class. + */ + public interface InterceptorMutator + { + void setInterceptor(ByteBuddyInterceptor interceptor); + } + + /** + * Method interceptor for proxies representing concrete object not backed by an interface. + * These proxies are represented by ByteBuddy proxies. + * + * @author Igor Vaynberg (ivaynberg) + */ + public static class ByteBuddyInterceptor + implements + ILazyInitProxy, + Serializable, + IWriteReplace + { + private static final long serialVersionUID = 1L; + + protected final IProxyTargetLocator locator; + + protected final String typeName; + + private transient Object target; + + /** + * Constructor + * + * @param type + * class of the object this proxy was created for + * + * @param locator + * object locator used to locate the object this proxy represents + */ + public ByteBuddyInterceptor(final Class<?> type, final IProxyTargetLocator locator) + { + super(); + + this.typeName = type.getName(); + this.locator = locator; + } + + @RuntimeType + public Object intercept(@Origin Method method, @AllArguments Object[] args, @Pipe Function pipe) throws Exception + { + if (LazyInitProxyFactory.isFinalizeMethod(method)) + { + // swallow finalize call + return null; + } + else if (LazyInitProxyFactory.isEqualsMethod(method)) + { + return (equals(args[0])) ? Boolean.TRUE : Boolean.FALSE; + } + else if (LazyInitProxyFactory.isHashCodeMethod(method)) + { + return hashCode(); + } + else if (LazyInitProxyFactory.isToStringMethod(method)) + { + return toString(); + } + + if (target == null) + { + target = locator.locateProxyTarget(); + } + + return pipe.apply(target); + } + + @Override + public IProxyTargetLocator getObjectLocator() + { + return locator; + } + + @Override + public Object writeReplace() throws ObjectStreamException + { + return new ProxyReplacement(typeName, locator); + } + } + + /** + * A strategy that decides what should be the fully qualified name of the generated + * classes. Since it is not possible to create new classes in the <em>java.**</em> + * package we modify the package name by prefixing it with <em>bytebuddy_generated_wicket_proxy.</em>. + * For classes in any other packages we modify just the class name by prefixing + * it with <em>WicketProxy_</em>. This way the generated proxy class could still + * access package-private members of sibling classes. + */ + public static final class WicketNamingStrategy extends NamingStrategy.AbstractBase + { + public static final WicketNamingStrategy INSTANCE = new WicketNamingStrategy(); + + private WicketNamingStrategy() + { + super(); + } + + @Override + protected String name(TypeDescription superClass) { + String prefix = superClass.getName(); + int lastIdxOfDot = prefix.lastIndexOf('.'); + String packageName = prefix.substring(0, lastIdxOfDot); + String className = prefix.substring(lastIdxOfDot + 1); + String name = packageName + "."; + if (prefix.startsWith("java.")) + { + name = "bytebuddy_generated_wicket_proxy." + name + className; + } + else + { + name += "WicketProxy_" + className; + } + return name; + } + + @Override + public String redefine(TypeDescription typeDescription) { + return typeDescription.getName(); + } + + @Override + public String rebase(TypeDescription typeDescription) { + return typeDescription.getName(); + } + } + + + private static boolean hasNoArgConstructor(Class<?> type) + { + for (Constructor<?> constructor : type.getDeclaredConstructors()) + { + if (constructor.getParameterTypes().length == 0) + return true; + } + + return false; + } + + private static boolean isObjenesisAvailable() + { + try { + Class.forName("org.objenesis.ObjenesisStd"); + return true; + } catch (Exception ignored) { + return false; + } + } +} diff --git a/wicket-ioc/src/main/java/org/apache/wicket/proxy/objenesis/ObjenesisCGLibInterceptor.java b/wicket-ioc/src/main/java/org/apache/wicket/proxy/bytebuddy/ObjenesisByteBuddyInterceptor.java similarity index 76% copy from wicket-ioc/src/main/java/org/apache/wicket/proxy/objenesis/ObjenesisCGLibInterceptor.java copy to wicket-ioc/src/main/java/org/apache/wicket/proxy/bytebuddy/ObjenesisByteBuddyInterceptor.java index 63975a0..bac1b64 100644 --- a/wicket-ioc/src/main/java/org/apache/wicket/proxy/objenesis/ObjenesisCGLibInterceptor.java +++ b/wicket-ioc/src/main/java/org/apache/wicket/proxy/bytebuddy/ObjenesisByteBuddyInterceptor.java @@ -14,20 +14,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.wicket.proxy.objenesis; +package org.apache.wicket.proxy.bytebuddy; import java.io.ObjectStreamException; import org.apache.wicket.proxy.IProxyTargetLocator; -import org.apache.wicket.proxy.LazyInitProxyFactory; /** - * Method interceptor for proxies representing concrete object not backed by an interface. These - * proxies are representing by cglib proxies. + * Method interceptor for proxies representing concrete object not backed by an interface. + * These proxies are representing by ByteBuddy proxies. */ -public class ObjenesisCGLibInterceptor extends LazyInitProxyFactory.AbstractCGLibInterceptor +public class ObjenesisByteBuddyInterceptor extends ByteBuddyProxyFactory.ByteBuddyInterceptor { - public ObjenesisCGLibInterceptor(Class<?> type, IProxyTargetLocator locator) { + public ObjenesisByteBuddyInterceptor(Class<?> type, IProxyTargetLocator locator) { super(type, locator); } diff --git a/wicket-ioc/src/main/java/org/apache/wicket/proxy/objenesis/ObjenesisCGLibInterceptor.java b/wicket-ioc/src/main/java/org/apache/wicket/proxy/bytebuddy/ObjenesisProxyFactory.java similarity index 58% copy from wicket-ioc/src/main/java/org/apache/wicket/proxy/objenesis/ObjenesisCGLibInterceptor.java copy to wicket-ioc/src/main/java/org/apache/wicket/proxy/bytebuddy/ObjenesisProxyFactory.java index 63975a0..45cf623 100644 --- a/wicket-ioc/src/main/java/org/apache/wicket/proxy/objenesis/ObjenesisCGLibInterceptor.java +++ b/wicket-ioc/src/main/java/org/apache/wicket/proxy/bytebuddy/ObjenesisProxyFactory.java @@ -14,26 +14,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.wicket.proxy.objenesis; - -import java.io.ObjectStreamException; +package org.apache.wicket.proxy.bytebuddy; import org.apache.wicket.proxy.IProxyTargetLocator; -import org.apache.wicket.proxy.LazyInitProxyFactory; +import org.objenesis.ObjenesisStd; -/** - * Method interceptor for proxies representing concrete object not backed by an interface. These - * proxies are representing by cglib proxies. - */ -public class ObjenesisCGLibInterceptor extends LazyInitProxyFactory.AbstractCGLibInterceptor +public class ObjenesisProxyFactory { - public ObjenesisCGLibInterceptor(Class<?> type, IProxyTargetLocator locator) { - super(type, locator); - } + private static final ObjenesisStd OBJENESIS = new ObjenesisStd(false); - @Override - public Object writeReplace() throws ObjectStreamException + public static Object createProxy(final Class<?> type, final IProxyTargetLocator locator) { - return new ObjenesisProxyReplacement(typeName, locator); + Class<?> proxyClass = ByteBuddyProxyFactory.createOrGetProxyClass(type); + Object instance = OBJENESIS.newInstance(proxyClass); + ObjenesisByteBuddyInterceptor interceptor = new ObjenesisByteBuddyInterceptor(type, locator); + ((ByteBuddyProxyFactory.InterceptorMutator) instance).setInterceptor(interceptor); + return instance; } } diff --git a/wicket-ioc/src/main/java/org/apache/wicket/proxy/objenesis/ObjenesisProxyReplacement.java b/wicket-ioc/src/main/java/org/apache/wicket/proxy/bytebuddy/ObjenesisProxyReplacement.java similarity index 90% copy from wicket-ioc/src/main/java/org/apache/wicket/proxy/objenesis/ObjenesisProxyReplacement.java copy to wicket-ioc/src/main/java/org/apache/wicket/proxy/bytebuddy/ObjenesisProxyReplacement.java index cbffee8..4430182 100644 --- a/wicket-ioc/src/main/java/org/apache/wicket/proxy/objenesis/ObjenesisProxyReplacement.java +++ b/wicket-ioc/src/main/java/org/apache/wicket/proxy/bytebuddy/ObjenesisProxyReplacement.java @@ -14,14 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.wicket.proxy.objenesis; +package org.apache.wicket.proxy.bytebuddy; import java.io.ObjectStreamException; import org.apache.wicket.WicketRuntimeException; import org.apache.wicket.core.util.lang.WicketObjects; import org.apache.wicket.proxy.IProxyTargetLocator; -import org.apache.wicket.proxy.LazyInitProxyFactory; import org.apache.wicket.util.io.IClusterable; /** @@ -50,6 +49,6 @@ class ObjenesisProxyReplacement implements IClusterable "] with the currently configured org.apache.wicket.application.IClassResolver"); throw new WicketRuntimeException(cause); } - return ObjenesisProxyFactory.createProxy(clazz, locator, LazyInitProxyFactory.WicketNamingPolicy.INSTANCE); + return ObjenesisProxyFactory.createProxy(clazz, locator); } } diff --git a/wicket-ioc/src/main/java/org/apache/wicket/proxy/cglib/CglibProxyFactory.java b/wicket-ioc/src/main/java/org/apache/wicket/proxy/cglib/CglibProxyFactory.java new file mode 100644 index 0000000..2cc8be7 --- /dev/null +++ b/wicket-ioc/src/main/java/org/apache/wicket/proxy/cglib/CglibProxyFactory.java @@ -0,0 +1,155 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.proxy.cglib; + +import java.io.Serializable; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import org.apache.wicket.Application; +import org.apache.wicket.proxy.ILazyInitProxy; +import org.apache.wicket.proxy.IProxyFactory; +import org.apache.wicket.proxy.IProxyTargetLocator; +import org.apache.wicket.proxy.LazyInitProxyFactory.CGLibInterceptor; +import org.apache.wicket.proxy.LazyInitProxyFactory.IWriteReplace; +import org.apache.wicket.proxy.LazyInitProxyFactory.SerializableNoOpCallback; +import org.apache.wicket.proxy.LazyInitProxyFactory.WicketNamingPolicy; +import org.apache.wicket.proxy.objenesis.ObjenesisProxyFactory; + +import net.sf.cglib.proxy.Callback; +import net.sf.cglib.proxy.CallbackFilter; +import net.sf.cglib.proxy.Enhancer; + +/** + * A factory class that creates cglib proxies. + */ +public class CglibProxyFactory implements IProxyFactory +{ + private static final int CGLIB_CALLBACK_NO_OVERRIDE = 0; + private static final int CGLIB_CALLBACK_HANDLER = 1; + + private static final boolean IS_OBJENESIS_AVAILABLE = isObjenesisAvailable(); + + /** + * Create a lazy init proxy for the specified type. The target object will be located using the + * provided locator upon first method invocation. + * + * @param type + * type that proxy will represent + * + * @param locator + * object locator that will locate the object the proxy represents + * + * @return lazily initializable proxy + */ + @Override + public Object createProxy(final Class<?> type, final IProxyTargetLocator locator) + { + if (IS_OBJENESIS_AVAILABLE && !hasNoArgConstructor(type)) + { + return ObjenesisProxyFactory.createProxy(type, locator, WicketNamingPolicy.INSTANCE); + } + else + { + CGLibInterceptor handler = new CGLibInterceptor(type, locator); + + Callback[] callbacks = new Callback[2]; + callbacks[CGLIB_CALLBACK_NO_OVERRIDE] = SerializableNoOpCallback.INSTANCE; + callbacks[CGLIB_CALLBACK_HANDLER] = handler; + + Enhancer e = new Enhancer(); + e.setClassLoader(resolveClassLoader()); + e.setInterfaces(new Class[] { Serializable.class, ILazyInitProxy.class, + IWriteReplace.class }); + e.setSuperclass(type); + e.setCallbackFilter(NoOpForProtectedMethodsCGLibCallbackFilter.INSTANCE); + e.setCallbacks(callbacks); + e.setNamingPolicy(WicketNamingPolicy.INSTANCE); + + return e.create(); + } + } + + private static ClassLoader resolveClassLoader() + { + ClassLoader classLoader = null; + if (Application.exists()) + { + classLoader = Application.get().getApplicationSettings() + .getClassResolver().getClassLoader(); + } + + if (classLoader == null) { + classLoader = Thread.currentThread().getContextClassLoader(); + } + + return classLoader; + } + + /** + * CGLib callback filter which does not intercept protected methods. + * + * Protected methods need to be called with invokeSuper() instead of invoke(). + * When invoke() is called on a protected method, it throws an "IllegalArgumentException: + * Protected method" exception. + * That being said, we do not need to intercept the protected methods so this callback filter + * is designed to use a NoOp callback for protected methods. + * + * @see <a href="http://comments.gmane.org/gmane.comp.java.cglib.devel/720">Discussion about + * this very issue in Spring AOP</a> + * @see <a href="https://github.com/wicketstuff/core/wiki/SpringReference">The WicketStuff + * SpringReference project which worked around this issue</a> + */ + private static class NoOpForProtectedMethodsCGLibCallbackFilter implements CallbackFilter + { + private static final CallbackFilter INSTANCE = new NoOpForProtectedMethodsCGLibCallbackFilter(); + + @Override + public int accept(Method method) { + if (Modifier.isProtected(method.getModifiers())) + { + return CGLIB_CALLBACK_NO_OVERRIDE; + } + else + { + return CGLIB_CALLBACK_HANDLER; + } + } + } + + private static boolean hasNoArgConstructor(Class<?> type) + { + for (Constructor<?> constructor : type.getDeclaredConstructors()) + { + if (constructor.getParameterTypes().length == 0) + return true; + } + + return false; + } + + private static boolean isObjenesisAvailable() + { + try { + Class.forName("org.objenesis.ObjenesisStd"); + return true; + } catch (Exception ignored) { + return false; + } + } +} diff --git a/wicket-ioc/src/main/java/org/apache/wicket/proxy/jdk/JdkProxyFactory.java b/wicket-ioc/src/main/java/org/apache/wicket/proxy/jdk/JdkProxyFactory.java new file mode 100644 index 0000000..66ecda0 --- /dev/null +++ b/wicket-ioc/src/main/java/org/apache/wicket/proxy/jdk/JdkProxyFactory.java @@ -0,0 +1,196 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.proxy.jdk; + +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +import org.apache.wicket.Application; +import org.apache.wicket.proxy.ILazyInitProxy; +import org.apache.wicket.proxy.IProxyTargetLocator; +import org.apache.wicket.proxy.LazyInitProxyFactory; +import org.apache.wicket.proxy.LazyInitProxyFactory.IWriteReplace; +import org.apache.wicket.proxy.LazyInitProxyFactory.ProxyReplacement; + +/** + * A factory class that creates jdk dynamic proxies. + */ +public class JdkProxyFactory +{ + /** + * Create a lazy init proxy for the specified type. The target object will be located using the + * provided locator upon first method invocation. + * + * @param type + * type that proxy will represent + * + * @param locator + * object locator that will locate the object the proxy represents + * + * @return lazily initializable proxy + */ + public Object createProxy(final Class<?> type, final IProxyTargetLocator locator) + { + JdkHandler handler = new JdkHandler(type, locator); + + try + { + return Proxy.newProxyInstance(resolveClassLoader(), + new Class[] { type, Serializable.class, ILazyInitProxy.class, + IWriteReplace.class }, handler); + } + catch (IllegalArgumentException e) + { + /* + * STW: In some clustering environments it appears the context classloader fails to + * load the proxied interface (currently seen in BEA WLS 9.x clusters). If this + * happens, we can try and fall back to the classloader (current) that actually + * loaded this class. + */ + return Proxy.newProxyInstance(LazyInitProxyFactory.class.getClassLoader(), + new Class[] { type, Serializable.class, ILazyInitProxy.class, + IWriteReplace.class }, handler); + } + } + + private ClassLoader resolveClassLoader() + { + ClassLoader classLoader = null; + if (Application.exists()) + { + classLoader = Application.get().getApplicationSettings() + .getClassResolver().getClassLoader(); + } + + if (classLoader == null) { + classLoader = Thread.currentThread().getContextClassLoader(); + } + + return classLoader; + } + + /** + * Invocation handler for proxies representing interface based object. For interface backed + * objects dynamic jdk proxies are used. + * + * @author Igor Vaynberg (ivaynberg) + * + */ + private static class JdkHandler + implements + InvocationHandler, + ILazyInitProxy, + Serializable, + IWriteReplace + { + private static final long serialVersionUID = 1L; + + private final IProxyTargetLocator locator; + + private final String typeName; + + private transient Object target; + + /** + * Constructor + * + * @param type + * class of object this handler will represent + * + * @param locator + * object locator used to locate the object this proxy represents + */ + public JdkHandler(final Class<?> type, final IProxyTargetLocator locator) + { + super(); + this.locator = locator; + typeName = type.getName(); + } + + /** + * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, + * java.lang.reflect.Method, java.lang.Object[]) + */ + @Override + public Object invoke(final Object proxy, final Method method, final Object[] args) + throws Throwable + { + if (LazyInitProxyFactory.isFinalizeMethod(method)) + { + // swallow finalize call + return null; + } + else if (LazyInitProxyFactory.isEqualsMethod(method)) + { + return (equals(args[0])) ? Boolean.TRUE : Boolean.FALSE; + } + else if (LazyInitProxyFactory.isHashCodeMethod(method)) + { + return hashCode(); + } + else if (LazyInitProxyFactory.isToStringMethod(method)) + { + return toString(); + } + else if (method.getDeclaringClass().equals(ILazyInitProxy.class)) + { + return getObjectLocator(); + } + else if (LazyInitProxyFactory.isWriteReplaceMethod(method)) + { + return writeReplace(); + } + + if (target == null) + { + + target = locator.locateProxyTarget(); + } + try + { + method.setAccessible(true); + return method.invoke(target, args); + } + catch (InvocationTargetException e) + { + throw e.getTargetException(); + } + } + + /** + * @see org.apache.wicket.proxy.ILazyInitProxy#getObjectLocator() + */ + @Override + public IProxyTargetLocator getObjectLocator() + { + return locator; + } + + /** + * @see org.apache.wicket.proxy.LazyInitProxyFactory.IWriteReplace#writeReplace() + */ + @Override + public Object writeReplace() throws ObjectStreamException + { + return new ProxyReplacement(typeName, locator); + } + } +} \ No newline at end of file diff --git a/wicket-ioc/src/main/java/org/apache/wicket/proxy/objenesis/ObjenesisCGLibInterceptor.java b/wicket-ioc/src/main/java/org/apache/wicket/proxy/objenesis/ObjenesisCGLibInterceptor.java index 63975a0..d21e011 100644 --- a/wicket-ioc/src/main/java/org/apache/wicket/proxy/objenesis/ObjenesisCGLibInterceptor.java +++ b/wicket-ioc/src/main/java/org/apache/wicket/proxy/objenesis/ObjenesisCGLibInterceptor.java @@ -19,13 +19,13 @@ package org.apache.wicket.proxy.objenesis; import java.io.ObjectStreamException; import org.apache.wicket.proxy.IProxyTargetLocator; -import org.apache.wicket.proxy.LazyInitProxyFactory; +import org.apache.wicket.proxy.LazyInitProxyFactory.AbstractCGLibInterceptor; /** * Method interceptor for proxies representing concrete object not backed by an interface. These * proxies are representing by cglib proxies. */ -public class ObjenesisCGLibInterceptor extends LazyInitProxyFactory.AbstractCGLibInterceptor +public class ObjenesisCGLibInterceptor extends AbstractCGLibInterceptor { public ObjenesisCGLibInterceptor(Class<?> type, IProxyTargetLocator locator) { super(type, locator); diff --git a/wicket-ioc/src/main/java/org/apache/wicket/proxy/objenesis/ObjenesisProxyReplacement.java b/wicket-ioc/src/main/java/org/apache/wicket/proxy/objenesis/ObjenesisProxyReplacement.java index cbffee8..fc8f22d 100644 --- a/wicket-ioc/src/main/java/org/apache/wicket/proxy/objenesis/ObjenesisProxyReplacement.java +++ b/wicket-ioc/src/main/java/org/apache/wicket/proxy/objenesis/ObjenesisProxyReplacement.java @@ -21,7 +21,7 @@ import java.io.ObjectStreamException; import org.apache.wicket.WicketRuntimeException; import org.apache.wicket.core.util.lang.WicketObjects; import org.apache.wicket.proxy.IProxyTargetLocator; -import org.apache.wicket.proxy.LazyInitProxyFactory; +import org.apache.wicket.proxy.LazyInitProxyFactory.WicketNamingPolicy; import org.apache.wicket.util.io.IClusterable; /** @@ -50,6 +50,6 @@ class ObjenesisProxyReplacement implements IClusterable "] with the currently configured org.apache.wicket.application.IClassResolver"); throw new WicketRuntimeException(cause); } - return ObjenesisProxyFactory.createProxy(clazz, locator, LazyInitProxyFactory.WicketNamingPolicy.INSTANCE); + return ObjenesisProxyFactory.createProxy(clazz, locator, WicketNamingPolicy.INSTANCE); } } diff --git a/wicket-ioc/src/test/java/org/apache/wicket/injection/util/MockDependency.java b/wicket-ioc/src/test/java/org/apache/wicket/injection/util/MockDependency.java index cc22135..6afeecc 100644 --- a/wicket-ioc/src/test/java/org/apache/wicket/injection/util/MockDependency.java +++ b/wicket-ioc/src/test/java/org/apache/wicket/injection/util/MockDependency.java @@ -16,6 +16,8 @@ */ package org.apache.wicket.injection.util; +import org.apache.wicket.proxy.LazyInitProxyFactory; + /** * Mock dependency that does not implement an interface * @@ -27,7 +29,8 @@ public class MockDependency private String message; /** - * Empty default constructor. It is required by cglib to create a proxy. + * Empty default constructor. It is required by {@link LazyInitProxyFactory} + * to create a proxy. */ public MockDependency() { diff --git a/wicket-spring/src/test/java/org/apache/wicket/spring/injection/annot/SpringBeanWithGenericsTest.java b/wicket-spring/src/test/java/org/apache/wicket/spring/injection/annot/SpringBeanWithGenericsTest.java index 653a93c..ac743c1 100644 --- a/wicket-spring/src/test/java/org/apache/wicket/spring/injection/annot/SpringBeanWithGenericsTest.java +++ b/wicket-spring/src/test/java/org/apache/wicket/spring/injection/annot/SpringBeanWithGenericsTest.java @@ -290,7 +290,7 @@ class SpringBeanWithGenericsTest @Bean public List<String> stringsList() { - return Arrays.asList("foo", "bar", "baz"); + return List.of("foo", "bar", "baz"); } @Bean
