You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@causeway.apache.org by ah...@apache.org on 2025/02/18 16:57:47 UTC

(causeway) branch main updated: CAUSEWAY-3859: Java record refactoring (part 10)

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 f84fecb8ca7 CAUSEWAY-3859: Java record refactoring (part 10)
f84fecb8ca7 is described below

commit f84fecb8ca7e4647b6a4205d985bd0f07900c8fd
Author: Andi Huber <ah...@apache.org>
AuthorDate: Tue Feb 18 17:57:41 2025 +0100

    CAUSEWAY-3859: Java record refactoring (part 10)
    
    - also unifies 2 classes into ProxyGenerator
---
 .../tabular/internal/DataTableInternal.java        |  8 +-
 .../{_FilterUtils.java => FilterUtils.java}        | 22 ++---
 .../runtimeservices/src/main/java/module-info.java |  3 +-
 .../publish/LifecycleCallbackNotifier.java         | 11 ++-
 .../wrapper/WrapperFactoryDefault.java             | 15 ++--
 .../handlers/DelegatingInvocationHandler.java      |  7 +-
 ...va => DelegatingInvocationHandlerAbstract.java} | 31 +++----
 .../handlers/DomainObjectInvocationHandler.java    | 18 ++--
 .../handlers/PluralInvocationHandlerAbstract.java  |  2 +-
 ...roxyContextHandler.java => ProxyGenerator.java} | 95 ++++++++++++++--------
 .../wrapper/proxy/ProxyCreator.java                | 64 ---------------
 .../ProxyCreatorTestUsingCodegenPlugin.java        | 23 +++---
 .../changetracking/events/PostStoreEvent.java      |  8 +-
 .../changetracking/events/PreStoreEvent.java       |  8 +-
 .../changetracking/events/TimestampService.java    |  2 +-
 15 files changed, 123 insertions(+), 194 deletions(-)

diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/tabular/internal/DataTableInternal.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/tabular/internal/DataTableInternal.java
index 85ee67e38b4..d9647345a0c 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/tabular/internal/DataTableInternal.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/tabular/internal/DataTableInternal.java
@@ -55,7 +55,7 @@
 import org.apache.causeway.core.metamodel.tabular.DataRow;
 import org.apache.causeway.core.metamodel.tabular.DataTableInteractive;
 import org.apache.causeway.core.metamodel.tabular.DataTableMemento;
-import org.apache.causeway.core.metamodel.tabular.internal._FilterUtils.FilterHandler;
+import org.apache.causeway.core.metamodel.tabular.internal.FilterUtils.FilterHandler;
 import org.apache.causeway.core.metamodel.tabular.simple.DataTable;
 
 import lombok.AccessLevel;
@@ -145,7 +145,7 @@ private DataTableInternal(
 
         this.managedMember = managedMember;
         this.where = where;
-        this.filterHandler = _FilterUtils.createFilterHandler(managedMember.getElementType());
+        this.filterHandler = FilterUtils.createFilterHandler(managedMember.getElementType());
 
         this.searchArgumentBindable = _Bindables.forValue("");
         this.columnSortBindable = _Bindables.forValue(null);
@@ -240,7 +240,7 @@ public Optional<DataRow> lookupDataRow(final int rowIndex) {
 
     @Override
     public String getSearchPromptPlaceholderText() {
-        return filterHandler.map(handler->handler.searchPromptPlaceholderText)
+        return filterHandler.map(FilterHandler::searchPromptPlaceholderText)
                 .orElse("");
     }
 
@@ -254,7 +254,7 @@ private Predicate<DataRow> adaptSearchPredicate() {
     private CollectionFilterService.@Nullable Tokens tokens(final ManagedObject element){
         return filterHandler.isEmpty()
                 ? null
-                : filterHandler.get().tokenizer.apply(element.getPojo());
+                : filterHandler.get().tokenizer().apply(element.getPojo());
     }
 
     // -- SORTING
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/tabular/internal/_FilterUtils.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/tabular/internal/FilterUtils.java
similarity index 86%
rename from core/metamodel/src/main/java/org/apache/causeway/core/metamodel/tabular/internal/_FilterUtils.java
rename to core/metamodel/src/main/java/org/apache/causeway/core/metamodel/tabular/internal/FilterUtils.java
index eac38bcba26..9c9bbdbbb86 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/tabular/internal/_FilterUtils.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/tabular/internal/FilterUtils.java
@@ -22,6 +22,7 @@
 import java.util.function.BiPredicate;
 import java.util.function.Function;
 
+import org.jspecify.annotations.NonNull;
 import org.jspecify.annotations.Nullable;
 
 import org.apache.causeway.applib.services.filter.CollectionFilterService;
@@ -32,27 +33,20 @@
 import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
 import org.apache.causeway.core.metamodel.tabular.DataRow;
 
-import lombok.AllArgsConstructor;
-import org.jspecify.annotations.NonNull;
-import lombok.experimental.UtilityClass;
-
-@UtilityClass
-class _FilterUtils {
-
-    @AllArgsConstructor
-    static class FilterHandler {
+record FilterUtils() {
 
-        final @NonNull Function<Object, Tokens> tokenizer;
-        final @NonNull BiPredicate<Tokens, String> tokenFilter;
-        final @NonNull String searchPromptPlaceholderText;
+    record FilterHandler(
+        @NonNull Function<Object, Tokens> tokenizer,
+        @NonNull BiPredicate<Tokens, String> tokenFilter,
+        @NonNull String searchPromptPlaceholderText) {
 
-        final @NonNull BiPredicate<DataRow, String> getDataRowFilter() {
+        @NonNull BiPredicate<DataRow, String> getDataRowFilter() {
             return (dataRow, searchArg) ->
                 tokenFilter.test(dataRow.filterTokens().orElse(null), searchArg);
         }
     }
 
-    Optional<FilterHandler> createFilterHandler(final @Nullable ObjectSpecification elementType) {
+    static Optional<FilterHandler> createFilterHandler(final @Nullable ObjectSpecification elementType) {
         if(elementType==null) return Optional.empty();
 
         var mmc = elementType.getMetaModelContext();
diff --git a/core/runtimeservices/src/main/java/module-info.java b/core/runtimeservices/src/main/java/module-info.java
index ad644cd40c2..219035955e9 100644
--- a/core/runtimeservices/src/main/java/module-info.java
+++ b/core/runtimeservices/src/main/java/module-info.java
@@ -49,7 +49,6 @@
     exports org.apache.causeway.core.runtimeservices.wrapper;
     exports org.apache.causeway.core.runtimeservices.wrapper.dispatchers;
     exports org.apache.causeway.core.runtimeservices.wrapper.handlers;
-    exports org.apache.causeway.core.runtimeservices.wrapper.proxy;
     exports org.apache.causeway.core.runtimeservices.xml;
     exports org.apache.causeway.core.runtimeservices.xmlsnapshot;
 
@@ -82,5 +81,5 @@
     
     opens org.apache.causeway.core.runtimeservices;
     opens org.apache.causeway.core.runtimeservices.wrapper;
-    opens org.apache.causeway.core.runtimeservices.wrapper.proxy; //to org.apache.causeway.core.codegen.bytebuddy
+    opens org.apache.causeway.core.runtimeservices.wrapper.handlers; //to org.apache.causeway.core.codegen.bytebuddy
 }
diff --git a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/publish/LifecycleCallbackNotifier.java b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/publish/LifecycleCallbackNotifier.java
index ebbfae68e39..1ff11b1c474 100644
--- a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/publish/LifecycleCallbackNotifier.java
+++ b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/publish/LifecycleCallbackNotifier.java
@@ -88,24 +88,24 @@ public void postLoad(final ManagedObject entity) {
      */
     public void prePersist(final Either<ManagedObject, ManagedObject> eitherWithOrWithoutOid) {
         var pojo = eitherWithOrWithoutOid.fold(ManagedObject::getPojo, ManagedObject::getPojo);
-        if(pojo==null) {return;}
-        eventBusService.post(PreStoreEvent.of(pojo));
+        if(pojo==null) return;
+        eventBusService.post(new PreStoreEvent(pojo));
         var entity = eitherWithOrWithoutOid.fold(UnaryOperator.identity(), UnaryOperator.identity());
         dispatch(entity, PersistingCallbackFacet.class, PersistingLifecycleEventFacet.class);
     }
 
     public void postPersist(final ManagedObject entity) {
-        eventBusService.post(PostStoreEvent.of(entity.getPojo()));
+        eventBusService.post(new PostStoreEvent(entity.getPojo()));
         dispatch(entity, PersistedCallbackFacet.class, PersistedLifecycleEventFacet.class);
     }
 
     public void preUpdate(final ManagedObject entity) {
-        eventBusService.post(PreStoreEvent.of(entity.getPojo()));
+        eventBusService.post(new PreStoreEvent(entity.getPojo()));
         dispatch(entity, UpdatingCallbackFacet.class, UpdatingLifecycleEventFacet.class);
     }
 
     public void postUpdate(final ManagedObject entity) {
-        eventBusService.post(PostStoreEvent.of(entity.getPojo()));
+        eventBusService.post(new PostStoreEvent(entity.getPojo()));
         dispatch(entity, UpdatedCallbackFacet.class, UpdatedLifecycleEventFacet.class);
     }
 
@@ -123,7 +123,6 @@ private void dispatch(
         ManagedObjects.asSpecified(entity)
         .map(ManagedObject::getSpecification)
         .ifPresent(spec->{
-
             spec.lookupFacet(callbackFacetType)
             .ifPresent(callbackFacet->invokeCallback(callbackFacet, entity));
 
diff --git a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/WrapperFactoryDefault.java b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/WrapperFactoryDefault.java
index 84f9345f377..0758800b026 100644
--- a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/WrapperFactoryDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/WrapperFactoryDefault.java
@@ -38,6 +38,8 @@
 import jakarta.inject.Named;
 import jakarta.inject.Provider;
 
+import org.jspecify.annotations.NonNull;
+
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
@@ -101,15 +103,13 @@
 import org.apache.causeway.core.runtimeservices.wrapper.dispatchers.InteractionEventDispatcher;
 import org.apache.causeway.core.runtimeservices.wrapper.dispatchers.InteractionEventDispatcherTypeSafe;
 import org.apache.causeway.core.runtimeservices.wrapper.handlers.DomainObjectInvocationHandler;
-import org.apache.causeway.core.runtimeservices.wrapper.handlers.ProxyContextHandler;
-import org.apache.causeway.core.runtimeservices.wrapper.proxy.ProxyCreator;
+import org.apache.causeway.core.runtimeservices.wrapper.handlers.ProxyGenerator;
 import org.apache.causeway.schema.cmd.v2.CommandDto;
 
 import static org.apache.causeway.applib.services.wrapper.control.SyncControl.control;
 
 import lombok.Data;
 import lombok.Getter;
-import org.jspecify.annotations.NonNull;
 import lombok.RequiredArgsConstructor;
 
 /**
@@ -142,17 +142,16 @@ public class WrapperFactoryDefault
     private final List<InteractionListener> listeners = new ArrayList<>();
     private final Map<Class<? extends InteractionEvent>, InteractionEventDispatcher>
         dispatchersByEventClass = new HashMap<>();
-    private ProxyContextHandler proxyContextHandler;
 
     private ExecutorService commonExecutorService;
+    private ProxyGenerator proxyGenerator;
 
     @PostConstruct
     public void init() {
 
         this.commonExecutorService = newCommonExecutorService();
 
-        var proxyCreator = new ProxyCreator(proxyFactoryService);
-        proxyContextHandler = new ProxyContextHandler(proxyCreator);
+        this.proxyGenerator = new ProxyGenerator(proxyFactoryService);
 
         putDispatcher(ObjectTitleEvent.class, InteractionListener::objectTitleRead);
         putDispatcher(PropertyVisibilityEvent.class, InteractionListener::propertyVisible);
@@ -253,13 +252,13 @@ public <T> T wrapMixin(
 
     protected <T> T createProxy(final T domainObject, final SyncControl syncControl) {
         var objAdapter = adaptAndGuardAgainstWrappingNotSupported(domainObject);
-        return proxyContextHandler.proxy(domainObject, objAdapter, syncControl);
+        return proxyGenerator.objectProxy(domainObject, objAdapter, syncControl);
     }
 
     protected <T> T createMixinProxy(final Object mixee, final T mixin, final SyncControl syncControl) {
         var mixeeAdapter = adaptAndGuardAgainstWrappingNotSupported(mixee);
         var mixinAdapter = adaptAndGuardAgainstWrappingNotSupported(mixin);
-        return proxyContextHandler.mixinProxy(mixin, mixeeAdapter, mixinAdapter, syncControl);
+        return proxyGenerator.mixinProxy(mixin, mixeeAdapter, mixinAdapter, syncControl);
     }
 
     @Override
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
index 915c70fd468..44ede502b20 100644
--- 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
@@ -21,14 +21,13 @@
 import java.lang.reflect.InvocationHandler;
 
 /**
- * @param <T>
+ * @param <T> type of delegate
  */
 public interface DelegatingInvocationHandler<T> extends InvocationHandler {
 
     T getDelegate();
 
-    public boolean isResolveObjectChangedEnabled();
-
-    public void setResolveObjectChangedEnabled(boolean resolveObjectChangedEnabled);
+    boolean isResolveObjectChangedEnabled();
+    void setResolveObjectChangedEnabled(boolean enabled);
 
 }
diff --git a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/DelegatingInvocationHandlerDefault.java b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/DelegatingInvocationHandlerAbstract.java
similarity index 85%
rename from core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/DelegatingInvocationHandlerDefault.java
rename to core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/DelegatingInvocationHandlerAbstract.java
index 669c5c52b04..48296a71afa 100644
--- a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/DelegatingInvocationHandlerDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/DelegatingInvocationHandlerAbstract.java
@@ -21,6 +21,8 @@
 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;
@@ -32,18 +34,17 @@
 import org.apache.causeway.core.metamodel.objectmanager.ObjectManager;
 
 import lombok.Getter;
-import org.jspecify.annotations.NonNull;
 import lombok.Setter;
 
 /**
- * @param <T>
+ * @param <T> type of delegate
  */
-public class DelegatingInvocationHandlerDefault<T> implements DelegatingInvocationHandler<T> {
+abstract class DelegatingInvocationHandlerAbstract<T> implements DelegatingInvocationHandler<T> {
 
     private ObjectManager objectManager;
 
     // getter is API
-    @Getter(onMethod = @__(@Override)) private final T delegate;
+    @Getter(onMethod_ = {@Override}) private final T delegate;
     @Getter protected final WrapperFactory wrapperFactory;
     @Getter private final SyncControl syncControl;
 
@@ -51,11 +52,10 @@ public class DelegatingInvocationHandlerDefault<T> implements DelegatingInvocati
     protected final Method hashCodeMethod;
     protected final Method toStringMethod;
 
-    // getter and setter are API
-    @Getter(onMethod = @__(@Override)) @Setter(onMethod = @__(@Override))
-    private boolean resolveObjectChangedEnabled;
+    @Getter(onMethod_ = {@Override}) @Setter(onMethod_ = {@Override})
+    private boolean isResolveObjectChangedEnabled = false;
 
-    public DelegatingInvocationHandlerDefault(
+    protected DelegatingInvocationHandlerAbstract(
             final @NonNull MetaModelContext metaModelContext,
             final @NonNull T delegate,
             final SyncControl syncControl) {
@@ -76,18 +76,11 @@ public DelegatingInvocationHandlerDefault(
     }
 
     protected void resolveIfRequired(final ManagedObject adapter) {
+        if(adapter==null) return;
+        if(!isResolveObjectChangedEnabled) return;
+        if(!ManagedObjects.isEntity(adapter)) return;
 
-        if(!resolveObjectChangedEnabled) {
-            return;
-        }
-        if(adapter==null) {
-            return;
-        }
-        if(!ManagedObjects.isEntity(adapter)) {
-            return;
-        }
-
-        _Blackhole.consume(adapter.getPojo());
+        _Blackhole.consume(adapter.getPojo()); // has side effects
     }
 
     protected void resolveIfRequired(final Object domainObject) {
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 b0934a23a9b..519d1b82a55 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
@@ -72,13 +72,13 @@
 
 /**
  *
- * @param <T>
+ * @param <T> type of delegate
  */
 @Log4j2
 public class DomainObjectInvocationHandler<T>
-extends DelegatingInvocationHandlerDefault<T> {
+extends DelegatingInvocationHandlerAbstract<T> {
 
-    private final ProxyContextHandler proxyContextHandler;
+    private final ProxyGenerator proxyGenerator;
     private final MetaModelContext mmContext;
 
     /**
@@ -109,14 +109,14 @@ public DomainObjectInvocationHandler(
             final ManagedObject mixeeAdapter, // ignored if not handling a mixin
             final ManagedObject targetAdapter,
             final SyncControl syncControl,
-            final ProxyContextHandler proxyContextHandler) {
+            final ProxyGenerator proxyGenerator) {
         super(
                 targetAdapter.getSpecification().getMetaModelContext(),
                 domainObject,
                 syncControl);
 
         this.mmContext = targetAdapter.getSpecification().getMetaModelContext();
-        this.proxyContextHandler = proxyContextHandler;
+        this.proxyGenerator = proxyGenerator;
 
         try {
             titleMethod = getDelegate().getClass().getMethod("title", _Constants.emptyClasses);
@@ -438,11 +438,11 @@ private Collection<?> lookupWrappingObject(
         if (collectionToLookup instanceof WrappingObject) {
             return collectionToLookup;
         }
-        if(proxyContextHandler == null) {
+        if(proxyGenerator == null) {
             throw new IllegalStateException("Unable to create proxy for collection; "
                     + "proxyContextHandler not provided");
         }
-        return proxyContextHandler.proxy(collectionToLookup, this, otma);
+        return proxyGenerator.collectionProxy(collectionToLookup, this, otma);
     }
 
     private Map<?, ?> lookupWrappingObject(
@@ -451,11 +451,11 @@ private Collection<?> lookupWrappingObject(
         if (mapToLookup instanceof WrappingObject) {
             return mapToLookup;
         }
-        if(proxyContextHandler == null) {
+        if(proxyGenerator == null) {
             throw new IllegalStateException("Unable to create proxy for collection; "
                     + "proxyContextHandler not provided");
         }
-        return proxyContextHandler.proxy(mapToLookup, this, otma);
+        return proxyGenerator.mapProxy(mapToLookup, this, otma);
     }
 
     private Object handleActionMethod(
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 186546deed9..ecff68a9429 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
@@ -32,7 +32,7 @@
  * @param <P> non-scalar type (eg. {@link Collection} or {@link Map}) to be proxied
  */
 abstract class PluralInvocationHandlerAbstract<T, P>
-extends DelegatingInvocationHandlerDefault<P> {
+extends DelegatingInvocationHandlerAbstract<P> {
 
     private final OneToManyAssociation oneToManyAssociation;
     private final T domainObject;
diff --git a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/ProxyContextHandler.java b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/ProxyGenerator.java
similarity index 54%
rename from core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/ProxyContextHandler.java
rename to core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/ProxyGenerator.java
index d67d94c74aa..1507310d72e 100644
--- a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/ProxyContextHandler.java
+++ b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/ProxyGenerator.java
@@ -18,37 +18,38 @@
  */
 package org.apache.causeway.core.runtimeservices.wrapper.handlers;
 
+import java.lang.reflect.Proxy;
 import java.util.Collection;
 import java.util.Map;
 
+import org.jspecify.annotations.NonNull;
+
+import org.apache.causeway.applib.services.wrapper.WrappingObject;
 import org.apache.causeway.applib.services.wrapper.control.SyncControl;
 import org.apache.causeway.commons.internal.base._Casts;
+import org.apache.causeway.commons.internal.collections._Arrays;
+import org.apache.causeway.commons.internal.context._Context;
+import org.apache.causeway.commons.internal.proxy._ProxyFactory;
+import org.apache.causeway.commons.internal.proxy._ProxyFactoryService;
 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.runtimeservices.wrapper.proxy.ProxyCreator;
-
-import org.jspecify.annotations.NonNull;
-import lombok.RequiredArgsConstructor;
-
-@RequiredArgsConstructor
-public class ProxyContextHandler {
 
-    @NonNull private final ProxyCreator proxyCreator;
+public record ProxyGenerator(@NonNull _ProxyFactoryService proxyFactoryService) {
 
-    public <T> T proxy(
-            final T domainObject,
-            final ManagedObject adapter,
-            final SyncControl syncControl) {
+    public <T> T objectProxy(
+        final T domainObject,
+        final ManagedObject adapter,
+        final SyncControl syncControl) {
 
         var invocationHandler = new DomainObjectInvocationHandler<T>(
-                domainObject,
-                null, // mixeeAdapter ignored
-                adapter,
-                syncControl,
-                this);
+            domainObject,
+            null, // mixeeAdapter ignored
+            adapter,
+            syncControl,
+            this);
 
-        return proxyCreator.instantiateProxy(invocationHandler);
+        return instantiateProxy(invocationHandler);
     }
 
     public <T> T mixinProxy(
@@ -56,54 +57,78 @@ public <T> T mixinProxy(
             final ManagedObject mixeeAdapter,
             final ManagedObject mixinAdapter,
             final SyncControl syncControl) {
-
+    
         var invocationHandler = new DomainObjectInvocationHandler<T>(
                 mixin,
                 mixeeAdapter,
                 mixinAdapter,
                 syncControl,
                 this);
-
-        return proxyCreator.instantiateProxy(invocationHandler);
+    
+        return instantiateProxy(invocationHandler);
     }
-
+    
     /**
      * Whether to execute or not will be picked up from the supplied parent
      * handler.
      */
-    public <T, E> Collection<E> proxy(
+    public <T, E> Collection<E> collectionProxy(
             final Collection<E> collectionToBeProxied,
             final DomainObjectInvocationHandler<T> handler,
             final OneToManyAssociation otma) {
-
+    
         var collectionInvocationHandler = new CollectionInvocationHandler<T, Collection<E>>(
                         collectionToBeProxied, handler, otma);
-        collectionInvocationHandler.setResolveObjectChangedEnabled(
-                handler.isResolveObjectChangedEnabled());
-
+    
         var proxyBase = CollectionSemantics
                 .valueOfElseFail(collectionToBeProxied.getClass())
                 .getContainerType();
-
-        return proxyCreator.instantiateProxy(_Casts.uncheckedCast(proxyBase), collectionInvocationHandler);
+    
+        return instantiateProxy(_Casts.uncheckedCast(proxyBase), collectionInvocationHandler);
     }
-
+    
     /**
      * Whether to execute or not will be picked up from the supplied parent
      * handler.
      */
-    public <T, P, Q> Map<P, Q> proxy(
+    public <T, P, Q> Map<P, Q> mapProxy(
             final Map<P, Q> collectionToBeProxied,
             final DomainObjectInvocationHandler<T> handler,
             final OneToManyAssociation otma) {
-
+    
         var mapInvocationHandler = new MapInvocationHandler<T, Map<P, Q>>(
                 collectionToBeProxied, handler, otma);
-        mapInvocationHandler.setResolveObjectChangedEnabled(handler.isResolveObjectChangedEnabled());
-
+    
         var proxyBase = Map.class;
+    
+        return instantiateProxy(_Casts.uncheckedCast(proxyBase), mapInvocationHandler);
+    }
+    
+    // -- HELPER
 
-        return proxyCreator.instantiateProxy(_Casts.uncheckedCast(proxyBase), mapInvocationHandler);
+    <T> T instantiateProxy(final DelegatingInvocationHandler<T> handler) {
+        final T classToBeProxied = handler.getDelegate();
+        final Class<T> base = _Casts.uncheckedCast(classToBeProxied.getClass());
+        return instantiateProxy(base, handler);
     }
 
+    /**
+     * Creates a proxy, using given {@code base} type as the proxy's base.
+     * @implNote introduced to circumvent access issues on cases,
+     *      where {@code handler.getDelegate().getClass()} is not visible
+     *      (eg. nested private type)
+     */
+    <T> T instantiateProxy(final Class<T> base, final DelegatingInvocationHandler<? extends T> handler) {
+        if (base.isInterface()) {
+            return _Casts.uncheckedCast(
+                    Proxy.newProxyInstance(
+                            _Context.getDefaultClassLoader(),
+                            _Arrays.combine(base, (Class<?>[]) new Class[]{WrappingObject.class}),
+                            handler));
+        } else {
+            final _ProxyFactory<T> proxyFactory = proxyFactoryService.factory(base, WrappingObject.class);
+            return proxyFactory.createInstance(handler, false);
+        }
+    }
+    
 }
diff --git a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/proxy/ProxyCreator.java b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/proxy/ProxyCreator.java
deleted file mode 100644
index 5da59e0a64e..00000000000
--- a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/proxy/ProxyCreator.java
+++ /dev/null
@@ -1,64 +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.proxy;
-
-import java.lang.reflect.Proxy;
-
-import org.apache.causeway.applib.services.wrapper.WrappingObject;
-import org.apache.causeway.commons.internal.base._Casts;
-import org.apache.causeway.commons.internal.collections._Arrays;
-import org.apache.causeway.commons.internal.context._Context;
-import org.apache.causeway.commons.internal.proxy._ProxyFactory;
-import org.apache.causeway.commons.internal.proxy._ProxyFactoryService;
-import org.apache.causeway.core.runtimeservices.wrapper.handlers.DelegatingInvocationHandler;
-
-import org.jspecify.annotations.NonNull;
-import lombok.RequiredArgsConstructor;
-
-@RequiredArgsConstructor
-public class ProxyCreator {
-
-    @NonNull private final _ProxyFactoryService proxyFactoryService;
-
-    public <T> T instantiateProxy(final DelegatingInvocationHandler<T> handler) {
-        final T classToBeProxied = handler.getDelegate();
-        final Class<T> base = _Casts.uncheckedCast(classToBeProxied.getClass());
-        return instantiateProxy(base, handler);
-    }
-
-    /**
-     * Creates a proxy, using given {@code base} type as the proxy's base.
-     * @implNote introduced to circumvent access issues on cases,
-     *      where {@code handler.getDelegate().getClass()} is not visible
-     *      (eg. nested private type)
-     */
-    public <T> T instantiateProxy(final Class<T> base, final DelegatingInvocationHandler<? extends T> handler) {
-        if (base.isInterface()) {
-            return _Casts.uncheckedCast(
-                    Proxy.newProxyInstance(
-                            _Context.getDefaultClassLoader(),
-                            _Arrays.combine(base, (Class<?>[]) new Class[]{WrappingObject.class}),
-                            handler));
-        } else {
-            final _ProxyFactory<T> proxyFactory = proxyFactoryService.factory(base, WrappingObject.class);
-            return proxyFactory.createInstance(handler, false);
-        }
-    }
-
-}
diff --git a/core/runtimeservices/src/test/java/org/apache/causeway/core/runtimeservices/wrapper/proxy/ProxyCreatorTestUsingCodegenPlugin.java b/core/runtimeservices/src/test/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/ProxyCreatorTestUsingCodegenPlugin.java
similarity index 82%
rename from core/runtimeservices/src/test/java/org/apache/causeway/core/runtimeservices/wrapper/proxy/ProxyCreatorTestUsingCodegenPlugin.java
rename to core/runtimeservices/src/test/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/ProxyCreatorTestUsingCodegenPlugin.java
index ca1cb2235e4..e44d78e8d62 100644
--- a/core/runtimeservices/src/test/java/org/apache/causeway/core/runtimeservices/wrapper/proxy/ProxyCreatorTestUsingCodegenPlugin.java
+++ b/core/runtimeservices/src/test/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/ProxyCreatorTestUsingCodegenPlugin.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.causeway.core.runtimeservices.wrapper.proxy;
+package org.apache.causeway.core.runtimeservices.wrapper.handlers;
 
 import java.lang.reflect.Method;
 import java.util.HashSet;
@@ -32,15 +32,17 @@
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import org.apache.causeway.core.codegen.bytebuddy.services.ProxyFactoryServiceByteBuddy;
-import org.apache.causeway.core.runtimeservices.wrapper.handlers.DelegatingInvocationHandler;
+
+import lombok.Getter;
+import lombok.Setter;
 
 class ProxyCreatorTestUsingCodegenPlugin {
 
-    private ProxyCreator proxyCreator;
+    private ProxyGenerator proxyGenerator;
 
     @BeforeEach
     void setUp() throws Exception {
-        proxyCreator = new ProxyCreator(new ProxyFactoryServiceByteBuddy());
+        proxyGenerator = new ProxyGenerator(new ProxyFactoryServiceByteBuddy());
     }
 
     public static class Employee {
@@ -68,25 +70,20 @@ public Employee getDelegate() {
             return delegate;
         }
 
-        @Override
-        public boolean isResolveObjectChangedEnabled() {
-            return false;
-        }
-
-        @Override
-        public void setResolveObjectChangedEnabled(final boolean resolveObjectChangedEnabled) {
-        }
+        @Getter @Setter 
+        private boolean resolveObjectChangedEnabled = false;
 
         public boolean wasInvoked(final String methodName) {
             return invoked.contains(methodName);
         }
+        
     }
 
     @Test
     void proxyShouldDelegateCalls() {
 
         final DelegatingInvocationHandlerForTest handler = new DelegatingInvocationHandlerForTest();
-        final Employee proxyOfEmployee = proxyCreator.instantiateProxy(handler);
+        final Employee proxyOfEmployee = proxyGenerator.instantiateProxy(handler);
 
         assertNotNull(proxyOfEmployee);
 
diff --git a/core/transaction/src/main/java/org/apache/causeway/core/transaction/changetracking/events/PostStoreEvent.java b/core/transaction/src/main/java/org/apache/causeway/core/transaction/changetracking/events/PostStoreEvent.java
index 1e9882cad14..0a0e294b7d4 100644
--- a/core/transaction/src/main/java/org/apache/causeway/core/transaction/changetracking/events/PostStoreEvent.java
+++ b/core/transaction/src/main/java/org/apache/causeway/core/transaction/changetracking/events/PostStoreEvent.java
@@ -18,15 +18,9 @@
  */
 package org.apache.causeway.core.transaction.changetracking.events;
 
-import lombok.Value;
-
 /**
- *
  * @since 2.0
- *
  */
-@Value(staticConstructor = "of")
-public class PostStoreEvent {
+public record PostStoreEvent(Object persistableObject) {
 
-    private final Object persistableObject;
 }
diff --git a/core/transaction/src/main/java/org/apache/causeway/core/transaction/changetracking/events/PreStoreEvent.java b/core/transaction/src/main/java/org/apache/causeway/core/transaction/changetracking/events/PreStoreEvent.java
index ba8e9aaf1b2..db3334348ed 100644
--- a/core/transaction/src/main/java/org/apache/causeway/core/transaction/changetracking/events/PreStoreEvent.java
+++ b/core/transaction/src/main/java/org/apache/causeway/core/transaction/changetracking/events/PreStoreEvent.java
@@ -18,15 +18,9 @@
  */
 package org.apache.causeway.core.transaction.changetracking.events;
 
-import lombok.Value;
-
 /**
- *
  * @since 2.0
- *
  */
-@Value(staticConstructor = "of")
-public class PreStoreEvent {
+public record PreStoreEvent(Object persistableObject) {
 
-    private final Object persistableObject;
 }
diff --git a/core/transaction/src/main/java/org/apache/causeway/core/transaction/changetracking/events/TimestampService.java b/core/transaction/src/main/java/org/apache/causeway/core/transaction/changetracking/events/TimestampService.java
index 62ae85d2fcb..7af0148b740 100644
--- a/core/transaction/src/main/java/org/apache/causeway/core/transaction/changetracking/events/TimestampService.java
+++ b/core/transaction/src/main/java/org/apache/causeway/core/transaction/changetracking/events/TimestampService.java
@@ -47,7 +47,7 @@ public class TimestampService {
     @EventListener(PreStoreEvent.class)
     public void onPreStore(PreStoreEvent event) {
 
-        var persistableObject = event.getPersistableObject();
+        var persistableObject = event.persistableObject();
 
         if(persistableObject instanceof OnUpdatedBy) {
             ((OnUpdatedBy)persistableObject).setUpdatedBy(userService.currentUserNameElseNobody());