This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/causeway.git


The following commit(s) were added to refs/heads/main by this push:
     new 6c15dc14f6c CAUSEWAY-3883: removes DelegatingInvocationHandlerAbstract 
(refactor)
6c15dc14f6c is described below

commit 6c15dc14f6cb484d91e901abbd51f700c752949b
Author: andi-huber <ahu...@apache.org>
AuthorDate: Mon Jun 16 09:57:32 2025 +0200

    CAUSEWAY-3883: removes DelegatingInvocationHandlerAbstract (refactor)
---
 core/runtime/src/main/java/module-info.java        |   1 +
 .../runtime/wrap/WrapperInvocationHandler.java     |  90 +++++++++++++++++
 .../handlers/DelegatingInvocationHandler.java      |  33 -------
 .../DelegatingInvocationHandlerAbstract.java       | 109 ---------------------
 .../handlers/DomainObjectInvocationHandler.java    |  67 ++++++-------
 .../handlers/PluralInvocationHandlerAbstract.java  |  28 +++---
 .../wrapper/handlers/ProxyGenerator.java           |   9 +-
 .../ProxyCreatorTestUsingCodegenPlugin.java        |  18 ++--
 8 files changed, 153 insertions(+), 202 deletions(-)

diff --git a/core/runtime/src/main/java/module-info.java 
b/core/runtime/src/main/java/module-info.java
index cd8306d5a8c..0e8fd44e818 100644
--- a/core/runtime/src/main/java/module-info.java
+++ b/core/runtime/src/main/java/module-info.java
@@ -20,6 +20,7 @@
     exports org.apache.causeway.core.runtime;
     exports org.apache.causeway.core.runtime.flushmgmt;
     exports org.apache.causeway.core.runtime.events;
+    exports org.apache.causeway.core.runtime.wrap;
 
     requires jakarta.annotation;
     requires java.desktop;
diff --git 
a/core/runtime/src/main/java/org/apache/causeway/core/runtime/wrap/WrapperInvocationHandler.java
 
b/core/runtime/src/main/java/org/apache/causeway/core/runtime/wrap/WrapperInvocationHandler.java
new file mode 100644
index 00000000000..d66e7bbc3c7
--- /dev/null
+++ 
b/core/runtime/src/main/java/org/apache/causeway/core/runtime/wrap/WrapperInvocationHandler.java
@@ -0,0 +1,90 @@
+/*
+ *  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.causeway.core.runtime.wrap;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.jspecify.annotations.NonNull;
+
+import org.apache.causeway.applib.services.wrapper.WrapperFactory;
+import org.apache.causeway.applib.services.wrapper.control.SyncControl;
+import org.apache.causeway.applib.services.wrapper.events.InteractionEvent;
+import org.apache.causeway.commons.internal._Constants;
+import org.apache.causeway.core.metamodel.context.MetaModelContext;
+
+public interface WrapperInvocationHandler extends InvocationHandler {
+    
+    Context context();
+    
+    default Method equalsMethod() { return context().equalsMethod(); }
+    default Method hashCodeMethod() { return context().hashCodeMethod(); }
+    default Method toStringMethod() { return context().toStringMethod(); }
+    
+    public record Context(
+            Object delegate,
+            WrapperFactory wrapperFactory,
+            SyncControl syncControl,
+
+            Method equalsMethod,
+            Method hashCodeMethod,
+            Method toStringMethod) {
+        
+        public static Context of(
+                final @NonNull MetaModelContext metaModelContext,
+                final @NonNull Object pojo,
+                final SyncControl syncControl) {
+
+            var pojoClass = pojo.getClass();
+            try {
+                var equalsMethod = pojoClass.getMethod("equals", 
_Constants.classesOfObject);
+                var hashCodeMethod = pojoClass.getMethod("hashCode", 
_Constants.emptyClasses);
+                var toStringMethod = pojoClass.getMethod("toString", 
_Constants.emptyClasses);
+                
+                return new WrapperInvocationHandler
+                        .Context(pojo, metaModelContext.getWrapperFactory(), 
+                                syncControl, equalsMethod, hashCodeMethod, 
toStringMethod);
+                
+            } catch (final NoSuchMethodException e) {
+                // ///CLOVER:OFF
+                throw new RuntimeException("An Object method could not be 
found: " + e.getMessage());
+                // ///CLOVER:ON
+            }
+        }
+        
+        public Object invoke(final Method method, final Object[] args)
+                throws IllegalArgumentException, IllegalAccessException, 
InvocationTargetException {
+            return method.invoke(delegate(), args);
+        }
+        
+        public boolean isObjectMethod(final Method method) {
+            return toStringMethod().equals(method) 
+                    || hashCodeMethod().equals(method) 
+                    || equalsMethod().equals(method);
+        }
+        
+        public InteractionEvent notifyListeners(final InteractionEvent 
interactionEvent) {
+            wrapperFactory().notifyListeners(interactionEvent);
+            return interactionEvent;
+        }
+        
+    }
+    
+}
diff --git 
a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/DelegatingInvocationHandler.java
 
b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/DelegatingInvocationHandler.java
deleted file mode 100644
index 44ede502b20..00000000000
--- 
a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/DelegatingInvocationHandler.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- *  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.causeway.core.runtimeservices.wrapper.handlers;
-
-import java.lang.reflect.InvocationHandler;
-
-/**
- * @param <T> type of delegate
- */
-public interface DelegatingInvocationHandler<T> extends InvocationHandler {
-
-    T getDelegate();
-
-    boolean isResolveObjectChangedEnabled();
-    void setResolveObjectChangedEnabled(boolean enabled);
-
-}
diff --git 
a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/DelegatingInvocationHandlerAbstract.java
 
b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/DelegatingInvocationHandlerAbstract.java
deleted file mode 100644
index 48296a71afa..00000000000
--- 
a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/DelegatingInvocationHandlerAbstract.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- *  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.causeway.core.runtimeservices.wrapper.handlers;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-import org.jspecify.annotations.NonNull;
-
-import org.apache.causeway.applib.services.wrapper.WrapperFactory;
-import org.apache.causeway.applib.services.wrapper.control.SyncControl;
-import org.apache.causeway.applib.services.wrapper.events.InteractionEvent;
-import org.apache.causeway.commons.internal._Constants;
-import org.apache.causeway.commons.internal.base._Blackhole;
-import org.apache.causeway.core.metamodel.context.MetaModelContext;
-import org.apache.causeway.core.metamodel.object.ManagedObject;
-import org.apache.causeway.core.metamodel.object.ManagedObjects;
-import org.apache.causeway.core.metamodel.objectmanager.ObjectManager;
-
-import lombok.Getter;
-import lombok.Setter;
-
-/**
- * @param <T> type of delegate
- */
-abstract class DelegatingInvocationHandlerAbstract<T> implements 
DelegatingInvocationHandler<T> {
-
-    private ObjectManager objectManager;
-
-    // getter is API
-    @Getter(onMethod_ = {@Override}) private final T delegate;
-    @Getter protected final WrapperFactory wrapperFactory;
-    @Getter private final SyncControl syncControl;
-
-    protected final Method equalsMethod;
-    protected final Method hashCodeMethod;
-    protected final Method toStringMethod;
-
-    @Getter(onMethod_ = {@Override}) @Setter(onMethod_ = {@Override})
-    private boolean isResolveObjectChangedEnabled = false;
-
-    protected DelegatingInvocationHandlerAbstract(
-            final @NonNull MetaModelContext metaModelContext,
-            final @NonNull T delegate,
-            final SyncControl syncControl) {
-        this.delegate = delegate;
-        this.objectManager = metaModelContext.getObjectManager();
-        this.wrapperFactory = metaModelContext.getWrapperFactory();
-        this.syncControl = syncControl;
-
-        try {
-            equalsMethod = delegate.getClass().getMethod("equals", 
_Constants.classesOfObject);
-            hashCodeMethod = delegate.getClass().getMethod("hashCode", 
_Constants.emptyClasses);
-            toStringMethod = delegate.getClass().getMethod("toString", 
_Constants.emptyClasses);
-        } catch (final NoSuchMethodException e) {
-            // ///CLOVER:OFF
-            throw new RuntimeException("An Object method could not be found: " 
+ e.getMessage());
-            // ///CLOVER:ON
-        }
-    }
-
-    protected void resolveIfRequired(final ManagedObject adapter) {
-        if(adapter==null) return;
-        if(!isResolveObjectChangedEnabled) return;
-        if(!ManagedObjects.isEntity(adapter)) return;
-
-        _Blackhole.consume(adapter.getPojo()); // has side effects
-    }
-
-    protected void resolveIfRequired(final Object domainObject) {
-        resolveIfRequired(objectManager.adapt(domainObject));
-    }
-
-    protected Object delegate(final Method method, final Object[] args)
-            throws IllegalArgumentException, IllegalAccessException, 
InvocationTargetException {
-        return method.invoke(getDelegate(), args);
-    }
-
-    protected boolean isObjectMethod(final Method method) {
-        return toStringMethod.equals(method) || hashCodeMethod.equals(method) 
|| equalsMethod.equals(method);
-    }
-
-    @Override
-    public Object invoke(final Object object, final Method method, final 
Object[] args) throws Throwable {
-        return method.invoke(object, args);
-    }
-
-    protected InteractionEvent notifyListeners(final InteractionEvent 
interactionEvent) {
-        wrapperFactory.notifyListeners(interactionEvent);
-        return interactionEvent;
-    }
-
-}
diff --git 
a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/DomainObjectInvocationHandler.java
 
b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/DomainObjectInvocationHandler.java
index 58ae84364bb..93286ad3987 100644
--- 
a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/DomainObjectInvocationHandler.java
+++ 
b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/DomainObjectInvocationHandler.java
@@ -66,8 +66,11 @@
 import org.apache.causeway.core.metamodel.spec.feature.OneToManyAssociation;
 import org.apache.causeway.core.metamodel.spec.feature.OneToOneAssociation;
 import org.apache.causeway.core.metamodel.util.Facets;
+import org.apache.causeway.core.runtime.wrap.WrapperInvocationHandler;
 
+import lombok.Getter;
 import lombok.SneakyThrows;
+import lombok.experimental.Accessors;
 import lombok.extern.log4j.Log4j2;
 
 /**
@@ -76,10 +79,13 @@
  */
 @Log4j2
 public class DomainObjectInvocationHandler<T>
-extends DelegatingInvocationHandlerAbstract<T> {
+implements WrapperInvocationHandler {
 
+    @Getter(onMethod_ = {@Override}) @Accessors(fluent=true) 
+    private final WrapperInvocationHandler.Context context;
+    
     private final ProxyGenerator proxyGenerator;
-    private final MetaModelContext mmContext;
+    private final MetaModelContext mmc;
 
     /**
      * The <tt>title()</tt> method; may be <tt>null</tt>.
@@ -110,16 +116,16 @@ public DomainObjectInvocationHandler(
             final ManagedObject targetAdapter,
             final SyncControl syncControl,
             final ProxyGenerator proxyGenerator) {
-        super(
-                targetAdapter.objSpec().getMetaModelContext(),
+        
+        this.mmc = targetAdapter.objSpec().getMetaModelContext();
+        this.context = WrapperInvocationHandler.Context.of(
+                mmc,
                 domainObject,
                 syncControl);
-
-        this.mmContext = targetAdapter.objSpec().getMetaModelContext();
         this.proxyGenerator = proxyGenerator;
 
         try {
-            titleMethod = getDelegate().getClass().getMethod("title", 
_Constants.emptyClasses);
+            titleMethod = context().delegate().getClass().getMethod("title", 
_Constants.emptyClasses);
         } catch (final NoSuchMethodException e) {
             // ignore
         }
@@ -149,15 +155,12 @@ public DomainObjectInvocationHandler(
     @Override
     public Object invoke(final Object proxyObjectUnused, final Method method, 
final Object[] args) throws Throwable {
 
-        if (isObjectMethod(method)) {
-            return delegate(method, args);
-        }
-
-        if(isEnhancedEntityMethod(method)) {
-            return delegate(method, args);
+        if (context().isObjectMethod(method)
+                || isEnhancedEntityMethod(method)) {
+            return context().invoke(method, args);
         }
 
-        final ManagedObject targetAdapter = 
getObjectManager().adapt(getDelegate());
+        final ManagedObject targetAdapter = 
getObjectManager().adapt(context().delegate());
 
         if(!targetAdapter.specialization().isMixin()) {
             MmAssertionUtils.assertIsBookmarkSupported(targetAdapter);
@@ -177,11 +180,11 @@ public Object invoke(final Object proxyObjectUnused, 
final Method method, final
         }
 
         if (method.equals(__causeway_wrappedMethod)) {
-            return getDelegate();
+            return context().delegate();
         }
 
         if (method.equals(__causeway_executionModes)) {
-            return getSyncControl().getExecutionModes();
+            return context().syncControl().getExecutionModes();
         }
 
         var objectMember = targetSpec.getMemberElseFail(resolvedMethod);
@@ -193,7 +196,7 @@ public Object invoke(final Object proxyObjectUnused, final 
Method method, final
         }
 
         if (intent == Intent.DEFAULTS || intent == 
Intent.CHOICES_OR_AUTOCOMPLETE) {
-            return method.invoke(getDelegate(), args);
+            return method.invoke(context().delegate(), args);
         }
 
         if (objectMember.isOneToOneAssociation()) {
@@ -301,13 +304,11 @@ private boolean isEnhancedEntityMethod(final Method 
method) {
 
     private Object handleTitleMethod(final ManagedObject targetAdapter) {
 
-        resolveIfRequired(targetAdapter);
-
         var targetNoSpec = targetAdapter.objSpec();
         var titleContext = targetNoSpec
                 .createTitleInteractionContext(targetAdapter, 
InteractionInitiatedBy.FRAMEWORK);
         var titleEvent = titleContext.createInteractionEvent();
-        notifyListeners(titleEvent);
+        context().notifyListeners(titleEvent);
         return titleEvent.getTitle();
     }
 
@@ -342,8 +343,6 @@ private Object handleGetterMethodOnProperty(
             checkVisibility(targetAdapter, property);
         });
 
-        resolveIfRequired(targetAdapter);
-
         return runExecutionTask(()->{
 
             var interactionInitiatedBy = getInteractionInitiatedBy();
@@ -352,8 +351,8 @@ private Object handleGetterMethodOnProperty(
             var currentReferencedObj = 
MmUnwrapUtils.single(currentReferencedAdapter);
 
             var propertyAccessEvent = new PropertyAccessEvent(
-                    getDelegate(), property.getFeatureIdentifier(), 
currentReferencedObj);
-            notifyListeners(propertyAccessEvent);
+                    context().delegate(), property.getFeatureIdentifier(), 
currentReferencedObj);
+            context().notifyListeners(propertyAccessEvent);
             return currentReferencedObj;
 
         });
@@ -374,8 +373,6 @@ private Object handleSetterMethodOnProperty(
 
         var argumentAdapter = getObjectManager().adapt(singleArg);
 
-        resolveIfRequired(targetAdapter);
-
         runValidationTask(()->{
             var interactionResult = property.isAssociationValid(
                     targetAdapter, argumentAdapter, 
getInteractionInitiatedBy())
@@ -402,8 +399,6 @@ private Object handleGetterMethodOnCollection(
             checkVisibility(targetAdapter, collection);
         });
 
-        resolveIfRequired(targetAdapter);
-
         return runExecutionTask(()->{
 
             var interactionInitiatedBy = getInteractionInitiatedBy();
@@ -411,17 +406,17 @@ private Object handleGetterMethodOnCollection(
 
             var currentReferencedObj = 
MmUnwrapUtils.single(currentReferencedAdapter);
 
-            var collectionAccessEvent = new 
CollectionAccessEvent(getDelegate(), collection.getFeatureIdentifier());
+            var collectionAccessEvent = new 
CollectionAccessEvent(context().delegate(), collection.getFeatureIdentifier());
 
             if (currentReferencedObj instanceof Collection) {
                 var collectionViewObject = lookupWrappingObject(
                         (Collection<?>) currentReferencedObj, collection);
-                notifyListeners(collectionAccessEvent);
+                context().notifyListeners(collectionAccessEvent);
                 return collectionViewObject;
             } else if (currentReferencedObj instanceof Map) {
                 var mapViewObject = lookupWrappingObject((Map<?, ?>) 
currentReferencedObj,
                         collection);
-                notifyListeners(collectionAccessEvent);
+                context().notifyListeners(collectionAccessEvent);
                 return mapViewObject;
             }
 
@@ -544,7 +539,7 @@ private void checkUsability(
 
     private void notifyListenersAndVetoIfRequired(final InteractionResult 
interactionResult) {
         var interactionEvent = interactionResult.getInteractionEvent();
-        notifyListeners(interactionEvent);
+        context().notifyListeners(interactionEvent);
         if (interactionEvent.isVeto()) {
             throw toException(interactionEvent);
         }
@@ -577,11 +572,11 @@ private InteractionException toException(final 
InteractionEvent interactionEvent
     // -- HELPER
 
     private boolean shouldEnforceRules() {
-        return 
!getSyncControl().getExecutionModes().contains(ExecutionMode.SKIP_RULE_VALIDATION);
+        return 
!context().syncControl().getExecutionModes().contains(ExecutionMode.SKIP_RULE_VALIDATION);
     }
 
     private boolean shouldExecute() {
-        return 
!getSyncControl().getExecutionModes().contains(ExecutionMode.SKIP_EXECUTION);
+        return 
!context().syncControl().getExecutionModes().contains(ExecutionMode.SKIP_EXECUTION);
     }
 
     private void runValidationTask(final Runnable task) {
@@ -608,7 +603,7 @@ private <X> X runExecutionTask(final Supplier<X> task) {
 
     @SneakyThrows
     private Object handleException(final Exception ex) {
-        var exceptionHandler = getSyncControl().getExceptionHandler()
+        var exceptionHandler = context().syncControl().getExceptionHandler()
                 .orElse(null);
 
         if(exceptionHandler==null) {
@@ -639,7 +634,7 @@ private void zeroArgsElseThrow(final Object[] args, final 
String name) {
     // -- DEPENDENCIES
 
     private ObjectManager getObjectManager() {
-        return mmContext.getObjectManager();
+        return mmc.getObjectManager();
     }
 
 }
diff --git 
a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/PluralInvocationHandlerAbstract.java
 
b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/PluralInvocationHandlerAbstract.java
index ecff68a9429..718a4d20566 100644
--- 
a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/PluralInvocationHandlerAbstract.java
+++ 
b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/PluralInvocationHandlerAbstract.java
@@ -19,11 +19,16 @@
 package org.apache.causeway.core.runtimeservices.wrapper.handlers;
 
 import java.lang.reflect.Method;
+import java.util.Collection;
 import java.util.Map;
 
 import 
org.apache.causeway.applib.services.wrapper.events.CollectionMethodEvent;
 import org.apache.causeway.commons.semantics.CollectionSemantics;
 import org.apache.causeway.core.metamodel.spec.feature.OneToManyAssociation;
+import org.apache.causeway.core.runtime.wrap.WrapperInvocationHandler;
+
+import lombok.Getter;
+import lombok.experimental.Accessors;
 
 /**
  * Base class in support of non-scalar types to be proxied up.
@@ -32,10 +37,12 @@
  * @param <P> non-scalar type (eg. {@link Collection} or {@link Map}) to be 
proxied
  */
 abstract class PluralInvocationHandlerAbstract<T, P>
-extends DelegatingInvocationHandlerAbstract<P> {
+implements WrapperInvocationHandler {
 
+    @Getter(onMethod_ = {@Override}) @Accessors(fluent=true) 
+    private final WrapperInvocationHandler.Context context;
+    
     private final OneToManyAssociation oneToManyAssociation;
-    private final T domainObject;
     private final CollectionSemantics collectionSemantics;
 
     protected PluralInvocationHandlerAbstract(
@@ -44,12 +51,10 @@ protected PluralInvocationHandlerAbstract(
             final OneToManyAssociation otma,
             final CollectionSemantics collectionSemantics) {
 
-        super(otma.getMetaModelContext(),
-                collectionOrMapToBeProxied,
-                handler.getSyncControl());
+        this.context = 
WrapperInvocationHandler.Context.of(otma.getMetaModelContext(), 
+                collectionOrMapToBeProxied, handler.context().syncControl());
 
         this.oneToManyAssociation = otma;
-        this.domainObject = handler.getDelegate();
         this.collectionSemantics = collectionSemantics;
     }
 
@@ -58,30 +63,27 @@ public OneToManyAssociation getCollection() {
     }
 
     public T getDomainObject() {
-        return domainObject;
+        return (T) context().delegate();
     }
 
     @Override
     public Object invoke(final Object collectionObject, final Method method, 
final Object[] args) throws Throwable {
 
-        // delegate
-        final Object returnValueObj = delegate(method, args);
+        final Object returnValueObj = context().invoke(method, args);
 
         var policy = collectionSemantics.getInvocationHandlingPolicy();
 
         if (policy.intercepts(method)) {
 
-            resolveIfRequired(domainObject);
-
             var event =
                     new CollectionMethodEvent(
-                            getDelegate(),
+                            context().delegate(),
                             getCollection().getFeatureIdentifier(),
                             getDomainObject(),
                             method.getName(),
                             args,
                             returnValueObj);
-            notifyListeners(event);
+            context().notifyListeners(event);
             return returnValueObj;
         }
 
diff --git 
a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/ProxyGenerator.java
 
b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/ProxyGenerator.java
index 1507310d72e..24aa3be43d7 100644
--- 
a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/ProxyGenerator.java
+++ 
b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/ProxyGenerator.java
@@ -34,6 +34,7 @@
 import org.apache.causeway.commons.semantics.CollectionSemantics;
 import org.apache.causeway.core.metamodel.object.ManagedObject;
 import org.apache.causeway.core.metamodel.spec.feature.OneToManyAssociation;
+import org.apache.causeway.core.runtime.wrap.WrapperInvocationHandler;
 
 public record ProxyGenerator(@NonNull _ProxyFactoryService 
proxyFactoryService) {
 
@@ -106,9 +107,9 @@ public <T, P, Q> Map<P, Q> mapProxy(
     
     // -- HELPER
 
-    <T> T instantiateProxy(final DelegatingInvocationHandler<T> handler) {
-        final T classToBeProxied = handler.getDelegate();
-        final Class<T> base = 
_Casts.uncheckedCast(classToBeProxied.getClass());
+    <T> T instantiateProxy(final WrapperInvocationHandler handler) {
+        var pojoToBeProxied = handler.context().delegate();
+        Class<T> base = _Casts.uncheckedCast(pojoToBeProxied.getClass());
         return instantiateProxy(base, handler);
     }
 
@@ -118,7 +119,7 @@ <T> T instantiateProxy(final DelegatingInvocationHandler<T> 
handler) {
      *      where {@code handler.getDelegate().getClass()} is not visible
      *      (eg. nested private type)
      */
-    <T> T instantiateProxy(final Class<T> base, final 
DelegatingInvocationHandler<? extends T> handler) {
+    <T> T instantiateProxy(final Class<T> base, final WrapperInvocationHandler 
handler) {
         if (base.isInterface()) {
             return _Casts.uncheckedCast(
                     Proxy.newProxyInstance(
diff --git 
a/core/runtimeservices/src/test/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/ProxyCreatorTestUsingCodegenPlugin.java
 
b/core/runtimeservices/src/test/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/ProxyCreatorTestUsingCodegenPlugin.java
index e44d78e8d62..48dcb890b6d 100644
--- 
a/core/runtimeservices/src/test/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/ProxyCreatorTestUsingCodegenPlugin.java
+++ 
b/core/runtimeservices/src/test/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/ProxyCreatorTestUsingCodegenPlugin.java
@@ -32,6 +32,7 @@
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import 
org.apache.causeway.core.codegen.bytebuddy.services.ProxyFactoryServiceByteBuddy;
+import org.apache.causeway.core.runtime.wrap.WrapperInvocationHandler;
 
 import lombok.Getter;
 import lombok.Setter;
@@ -55,9 +56,12 @@ public void setName(final String name) {
         }
     }
 
-    private static class DelegatingInvocationHandlerForTest implements 
DelegatingInvocationHandler<Employee> {
+    private static class WrapperInvocationHandlerForTest implements 
WrapperInvocationHandler {
         private final Employee delegate = new Employee();
         private final Set<String> invoked = new HashSet<>();
+        private final WrapperInvocationHandler.Context context = new 
WrapperInvocationHandler.Context(
+                delegate, null, null, null, null, null);
+                
 
         @Override
         public Object invoke(final Object proxy, final Method method, final 
Object[] args) throws Throwable {
@@ -65,24 +69,24 @@ public Object invoke(final Object proxy, final Method 
method, final Object[] arg
             return "hi";
         }
 
-        @Override
-        public Employee getDelegate() {
-            return delegate;
-        }
-
         @Getter @Setter 
         private boolean resolveObjectChangedEnabled = false;
 
         public boolean wasInvoked(final String methodName) {
             return invoked.contains(methodName);
         }
+
+        @Override
+        public WrapperInvocationHandler.Context context() {
+            return context;
+        }
         
     }
 
     @Test
     void proxyShouldDelegateCalls() {
 
-        final DelegatingInvocationHandlerForTest handler = new 
DelegatingInvocationHandlerForTest();
+        final WrapperInvocationHandlerForTest handler = new 
WrapperInvocationHandlerForTest();
         final Employee proxyOfEmployee = 
proxyGenerator.instantiateProxy(handler);
 
         assertNotNull(proxyOfEmployee);

Reply via email to