[
https://issues.apache.org/jira/browse/WICKET-7204?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18112971#comment-18112971
]
ASF GitHub Bot commented on WICKET-7204:
----------------------------------------
papegaaij commented on code in PR #1577:
URL: https://github.com/apache/wicket/pull/1577#discussion_r3961475632
##########
wicket-ioc/src/main/java/org/apache/wicket/proxy/bytebuddy/ByteBuddyProxyFactory.java:
##########
@@ -17,8 +17,10 @@
package org.apache.wicket.proxy.bytebuddy;
import java.io.Serializable;
+import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
Review Comment:
`Modifier` is not needed once the branch is on the package rather than on
the visibility.
```suggestion
```
##########
wicket-ioc/src/main/java/org/apache/wicket/proxy/bytebuddy/ByteBuddyProxyFactory.java:
##########
@@ -116,10 +120,26 @@ public static <T> Class<T> createOrGetProxyClass(Class<T>
type)
.implement(InterceptorMutator.class).intercept(FieldAccessor.ofBeanProperty())
.implement(Serializable.class,
IWriteReplace.class,
ILazyInitProxy.class).intercept(MethodDelegation.toField(INTERCEPTOR_FIELD_NAME))
.make()
- .load(classLoader,
ClassLoadingStrategy.Default.INJECTION.allowExistingTypes())
+ .load(classLoader,
loadingStrategy)
.getLoaded());
Review Comment:
The monitor argument makes class creation for one `(loader, type)` pair
mutually exclusive. Without it, `UsingLookup` has no `allowExistingTypes()`
equivalent and concurrent first use of a package-private type defines the class
twice — WICKET-7005 again.
```suggestion
.load(classLoader,
resolveLoadingStrategy(type))
.getLoaded(),
DYNAMIC_CLASS_CACHE);
```
##########
wicket-ioc/src/main/java/org/apache/wicket/proxy/bytebuddy/ByteBuddyProxyFactory.java:
##########
@@ -100,8 +102,10 @@ public <T> T createProxy(final Class<T> type, final
IProxyTargetLocator locator)
@SuppressWarnings("unchecked")
public static <T> Class<T> createOrGetProxyClass(Class<T> type)
- {
+ {
+ ClassLoadingStrategy<ClassLoader> loadingStrategy =
resolveLoadingStrategy(type);
ClassLoader classLoader = resolveClassLoader();
+
Review Comment:
Resolving the strategy here runs `privateLookupIn` on every `createProxy`
call, not just on a cache miss, and makes it throw even when the proxy class is
already cached. Moving it into the lambda also lets the trailing whitespace go.
```suggestion
{
ClassLoader classLoader = resolveClassLoader();
```
##########
wicket-ioc/src/main/java/org/apache/wicket/proxy/bytebuddy/ByteBuddyProxyFactory.java:
##########
@@ -205,7 +225,9 @@ private static boolean hasNoArgConstructor(Class<?> type)
for (Constructor<?> constructor :
type.getDeclaredConstructors())
{
if (constructor.getParameterTypes().length == 0)
+ {
Review Comment:
Unrelated to the fix — worth dropping to keep the commit to one thing.
##########
wicket-ioc/src/main/java/org/apache/wicket/proxy/bytebuddy/ByteBuddyProxyFactory.java:
##########
@@ -116,10 +120,26 @@ public static <T> Class<T> createOrGetProxyClass(Class<T>
type)
.implement(InterceptorMutator.class).intercept(FieldAccessor.ofBeanProperty())
.implement(Serializable.class,
IWriteReplace.class,
ILazyInitProxy.class).intercept(MethodDelegation.toField(INTERCEPTOR_FIELD_NAME))
.make()
- .load(classLoader,
ClassLoadingStrategy.Default.INJECTION.allowExistingTypes())
+ .load(classLoader,
loadingStrategy)
.getLoaded());
}
+ private static ClassLoadingStrategy<ClassLoader>
resolveLoadingStrategy(Class<?> type)
+ {
+ try
+ {
+ int modifiers = type.getModifiers();
+
+ return Modifier.isPublic(modifiers)
+ ?
ClassLoadingStrategy.Default.WRAPPER.allowExistingTypes()
+ :
ClassLoadingStrategy.UsingLookup.of(MethodHandles.privateLookupIn(type,
MethodHandles.lookup()));
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new WicketRuntimeException(e);
+ }
+ }
Review Comment:
This is the core of it: branch on whether the proxy keeps the type's
package, not on the type's visibility. Only a `java.*` proxy is renamed into
another package by `WicketNamingStrategy`, and that is the only case that needs
a class loader of its own — `privateLookupIn` cannot serve it anyway, since
`java.base` does not open its packages.
The message on the exception matters here: when it fires, it is because a
named module does not `open` its package to wicket-ioc, and a bare
`IllegalAccessException` gives the user nothing to act on.
```suggestion
/**
* The proxy has to be defined in the same runtime package as the type
it proxies, or the
* package private methods it overrides are not overridden at all. Only
a proxy for a
* <em>java.**</em> type is renamed into another package, and needs a
class loader of its own.
*/
private static ClassLoadingStrategy<ClassLoader>
resolveLoadingStrategy(Class<?> type)
{
if (type.getName().startsWith("java."))
{
return
ClassLoadingStrategy.Default.WRAPPER.allowExistingTypes();
}
try
{
return ClassLoadingStrategy.UsingLookup
.of(MethodHandles.privateLookupIn(type,
MethodHandles.lookup()));
}
catch (IllegalAccessException e)
{
throw new WicketRuntimeException("Cannot create a proxy
for " + type.getName()
+ ", because its package is not open to " +
ByteBuddyProxyFactory.class.getModule(), e);
}
}
```
##########
pom.xml:
##########
@@ -159,7 +159,7 @@
<aspectj.version>1.9.25.1</aspectj.version>
<assertj-core.version>3.27.7</assertj-core.version>
<bouncycastle.version>1.85.2</bouncycastle.version>
- <byte-buddy.version>1.18.8</byte-buddy.version>
+ <byte-buddy.version>1.18.13</byte-buddy.version>
Review Comment:
This bump is separable from the fix: 1.18.13 does not disable `INJECTION` (I
checked on JDK 25), so it is not what forces the change. No objection to
bumping, but it reads as part of the fix here.
> Don't use INJECTION for ByteBuddy proxy creation
> -------------------------------------------------
>
> Key: WICKET-7204
> URL: https://issues.apache.org/jira/browse/WICKET-7204
> Project: Wicket
> Issue Type: Improvement
> Reporter: Andrea Del Bene
> Assignee: Andrea Del Bene
> Priority: Major
> Fix For: 11.0.0
>
>
> The current proxy creation with byte buddy uses
> ClassLoadingStrategy.Default.INJECTION. ad class loading strategy, but this
> relies on Java Unsafe support, which is deprecated and disabled with the
> newer release of ByteBuddy
--
This message was sent by Atlassian Jira
(v8.20.10#820010)