This is an automated email from the ASF dual-hosted git repository.
mgrigorov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/wicket.git
The following commit(s) were added to refs/heads/master by this push:
new 8cfffea WICKET-6913 Replace CGLib with ByteBuddy (#476)
8cfffea is described below
commit 8cfffea6441153a2c59700e4db30d71857fd0cbe
Author: Martin Grigorov <[email protected]>
AuthorDate: Mon Aug 16 14:47:57 2021 +0300
WICKET-6913 Replace CGLib with ByteBuddy (#476)
* WICKET-6913 Replace CGLib with ByteBuddy in LazyInitProxyFactory
TODO: Update the Objenesis related classes too and wicket-jmx
(cherry picked from commit 8e1a15b3c08a59cc21c285440d1bf4d3b1876419)
* WICKET-6913 Convert Objenesis proxy generator to ByteBuddy
(cherry picked from commit 43f040e1ffc2ea03a458cb74aca186e2692e63e8)
* WICKET-6913 Replace CGLib with ByteBuddy
Replace all occurrences of "cglib" with "byte-buddy".
Merge AbstractByteBuddyInterceptor and ByteBuddyInterceptor. I see no need
of both. If an application needs special impl of #writeReplace() then it could
extend ByteBuddyInterceptor and override it.
Improve Maven dependency management related to byte-buddy.
* WICKET-6913 Set the ByteBuddy interceptor after creating an instance
This is needed because otherwise we may get a cached generated class with
wrong interceptor (i.e. IProxyTargetLocator) for classes with generics
* WICKET-6913 Fix typos in javadoc
---
NOTICE | 8 +-
README.md | 4 +-
pom.xml | 12 +-
wicket-examples/src/main/resources/META-INF/NOTICE | 10 +-
wicket-ioc/pom.xml | 8 +-
wicket-ioc/src/main/java/module-info.java | 2 +-
.../apache/wicket/proxy/LazyInitProxyFactory.java | 238 ++++++++++-----------
...tor.java => ObjenesisByteBuddyInterceptor.java} | 8 +-
.../proxy/objenesis/ObjenesisProxyFactory.java | 28 +--
.../proxy/objenesis/ObjenesisProxyReplacement.java | 2 +-
.../wicket/injection/util/MockDependency.java | 2 +-
.../wicket/proxy/LazyInitProxyFactoryTest.java | 51 +++--
.../wicket/proxy/PackagePrivateConcreteObject.java | 2 +-
.../apache/wicket/proxy/util/ConcreteObject.java | 2 +-
wicket-jmx/pom.xml | 4 +-
wicket-jmx/src/main/java/module-info.java | 2 +-
.../java/org/apache/wicket/jmx/Initializer.java | 130 +++++++----
.../org/apache/wicket/jmx/wrapper/Application.java | 21 --
.../wicket/jmx/wrapper/ApplicationSettings.java | 9 -
.../annot/SpringBeanWithGenericsTest.java | 2 +-
20 files changed, 268 insertions(+), 277 deletions(-)
diff --git a/NOTICE b/NOTICE
index 3e462db..b212522 100644
--- a/NOTICE
+++ b/NOTICE
@@ -53,11 +53,11 @@ src/./wicket-examples
This product includes software developed by the Spring Framework Project
(http://www.springframework.org).
- This product includes software developed by the CGLib Project
- (http://cglib.sourceforge.net).
+ This product includes software developed by the ByteBuddy Project
+ (https://bytebuddy.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 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..32b9555 100644
--- a/README.md
+++ b/README.md
@@ -158,8 +158,8 @@ the src/ folder.
- wicket-ioc:
- cglib 3.1 (http://cglib.sourceforge.net/) and
- asm-util 5.0.3 (http://asm.objectweb.org/)
+ byte-buddy 1.11.12 (https://bytebuddy.net/) and
+ asm-util 9.1 (https://asm.ow2.io/)
- wicket-spring:
diff --git a/pom.xml b/pom.xml
index 689a079..5e7a2b4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -137,8 +137,8 @@
<asm.version>9.1</asm.version>
<aspectj.version>1.9.6</aspectj.version>
<assertj-core.version>3.19.0</assertj-core.version>
+ <byte-buddy.version>1.11.12</byte-buddy.version>
<cdi-unit.version>4.1.0</cdi-unit.version>
- <cglib.version>3.3.0</cglib.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>
@@ -259,11 +259,6 @@
<scope>provided</scope>
</dependency>
<dependency>
- <groupId>cglib</groupId>
- <artifactId>cglib</artifactId>
- <version>${cglib.version}</version>
- </dependency>
- <dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
@@ -323,6 +318,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..08cc74b 100644
--- a/wicket-examples/src/main/resources/META-INF/NOTICE
+++ b/wicket-examples/src/main/resources/META-INF/NOTICE
@@ -26,11 +26,11 @@
This product includes software developed by the Spring Framework Project
(http://www.springframework.org).
- This product includes software developed by the CGLib Project
- (http://cglib.sourceforge.net).
+ This product includes software developed by the ByteBiddy Project
+ (https://bytebuddy.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 jhighlight (https://jhighlight.dev.java.net/)
which is released under CDDL 1.0 license
(http://www.opensource.org/licenses/cddl1.php).
@@ -42,4 +42,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 a7da8d9..6e3697a 100644
--- a/wicket-ioc/pom.xml
+++ b/wicket-ioc/pom.xml
@@ -33,14 +33,14 @@
<dependencies>
<dependency>
- <groupId>cglib</groupId>
- <artifactId>cglib</artifactId>
- </dependency>
- <dependency>
<groupId>jakarta.inject</groupId>
<artifactId>jakarta.inject-api</artifactId>
</dependency>
<dependency>
+ <groupId>net.bytebuddy</groupId>
+ <artifactId>byte-buddy</artifactId>
+ </dependency>
+ <dependency>
<groupId>org.apache.wicket</groupId>
<artifactId>wicket-core</artifactId>
<version>${project.version}</version>
diff --git a/wicket-ioc/src/main/java/module-info.java
b/wicket-ioc/src/main/java/module-info.java
index 6f7f7e1..b9814fe 100644
--- a/wicket-ioc/src/main/java/module-info.java
+++ b/wicket-ioc/src/main/java/module-info.java
@@ -18,7 +18,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/org/apache/wicket/proxy/LazyInitProxyFactory.java
b/wicket-ioc/src/main/java/org/apache/wicket/proxy/LazyInitProxyFactory.java
index ccc7769..3e33b74 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
@@ -22,19 +22,22 @@ 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 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 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.RuntimeType;
+import net.bytebuddy.matcher.ElementMatchers;
import org.apache.wicket.Application;
import org.apache.wicket.WicketRuntimeException;
@@ -42,7 +45,6 @@ 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}
@@ -53,7 +55,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,14 +114,19 @@ 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;
+ /**
+ * 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();
@@ -169,29 +176,43 @@ public class LazyInitProxyFactory
}
else if (IS_OBJENESIS_AVAILABLE && !hasNoArgConstructor(type))
{
- return ObjenesisProxyFactory.createProxy(type, locator,
WicketNamingPolicy.INSTANCE);
+ return ObjenesisProxyFactory.createProxy(type, locator);
}
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();
+ 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)
+ .implement(Serializable.class,
ILazyInitProxy.class, IWriteReplace.class)
+ .method(ElementMatchers.any())
+
.intercept(MethodDelegation.toField("interceptor"))
+ .defineField("interceptor",
ByteBuddyInterceptor.class, Visibility.PRIVATE)
+
.implement(InterceptorMutator.class).intercept(FieldAccessor.ofBeanProperty())
+ .make()
+ .load(classLoader,
ClassLoadingStrategy.Default.INJECTION)
+ .getLoaded());
+ }
+
private static ClassLoader resolveClassLoader()
{
ClassLoader classLoader = null;
@@ -286,15 +307,30 @@ public class LazyInitProxyFactory
}
/**
- * Method interceptor for proxies representing concrete object not
backed by an interface. These
- * proxies are represented by cglib proxies.
+ * 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 abstract static class AbstractCGLibInterceptor
+ public static class ByteBuddyInterceptor
implements
- MethodInterceptor,
ILazyInitProxy,
Serializable,
IWriteReplace
@@ -316,20 +352,17 @@ public class LazyInitProxyFactory
* @param locator
* object locator used to locate the object this
proxy represents
*/
- public AbstractCGLibInterceptor(final Class<?> type, final
IProxyTargetLocator locator)
+ public ByteBuddyInterceptor(final Class<?> type, final
IProxyTargetLocator locator)
{
super();
typeName = type.getName();
this.locator = locator;
}
- /**
- * @see
net.sf.cglib.proxy.MethodInterceptor#intercept(java.lang.Object,
- * java.lang.reflect.Method, java.lang.Object[],
net.sf.cglib.proxy.MethodProxy)
- */
- @Override
- public Object intercept(final Object object, final Method
method, final Object[] args,
- final MethodProxy proxy) throws Throwable
+ @RuntimeType
+ public Object intercept(final @Origin Method method,
+ final
@AllArguments Object[] args)
+ throws Exception
{
if (isFinalizeMethod(method))
{
@@ -361,35 +394,16 @@ public class LazyInitProxyFactory
{
target = locator.locateProxyTarget();
}
- return proxy.invoke(target, args);
+
+ return method.invoke(target, args);
}
- /**
- * @see
org.apache.wicket.proxy.ILazyInitProxy#getObjectLocator()
- */
@Override
public IProxyTargetLocator getObjectLocator()
{
return locator;
}
- }
- /**
- * Method interceptor for proxies representing concrete object not
backed by an interface. These
- * proxies are representing by cglib proxies.
- *
- * @author Igor Vaynberg (ivaynberg)
- */
- protected 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
{
@@ -398,47 +412,6 @@ public class LazyInitProxyFactory
}
/**
- * Serializable implementation of the NoOp callback.
- */
- public static class SerializableNoOpCallback implements NoOp,
Serializable
- {
- 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.
*
@@ -476,10 +449,6 @@ public class LazyInitProxyFactory
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
@@ -526,18 +495,12 @@ public class LazyInitProxyFactory
}
}
- /**
- * @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
{
@@ -611,24 +574,49 @@ public class LazyInitProxyFactory
(method.getParameterTypes().length == 0) &&
method.getName().equals("writeReplace");
}
- public static final class WicketNamingPolicy extends DefaultNamingPolicy
+ /**
+ * 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 WicketNamingPolicy INSTANCE = new
WicketNamingPolicy();
+ public static final WicketNamingStrategy INSTANCE = new
WicketNamingStrategy();
- private WicketNamingPolicy()
+ private WicketNamingStrategy()
{
super();
}
@Override
- public String getClassName(final String prefix, final String
source, final Object key,
- final Predicate names)
- {
+ 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 newPrefix = packageName + ".Wicket_Proxy_" +
className;
- return super.getClassName(newPrefix, source, key,
names);
+ 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();
}
}
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/ObjenesisByteBuddyInterceptor.java
similarity index 82%
rename from
wicket-ioc/src/main/java/org/apache/wicket/proxy/objenesis/ObjenesisCGLibInterceptor.java
rename to
wicket-ioc/src/main/java/org/apache/wicket/proxy/objenesis/ObjenesisByteBuddyInterceptor.java
index 63975a0..e2bdbff 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/ObjenesisByteBuddyInterceptor.java
@@ -22,12 +22,12 @@ 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
LazyInitProxyFactory.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/ObjenesisProxyFactory.java
b/wicket-ioc/src/main/java/org/apache/wicket/proxy/objenesis/ObjenesisProxyFactory.java
index 730da6b..b29ca81 100644
---
a/wicket-ioc/src/main/java/org/apache/wicket/proxy/objenesis/ObjenesisProxyFactory.java
+++
b/wicket-ioc/src/main/java/org/apache/wicket/proxy/objenesis/ObjenesisProxyFactory.java
@@ -16,38 +16,20 @@
*/
package org.apache.wicket.proxy.objenesis;
-import java.io.Serializable;
-
-import org.apache.wicket.proxy.ILazyInitProxy;
import org.apache.wicket.proxy.IProxyTargetLocator;
-import org.apache.wicket.proxy.LazyInitProxyFactory.IWriteReplace;
+import org.apache.wicket.proxy.LazyInitProxyFactory;
import org.objenesis.ObjenesisStd;
-import net.sf.cglib.core.NamingPolicy;
-import net.sf.cglib.proxy.Callback;
-import net.sf.cglib.proxy.Enhancer;
-import net.sf.cglib.proxy.Factory;
-
public class ObjenesisProxyFactory
{
private static final ObjenesisStd OBJENESIS = new ObjenesisStd(false);
- public static Object createProxy(final Class<?> type, final
IProxyTargetLocator locator, NamingPolicy namingPolicy)
+ public static Object createProxy(final Class<?> type, final
IProxyTargetLocator locator)
{
- ObjenesisCGLibInterceptor handler = new
ObjenesisCGLibInterceptor(type, locator);
-
- Enhancer e = new Enhancer();
- e.setInterfaces(new Class[]{Serializable.class,
ILazyInitProxy.class, IWriteReplace.class});
- e.setSuperclass(type);
- e.setCallbackType(handler.getClass());
- e.setNamingPolicy(namingPolicy);
- Class<?> proxyClass = e.createClass();
-
+ Class<?> proxyClass =
LazyInitProxyFactory.createOrGetProxyClass(type);
Object instance = OBJENESIS.newInstance(proxyClass);
-
- // set callbacks directly (WICKET-6607)
- ((Factory) instance).setCallbacks(new Callback[]{handler});
-
+ ObjenesisByteBuddyInterceptor interceptor = new
ObjenesisByteBuddyInterceptor(type, locator);
+ ((LazyInitProxyFactory.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/objenesis/ObjenesisProxyReplacement.java
index cbffee8..f51258c 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
@@ -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);
}
}
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..70daa3b 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
@@ -27,7 +27,7 @@ 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 byte-buddy to create a
proxy.
*/
public MockDependency()
{
diff --git
a/wicket-ioc/src/test/java/org/apache/wicket/proxy/LazyInitProxyFactoryTest.java
b/wicket-ioc/src/test/java/org/apache/wicket/proxy/LazyInitProxyFactoryTest.java
index 5483ce4..6b907d2 100644
---
a/wicket-ioc/src/test/java/org/apache/wicket/proxy/LazyInitProxyFactoryTest.java
+++
b/wicket-ioc/src/test/java/org/apache/wicket/proxy/LazyInitProxyFactoryTest.java
@@ -25,6 +25,7 @@ import org.apache.wicket.proxy.util.InterfaceObject;
import org.apache.wicket.proxy.util.ObjectMethodTester;
import org.junit.jupiter.api.Test;
+import java.io.ObjectStreamException;
import java.lang.reflect.Proxy;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -39,11 +40,11 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
* @author Igor Vaynberg (ivaynberg)
*
*/
-public class LazyInitProxyFactoryTest
+class LazyInitProxyFactoryTest
{
private static InterfaceObject interfaceObject = new
InterfaceObject("interface");
- private static ConcreteObject concreteObject = new
ConcreteObject("concrete");
+ private static final ConcreteObject concreteObject = new
ConcreteObject("concrete");
private static final PackagePrivateConcreteObject
PACKAGE_PRIVATE_CONCRETE_OBJECT = new
PackagePrivateConcreteObject("package-private-concrete");
@@ -58,7 +59,7 @@ public class LazyInitProxyFactoryTest
}
};
- private static IProxyTargetLocator concreteObjectLocator = new
IProxyTargetLocator()
+ private static final IProxyTargetLocator concreteObjectLocator = new
IProxyTargetLocator()
{
private static final long serialVersionUID = 1L;
@@ -67,6 +68,11 @@ public class LazyInitProxyFactoryTest
{
return LazyInitProxyFactoryTest.concreteObject;
}
+
+ // This method is needed to prevent (de)serialization of this
locator instance in #testByteBuddyInterceptorReplacement()
+ private Object readResolve() throws ObjectStreamException {
+ return concreteObjectLocator;
+ }
};
private final static IProxyTargetLocator
PACKAGE_PRIVATE_CONCRETE_OBJECT_LOCATOR = new IProxyTargetLocator()
@@ -95,7 +101,7 @@ public class LazyInitProxyFactoryTest
* Tests lazy init proxy to represent interfaces
*/
@Test
- public void testInterfaceProxy()
+ void testInterfaceProxy()
{
// test proxy creation for an interface class
IInterface proxy =
(IInterface)LazyInitProxyFactory.createProxy(IInterface.class,
@@ -106,15 +112,15 @@ public class LazyInitProxyFactoryTest
// test proxy implements ILazyInitProxy
assertTrue(proxy instanceof ILazyInitProxy);
- assertTrue(((ILazyInitProxy)proxy).getObjectLocator() ==
interfaceObjectLocator);
+ assertSame(((ILazyInitProxy) proxy).getObjectLocator(),
interfaceObjectLocator);
// test method invocation
- assertEquals(proxy.getMessage(), "interface");
+ assertEquals("interface", proxy.getMessage());
// test serialization
IInterface proxy2 = WicketObjects.cloneObject(proxy);
- assertTrue(proxy != proxy2);
- assertEquals(proxy2.getMessage(), "interface");
+ assertNotSame(proxy, proxy2);
+ assertEquals("interface", proxy2.getMessage());
// test equals/hashcode method interception
final IObjectMethodTester tester = new ObjectMethodTester();
@@ -143,32 +149,33 @@ public class LazyInitProxyFactoryTest
* Tests lazy init proxy to represent concrete objects
*/
@Test
- public void testConcreteProxy()
+ void testConcreteProxy()
{
ConcreteObject proxy =
(ConcreteObject)LazyInitProxyFactory.createProxy(
ConcreteObject.class, concreteObjectLocator);
// test proxy implements ILazyInitProxy
assertTrue(proxy instanceof ILazyInitProxy);
- assertSame(((ILazyInitProxy) proxy).getObjectLocator(),
concreteObjectLocator);
+ final IProxyTargetLocator objectLocator = ((ILazyInitProxy)
proxy).getObjectLocator();
+ assertSame(objectLocator, concreteObjectLocator);
// test we do not have a jdk dynamic proxy
assertFalse(Proxy.isProxyClass(proxy.getClass()));
// test method invocation
- assertEquals(proxy.getMessage(), "concrete");
+ assertEquals("concrete", proxy.getMessage());
// test serialization
ConcreteObject proxy2 = WicketObjects.cloneObject(proxy);
assertNotSame(proxy, proxy2);
- assertEquals(proxy2.getMessage(), "concrete");
+ assertEquals("concrete", proxy2.getMessage());
// test equals/hashcode method interception
final IObjectMethodTester tester = new ObjectMethodTester();
assertTrue(tester.isValid());
// test only a single class is generated,
- // otherwise permgen space will fill up with each proxy
+ // otherwise meta space will fill up with each proxy
assertSame(proxy.getClass(), LazyInitProxyFactory.createProxy(
ConcreteObject.class,
concreteObjectLocator).getClass());
@@ -197,25 +204,25 @@ public class LazyInitProxyFactoryTest
* https://issues.apache.org/jira/browse/WICKET-4324
*/
@Test
- public void testPackagePrivateConcreteProxy()
+ void testPackagePrivateConcreteProxy()
{
PackagePrivateConcreteObject proxy =
(PackagePrivateConcreteObject)LazyInitProxyFactory.createProxy(
PackagePrivateConcreteObject.class,
PACKAGE_PRIVATE_CONCRETE_OBJECT_LOCATOR);
// test proxy implements ILazyInitProxy
assertTrue(proxy instanceof ILazyInitProxy);
- assertTrue(((ILazyInitProxy)proxy).getObjectLocator() ==
PACKAGE_PRIVATE_CONCRETE_OBJECT_LOCATOR);
+ assertSame(((ILazyInitProxy)proxy).getObjectLocator(),
PACKAGE_PRIVATE_CONCRETE_OBJECT_LOCATOR);
// test we do not have a jdk dynamic proxy
assertFalse(Proxy.isProxyClass(proxy.getClass()));
// test method invocation
- assertEquals(proxy.getMessage(), "package-private-concrete");
+ assertEquals("package-private-concrete", proxy.getMessage());
// test serialization
PackagePrivateConcreteObject proxy2 =
WicketObjects.cloneObject(proxy);
- assertTrue(proxy != proxy2);
- assertEquals(proxy2.getMessage(), "package-private-concrete");
+ assertNotSame(proxy, proxy2);
+ assertEquals("package-private-concrete", proxy2.getMessage());
// test equals/hashcode method interception
final IObjectMethodTester tester = new ObjectMethodTester();
@@ -246,23 +253,23 @@ public class LazyInitProxyFactoryTest
}
/**
- * Tests lazy init concrete replacement replacement
+ * Tests lazy init concrete replacement
*/
@Test
- public void testCGLibInterceptorReplacement()
+ void testByteBuddyInterceptorReplacement()
{
ProxyReplacement ser = new
ProxyReplacement(ConcreteObject.class.getName(),
concreteObjectLocator);
Object proxy2 = WicketObjects.cloneObject(ser);
- assertEquals(((ConcreteObject)proxy2).getMessage(), "concrete");
+ assertEquals("concrete", ((ConcreteObject)proxy2).getMessage());
}
/**
* Tests String beans.
*/
@Test
- public void testStringProxy()
+ void testStringProxy()
{
// We special-case String objects to avoid proxying them, as
they're
// final.
diff --git
a/wicket-ioc/src/test/java/org/apache/wicket/proxy/PackagePrivateConcreteObject.java
b/wicket-ioc/src/test/java/org/apache/wicket/proxy/PackagePrivateConcreteObject.java
index 3b31e63..5f87e29 100644
---
a/wicket-ioc/src/test/java/org/apache/wicket/proxy/PackagePrivateConcreteObject.java
+++
b/wicket-ioc/src/test/java/org/apache/wicket/proxy/PackagePrivateConcreteObject.java
@@ -26,7 +26,7 @@ class PackagePrivateConcreteObject
private String message;
/**
- * Empty default constructor. It is required by cglib to create a proxy.
+ * Empty default constructor. It is required by byte-buddy to create a
proxy.
*/
public PackagePrivateConcreteObject()
{
diff --git
a/wicket-ioc/src/test/java/org/apache/wicket/proxy/util/ConcreteObject.java
b/wicket-ioc/src/test/java/org/apache/wicket/proxy/util/ConcreteObject.java
index e36c269..cb45c47 100644
--- a/wicket-ioc/src/test/java/org/apache/wicket/proxy/util/ConcreteObject.java
+++ b/wicket-ioc/src/test/java/org/apache/wicket/proxy/util/ConcreteObject.java
@@ -27,7 +27,7 @@ public class ConcreteObject
private String message;
/**
- * Empty default constructor. It is required by cglib to create a proxy.
+ * Empty default constructor. It is required by byte-buddy to create a
proxy.
*/
public ConcreteObject()
{
diff --git a/wicket-jmx/pom.xml b/wicket-jmx/pom.xml
index c312f9b..67303ae 100644
--- a/wicket-jmx/pom.xml
+++ b/wicket-jmx/pom.xml
@@ -30,8 +30,8 @@
<dependencies>
<dependency>
- <groupId>cglib</groupId>
- <artifactId>cglib</artifactId>
+ <groupId>net.bytebuddy</groupId>
+ <artifactId>byte-buddy</artifactId>
</dependency>
<dependency>
<groupId>org.apache.wicket</groupId>
diff --git a/wicket-jmx/src/main/java/module-info.java
b/wicket-jmx/src/main/java/module-info.java
index d07942d..a0366f8 100644
--- a/wicket-jmx/src/main/java/module-info.java
+++ b/wicket-jmx/src/main/java/module-info.java
@@ -20,7 +20,7 @@ module org.apache.wicket.jmx {
requires org.apache.wicket.util;
requires org.apache.wicket.core;
requires org.slf4j;
- requires cglib;
+ requires net.bytebuddy;
provides org.apache.wicket.IInitializer with
org.apache.wicket.jmx.Initializer;
exports org.apache.wicket.jmx;
diff --git a/wicket-jmx/src/main/java/org/apache/wicket/jmx/Initializer.java
b/wicket-jmx/src/main/java/org/apache/wicket/jmx/Initializer.java
index ca990ac..a2d9b3d 100644
--- a/wicket-jmx/src/main/java/org/apache/wicket/jmx/Initializer.java
+++ b/wicket-jmx/src/main/java/org/apache/wicket/jmx/Initializer.java
@@ -17,6 +17,7 @@
package org.apache.wicket.jmx;
import java.lang.management.ManagementFactory;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
@@ -30,9 +31,16 @@ import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
-import net.sf.cglib.core.DefaultNamingPolicy;
-import net.sf.cglib.core.Predicate;
-import net.sf.cglib.proxy.Enhancer;
+import net.bytebuddy.ByteBuddy;
+import net.bytebuddy.NamingStrategy;
+import net.bytebuddy.TypeCache;
+import net.bytebuddy.description.type.TypeDescription;
+import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
+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.RuntimeType;
+import net.bytebuddy.matcher.ElementMatchers;
import org.apache.wicket.IInitializer;
import org.apache.wicket.ThreadContext;
@@ -68,7 +76,24 @@ import org.slf4j.LoggerFactory;
*/
public class Initializer implements IInitializer
{
- private static Logger log = LoggerFactory.getLogger(Initializer.class);
+ private static final Logger LOG =
LoggerFactory.getLogger(Initializer.class);
+
+ /**
+ * 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(new NamingStrategy.AbstractBase()
+ {
+ @Override
+ protected String name(TypeDescription
superClass)
+ {
+ return
superClass.getName().replace(".wrapper", "");
+ }
+ });
// It's best to store a reference to the MBeanServer rather than
getting it
// over and over
@@ -90,7 +115,7 @@ public class Initializer implements IInitializer
}
catch (InstanceNotFoundException |
MBeanRegistrationException e)
{
- log.error(e.getMessage(), e);
+ LOG.error(e.getMessage(), e);
}
}
}
@@ -110,7 +135,7 @@ public class Initializer implements IInitializer
catch (SecurityException e)
{
// Ignore - we're not allowed to read this
property.
- log.warn("not allowed to read property
wicket.mbean.server.agentid due to security settings; ignoring");
+ LOG.warn("not allowed to read property
wicket.mbean.server.agentid due to security settings; ignoring");
}
if (agentId != null)
{
@@ -121,7 +146,7 @@ public class Initializer implements IInitializer
}
else
{
- log.error("unable to find mbean server
with agent id " + agentId);
+ LOG.error("unable to find mbean server
with agent id {}", agentId);
}
}
if (mbeanServer == null)
@@ -134,7 +159,7 @@ public class Initializer implements IInitializer
catch (SecurityException e)
{
// Ignore - we're not allowed to read
this property.
- log.warn("not allowed to read property
wicket.mbean.server.class due to security settings; ignoring");
+ LOG.warn("not allowed to read property
wicket.mbean.server.class due to security settings; ignoring");
}
if (impl != null)
{
@@ -152,7 +177,7 @@ public class Initializer implements IInitializer
}
if (mbeanServer == null)
{
- log.error("unable to find mbean
server of type '{}'", impl);
+ LOG.error("unable to find mbean
server of type '{}'", impl);
}
}
}
@@ -162,7 +187,7 @@ public class Initializer implements IInitializer
// never null
}
- log.info("registering Wicket mbeans with server '{}'",
mbeanServer);
+ LOG.info("registering Wicket mbeans with server '{}'",
mbeanServer);
// register top level application object, but first
check whether
// multiple instances of the same application (name)
are running and
@@ -238,48 +263,67 @@ public class Initializer implements IInitializer
registered.add(objectName);
}
- private Object createProxy(final org.apache.wicket.Application
application, final Object o)
+ private static class Interceptor
{
- Enhancer e = new Enhancer();
- e.setInterfaces(o.getClass().getInterfaces());
- e.setSuperclass(Object.class);
- e.setCallback(new net.sf.cglib.proxy.InvocationHandler()
+ private final org.apache.wicket.Application application;
+ private final Object object;
+
+ private Interceptor(org.apache.wicket.Application application,
Object object) {
+ this.application = application;
+ this.object = object;
+ }
+
+ @RuntimeType
+ public Object intercept(final @Origin Method method,
+ final
@AllArguments Object[] args)
+ throws Throwable
{
- @Override
- public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable
+ boolean existed = ThreadContext.exists();
+
+ if (existed == false)
{
- boolean existed = ThreadContext.exists();
+ ThreadContext.setApplication(application);
+ }
+ try
+ {
+ return method.invoke(object, args);
+ }
+ finally
+ {
if (existed == false)
{
-
ThreadContext.setApplication(application);
- }
-
- try
- {
- return method.invoke(o, args);
+ ThreadContext.detach();
}
- finally
- {
- if (existed == false)
- {
- ThreadContext.detach();
- }
- }
- }
- });
- e.setNamingPolicy(new DefaultNamingPolicy()
- {
- @Override
- public String getClassName(final String prefix, final
String source, final Object key,
- final Predicate names)
- {
- return
o.getClass().getName().replace(".wrapper", "");
}
- });
- e.setClassLoader(resolveClassLoader());
+ }
+ }
+
+ private Object createProxy(final org.apache.wicket.Application
application, final Object o)
+ {
+ Class<?> type = o.getClass();
+ ClassLoader classLoader = resolveClassLoader();
+
+ Class<?> proxyClass =
DYNAMIC_CLASS_CACHE.findOrInsert(classLoader,
+ new TypeCache.SimpleKey(type),
+ () -> BYTE_BUDDY
+ .subclass(type)
+ .implement(type.getInterfaces())
+ .method(ElementMatchers.any())
+
.intercept(MethodDelegation.to(new Interceptor(application, o)))
+ .make()
+ .load(classLoader,
ClassLoadingStrategy.Default.INJECTION)
+ .getLoaded());
- return e.create();
+
+ try
+ {
+ return
proxyClass.getDeclaredConstructor(org.apache.wicket.Application.class).newInstance(application);
+ }
+ catch (InstantiationException | IllegalAccessException |
InvocationTargetException | NoSuchMethodException e)
+ {
+ throw new WicketRuntimeException(e);
+ }
}
private static ClassLoader resolveClassLoader()
diff --git
a/wicket-jmx/src/main/java/org/apache/wicket/jmx/wrapper/Application.java
b/wicket-jmx/src/main/java/org/apache/wicket/jmx/wrapper/Application.java
index 56e0eff..3d23047 100644
--- a/wicket-jmx/src/main/java/org/apache/wicket/jmx/wrapper/Application.java
+++ b/wicket-jmx/src/main/java/org/apache/wicket/jmx/wrapper/Application.java
@@ -39,63 +39,42 @@ public class Application implements ApplicationMBean
this.application = application;
}
- /**
- * @see org.apache.wicket.jmx.ApplicationMBean#clearMarkupCache()
- */
@Override
public void clearMarkupCache() throws IOException
{
application.getMarkupSettings().getMarkupFactory().getMarkupCache().clear();
}
- /**
- * @see org.apache.wicket.jmx.ApplicationMBean#getApplicationClass()
- */
@Override
public String getApplicationClass() throws IOException
{
return application.getClass().getName();
}
- /**
- * @see org.apache.wicket.jmx.ApplicationMBean#getConfigurationType()
- */
@Override
public String getConfigurationType()
{
return application.getConfigurationType().name();
}
- /**
- * @see org.apache.wicket.jmx.ApplicationMBean#getHomePageClass()
- */
@Override
public String getHomePageClass() throws IOException
{
return application.getHomePage().getName();
}
- /**
- * @see org.apache.wicket.jmx.ApplicationMBean#getMarkupCacheSize()
- */
@Override
public int getMarkupCacheSize() throws IOException
{
return
application.getMarkupSettings().getMarkupFactory().getMarkupCache().size();
}
- /**
- * @see org.apache.wicket.jmx.ApplicationMBean#getWicketVersion()
- */
@Override
public String getWicketVersion() throws IOException
{
return application.getFrameworkSettings().getVersion();
}
- /**
- * @see org.apache.wicket.jmx.ApplicationMBean#clearLocalizerCache()
- */
@Override
public void clearLocalizerCache() throws IOException
{
diff --git
a/wicket-jmx/src/main/java/org/apache/wicket/jmx/wrapper/ApplicationSettings.java
b/wicket-jmx/src/main/java/org/apache/wicket/jmx/wrapper/ApplicationSettings.java
index a6a0d4c..c5bda35 100644
---
a/wicket-jmx/src/main/java/org/apache/wicket/jmx/wrapper/ApplicationSettings.java
+++
b/wicket-jmx/src/main/java/org/apache/wicket/jmx/wrapper/ApplicationSettings.java
@@ -40,18 +40,12 @@ public class ApplicationSettings implements
ApplicationSettingsMBean
this.application = application;
}
- /**
- * @see
org.apache.wicket.jmx.ApplicationSettingsMBean#getAccessDeniedPage()
- */
@Override
public String getAccessDeniedPage()
{
return
Classes.name(application.getApplicationSettings().getAccessDeniedPage());
}
- /**
- * @see
org.apache.wicket.jmx.ApplicationSettingsMBean#getClassResolver()
- */
@Override
public String getClassResolver()
{
@@ -64,9 +58,6 @@ public class ApplicationSettings implements
ApplicationSettingsMBean
return
application.getApplicationSettings().getDefaultMaximumUploadSize().toString();
}
- /**
- * @see
org.apache.wicket.jmx.ApplicationSettingsMBean#getInternalErrorPage()
- */
@Override
public String getInternalErrorPage()
{
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