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 9961569386d CAUSEWAY-3883: WrapperInvocation to capture invocation
specifics
9961569386d is described below
commit 9961569386d5a6de9e8d0ca7cfe0ef6862953c2a
Author: Andi Huber <[email protected]>
AuthorDate: Wed Jun 18 13:59:34 2025 +0200
CAUSEWAY-3883: WrapperInvocation to capture invocation specifics
---
.../applib/services/wrapper/WrappingObject.java | 9 +-
.../runtime/wrap/WrapperInvocationHandler.java | 57 +++---
.../wrapper/WrapperFactoryDefault.java | 15 +-
.../handlers/DomainObjectInvocationHandler.java | 196 ++++++++++-----------
.../wrapper/handlers/PluralInvocationHandler.java | 18 +-
.../wrapper/handlers/ProxyGenerator.java | 31 +++-
.../wrapper/WrapperFactoryDefaultTest.java | 2 +-
.../ProxyCreatorTestUsingCodegenPlugin.java | 25 ++-
8 files changed, 174 insertions(+), 179 deletions(-)
diff --git
a/api/applib/src/main/java/org/apache/causeway/applib/services/wrapper/WrappingObject.java
b/api/applib/src/main/java/org/apache/causeway/applib/services/wrapper/WrappingObject.java
index 1374dd7f01d..f5a1827c0f4 100644
---
a/api/applib/src/main/java/org/apache/causeway/applib/services/wrapper/WrappingObject.java
+++
b/api/applib/src/main/java/org/apache/causeway/applib/services/wrapper/WrappingObject.java
@@ -49,9 +49,12 @@ public interface WrappingObject {
final static List<AdditionalField> ADDITIONAL_FIELDS = List.of(
new AdditionalField(ORIGIN_FIELD_NAME,
WrappingObject.Origin.class, Modifier.PROTECTED));
- record Origin(Object pojo) {
- public static Origin empty() {
- return new Origin(null);
+ record Origin(Object pojo, SyncControl syncControl, boolean isFallback) {
+ public static Origin fallback(Object target) {
+ return new Origin(target, SyncControl.control().withNoExecute(),
true);
+ }
+ public Origin(Object pojo, SyncControl syncControl) {
+ this(pojo, syncControl, false);
}
}
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
index 618d102cf94..92f9f6cf450 100644
---
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
@@ -20,38 +20,35 @@
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
+import java.util.Objects;
import org.jspecify.annotations.NonNull;
-import org.apache.causeway.applib.services.wrapper.WrapperFactory;
import org.apache.causeway.applib.services.wrapper.WrappingObject;
-import org.apache.causeway.applib.services.wrapper.control.SyncControl;
-import org.apache.causeway.applib.services.wrapper.events.InteractionEvent;
+import org.apache.causeway.applib.services.wrapper.control.ExecutionMode;
import org.apache.causeway.commons.internal._Constants;
-import org.apache.causeway.core.metamodel.context.MetaModelContext;
public interface WrapperInvocationHandler extends InvocationHandler {
- Context context();
+ ClassMetaData classMetaData();
- default Method equalsMethod() { return context().equalsMethod(); }
- default Method hashCodeMethod() { return context().hashCodeMethod(); }
- default Method toStringMethod() { return context().toStringMethod(); }
+ Object invoke(WrapperInvocation wrapperInvocation) throws Throwable;
- public record Context(
+ @Override
+ default Object invoke(Object target, Method method, Object[] args) throws
Throwable {
+ return invoke(WrapperInvocation.of(target, method, args));
+ }
+
+ public record ClassMetaData(
/** underlying class that is to be proxied */
Class<?> pojoClass,
- WrapperFactory wrapperFactory,
- SyncControl syncControl,
Method equalsMethod,
Method hashCodeMethod,
Method toStringMethod) {
- public static Context of(
- final @NonNull MetaModelContext mmc,
- final @NonNull Object pojo,
- final SyncControl syncControl) {
+ public static ClassMetaData of(
+ final @NonNull Object pojo) {
var pojoClass = pojo.getClass();
try {
@@ -60,8 +57,7 @@ public static Context of(
var toStringMethod = pojoClass.getMethod("toString",
_Constants.emptyClasses);
return new WrapperInvocationHandler
- .Context(pojoClass, mmc.getWrapperFactory(),
- syncControl, equalsMethod, hashCodeMethod,
toStringMethod);
+ .ClassMetaData(pojoClass, equalsMethod,
hashCodeMethod, toStringMethod);
} catch (final NoSuchMethodException e) {
// ///CLOVER:OFF
@@ -70,21 +66,34 @@ public static Context of(
}
}
- public WrappingObject.Origin origin(WrappingObject wrappingObject) {
- return WrappingObject.getOrigin(wrappingObject);
- }
-
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;
+ }
+
+ public record WrapperInvocation(
+ WrappingObject.Origin origin,
+ Method method,
+ Object[] args) {
+
+ static WrapperInvocation of(Object target, Method method, Object[]
args) {
+ Objects.requireNonNull(target);
+ var origin = target instanceof WrappingObject wrappingObject
+ ? WrappingObject.getOrigin(wrappingObject)
+ : WrappingObject.Origin.fallback(target);
+ return new WrapperInvocation(origin, method, args);
}
+ public boolean shouldEnforceRules() {
+ return
!origin().syncControl().getExecutionModes().contains(ExecutionMode.SKIP_RULE_VALIDATION);
+ }
+
+ public boolean shouldExecute() {
+ return
!origin().syncControl().getExecutionModes().contains(ExecutionMode.SKIP_EXECUTION);
+ }
}
}
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 4bfb8cf8212..1d591931312 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
@@ -102,7 +102,6 @@
import org.apache.causeway.core.runtimeservices.session.InteractionIdGenerator;
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.ProxyGenerator;
import org.apache.causeway.schema.cmd.v2.CommandDto;
@@ -301,12 +300,7 @@ public <T,R> T asyncWrap(
}
if (asyncControl.isCheckRules()) {
- var doih = new DomainObjectInvocationHandler<>(
- domainObject,
- null, // mixeeAdapter ignored
- targetAdapter,
- control().withNoExecute(),
- null);
+ var doih = proxyGenerator.handlerForRegular(domainObject,
targetAdapter);
doih.invoke(domainObject, method, args);
}
@@ -347,12 +341,7 @@ public <T, R> T asyncWrapMixin(
}
if (asyncControl.isCheckRules()) {
- var doih = new DomainObjectInvocationHandler<>(
- mixin,
- mixeeAdapter,
- mixinAdapter,
- control().withNoExecute(),
- null);
+ var doih = proxyGenerator.handlerForMixin(mixin, mixeeAdapter,
mixinAdapter);
doih.invoke(mixin, method, args);
}
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 f02655ffd91..89d576f1185 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
@@ -21,7 +21,6 @@
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;
-import java.util.Objects;
import java.util.function.Supplier;
import java.util.stream.Stream;
@@ -31,8 +30,6 @@
import org.apache.causeway.applib.services.wrapper.HiddenException;
import org.apache.causeway.applib.services.wrapper.InvalidException;
import org.apache.causeway.applib.services.wrapper.WrappingObject;
-import org.apache.causeway.applib.services.wrapper.control.ExecutionMode;
-import org.apache.causeway.applib.services.wrapper.control.SyncControl;
import
org.apache.causeway.applib.services.wrapper.events.CollectionAccessEvent;
import org.apache.causeway.applib.services.wrapper.events.InteractionEvent;
import org.apache.causeway.applib.services.wrapper.events.PropertyAccessEvent;
@@ -78,11 +75,11 @@
* @param <T> type of delegate
*/
@Log4j2
-public final class DomainObjectInvocationHandler<T>
+final class DomainObjectInvocationHandler<T>
implements WrapperInvocationHandler {
@Getter(onMethod_ = {@Override}) @Accessors(fluent=true)
- private final WrapperInvocationHandler.Context context;
+ private final WrapperInvocationHandler.ClassMetaData classMetaData;
private final ProxyGenerator proxyGenerator;
private final MetaModelContext mmc;
@@ -114,19 +111,15 @@ public DomainObjectInvocationHandler(
final T domainObject,
final ManagedObject mixeeAdapter, // ignored if not handling a
mixin
final ManagedObject targetAdapter,
- final SyncControl syncControl,
final ProxyGenerator proxyGenerator) {
this.mmc = targetAdapter.objSpec().getMetaModelContext();
- this.context = WrapperInvocationHandler.Context.of(
- mmc,
- domainObject,
- syncControl);
+ this.classMetaData =
WrapperInvocationHandler.ClassMetaData.of(domainObject);
this.proxyGenerator = proxyGenerator;
var _titleMethod = (Method)null;
try {
- _titleMethod = context().pojoClass().getMethod("title",
_Constants.emptyClasses);
+ _titleMethod = classMetaData().pojoClass().getMethod("title",
_Constants.emptyClasses);
} catch (final NoSuchMethodException e) {
// ignore
}
@@ -146,52 +139,46 @@ public DomainObjectInvocationHandler(
this.mixeeAdapter = mixeeAdapter;
}
- /**
- * @param target - either the pojo directly or the proxy instance that is
the target of invocation
- * @param method - the method invoked on the proxy
- * @param args - the args to the method invoked on the proxy
- * @throws Throwable
- */
@Override
- public Object invoke(final Object target, final Method method, final
Object[] args) throws Throwable {
-
- Objects.requireNonNull(target);
- final var delegate = target instanceof WrappingObject wrappingObject
- ? context().origin(wrappingObject).pojo()
- : target; // fallback to argument directly passed in
+ public Object invoke(WrapperInvocation wrapperInvocation) throws Throwable
{
+
+ final Object target = wrapperInvocation.origin().pojo();
+ final Method method = wrapperInvocation.method();
+ final Object[] args = wrapperInvocation.args();
+ var syncControl = wrapperInvocation.origin().syncControl();
- if (context().isObjectMethod(method)
+ if (classMetaData().isObjectMethod(method)
|| isEnhancedEntityMethod(method)) {
- return method.invoke(delegate, args);
+ return method.invoke(target, args);
}
- final ManagedObject targetAdapter =
mmc.getObjectManager().adapt(delegate);
+ final ManagedObject targetAdapter =
mmc.getObjectManager().adapt(target);
if(!targetAdapter.specialization().isMixin()) {
MmAssertionUtils.assertIsBookmarkSupported(targetAdapter);
}
if (method.equals(titleMethod)) {
- return handleTitleMethod(targetAdapter);
+ return handleTitleMethod(wrapperInvocation, targetAdapter);
}
final ObjectSpecification targetSpec = targetAdapter.objSpec();
var resolvedMethod = _GenericResolver.resolveMethod(method,
targetSpec.getCorrespondingClass())
.orElseThrow();
- if(target instanceof WrappingObject) {
+ if(!wrapperInvocation.origin().isFallback()) {
if (method.equals(__causeway_originMethod)) {
- return delegate;
+ return wrapperInvocation.origin();
}
// save method, through the proxy
if (method.equals(__causeway_saveMethod)) {
- return handleSaveMethod(targetAdapter, targetSpec);
+ return handleSaveMethod(wrapperInvocation, targetAdapter,
targetSpec);
}
if (method.equals(__causeway_executionModes)) {
- return context().syncControl().getExecutionModes();
+ return syncControl.getExecutionModes();
}
}
@@ -204,7 +191,7 @@ public Object invoke(final Object target, final Method
method, final Object[] ar
}
if (intent == Intent.DEFAULTS || intent ==
Intent.CHOICES_OR_AUTOCOMPLETE) {
- return method.invoke(delegate, args);
+ return method.invoke(target, args);
}
if (objectMember.isOneToOneAssociation()) {
@@ -216,11 +203,11 @@ public Object invoke(final Object target, final Method
method, final Object[] ar
final OneToOneAssociation otoa = (OneToOneAssociation)
objectMember;
if (intent == Intent.ACCESSOR) {
- return handleGetterMethodOnProperty(targetAdapter, args, otoa);
+ return handleGetterMethodOnProperty(wrapperInvocation,
targetAdapter, args, otoa);
}
if (intent == Intent.MODIFY_PROPERTY || intent ==
Intent.INITIALIZATION) {
- return handleSetterMethodOnProperty(targetAdapter, args, otoa);
+ return handleSetterMethodOnProperty(wrapperInvocation,
targetAdapter, args, otoa);
}
}
if (objectMember.isOneToManyAssociation()) {
@@ -231,7 +218,7 @@ public Object invoke(final Object target, final Method
method, final Object[] ar
final OneToManyAssociation otma = (OneToManyAssociation)
objectMember;
if (intent == Intent.ACCESSOR) {
- return handleGetterMethodOnCollection(targetAdapter, args,
otma, memberId);
+ return handleGetterMethodOnCollection(wrapperInvocation,
targetAdapter, args, otma, memberId);
}
}
@@ -255,13 +242,13 @@ public Object invoke(final Object target, final Method
method, final Object[] ar
if (mixinMember != null) {
if(mixinMember instanceof ObjectAction) {
- return handleActionMethod(mixeeAdapter, args,
(ObjectAction)mixinMember);
+ return handleActionMethod(wrapperInvocation,
mixeeAdapter, args, (ObjectAction)mixinMember);
}
if(mixinMember instanceof OneToOneAssociation) {
- return handleGetterMethodOnProperty(mixeeAdapter, new
Object[0], (OneToOneAssociation)mixinMember);
+ return handleGetterMethodOnProperty(wrapperInvocation,
mixeeAdapter, new Object[0], (OneToOneAssociation)mixinMember);
}
if(mixinMember instanceof OneToManyAssociation) {
- return handleGetterMethodOnCollection(mixeeAdapter,
new Object[0], (OneToManyAssociation)mixinMember, memberId);
+ return
handleGetterMethodOnCollection(wrapperInvocation, mixeeAdapter, new Object[0],
(OneToManyAssociation)mixinMember, memberId);
}
} else {
throw _Exceptions.illegalState(String.format(
@@ -270,7 +257,7 @@ public Object invoke(final Object target, final Method
method, final Object[] ar
}
// this is just a regular non-mixin action.
- return handleActionMethod(targetAdapter, args, objectAction);
+ return handleActionMethod(wrapperInvocation, targetAdapter, args,
objectAction);
}
throw new UnsupportedOperationException(String.format("Unknown member
type '%s'", objectMember));
@@ -298,8 +285,8 @@ private static ObjectMember determineMixinMember(
// throw new RuntimeException("Unable to find the mixed-in action
corresponding to " + objectAction.getIdentifier().toFullIdentityString());
}
- public InteractionInitiatedBy getInteractionInitiatedBy() {
- return shouldEnforceRules()
+ public InteractionInitiatedBy getInteractionInitiatedBy(final
WrapperInvocation wrapperInvocation) {
+ return wrapperInvocation.shouldEnforceRules()
? InteractionInitiatedBy.USER
: InteractionInitiatedBy.FRAMEWORK;
}
@@ -310,28 +297,32 @@ private boolean isEnhancedEntityMethod(final Method
method) {
: false;
}
- private Object handleTitleMethod(final ManagedObject targetAdapter) {
+ private Object handleTitleMethod(
+ final WrapperInvocation wrapperInvocation,
+ final ManagedObject targetAdapter) {
var targetNoSpec = targetAdapter.objSpec();
var titleContext = targetNoSpec
.createTitleInteractionContext(targetAdapter,
InteractionInitiatedBy.FRAMEWORK);
var titleEvent = titleContext.createInteractionEvent();
- context().notifyListeners(titleEvent);
+ mmc.getWrapperFactory().notifyListeners(titleEvent);
return titleEvent.getTitle();
}
private Object handleSaveMethod(
- final ManagedObject targetAdapter, final ObjectSpecification
targetNoSpec) {
+ final WrapperInvocation wrapperInvocation,
+ final ManagedObject targetAdapter,
+ final ObjectSpecification targetNoSpec) {
- runValidationTask(()->{
+ runValidationTask(wrapperInvocation, ()->{
var interactionResult =
- targetNoSpec.isValidResult(targetAdapter,
getInteractionInitiatedBy());
+ targetNoSpec.isValidResult(targetAdapter,
getInteractionInitiatedBy(wrapperInvocation));
notifyListenersAndVetoIfRequired(interactionResult);
});
var spec = targetAdapter.objSpec();
if(spec.isEntity()) {
- return runExecutionTask(()->{
+ return runExecutionTask(wrapperInvocation, ()->{
MmEntityUtils.persistInCurrentTransaction(targetAdapter);
return null;
});
@@ -341,24 +332,25 @@ private Object handleSaveMethod(
}
private Object handleGetterMethodOnProperty(
+ final WrapperInvocation wrapperInvocation,
final ManagedObject targetAdapter,
final Object[] args,
final OneToOneAssociation property) {
zeroArgsElseThrow(args, "get");
- runValidationTask(()->{
- checkVisibility(targetAdapter, property);
+ runValidationTask(wrapperInvocation, ()->{
+ checkVisibility(wrapperInvocation, targetAdapter, property);
});
- return runExecutionTask(()->{
+ return runExecutionTask(wrapperInvocation, ()->{
- var interactionInitiatedBy = getInteractionInitiatedBy();
+ var interactionInitiatedBy =
getInteractionInitiatedBy(wrapperInvocation);
var currentReferencedAdapter = property.get(targetAdapter,
interactionInitiatedBy);
var currentReferencedObj =
MmUnwrapUtils.single(currentReferencedAdapter);
- context().notifyListeners(new PropertyAccessEvent(
+ mmc.getWrapperFactory().notifyListeners(new PropertyAccessEvent(
targetAdapter.getPojo(),
property.getFeatureIdentifier(),
currentReferencedObj));
@@ -369,34 +361,36 @@ private Object handleGetterMethodOnProperty(
}
private Object handleSetterMethodOnProperty(
+ final WrapperInvocation wrapperInvocation,
final ManagedObject targetAdapter,
final Object[] args,
final OneToOneAssociation property) {
var singleArg = singleArgUnderlyingElseNull(args, "setter");
- runValidationTask(()->{
- checkVisibility(targetAdapter, property);
- checkUsability(targetAdapter, property);
+ runValidationTask(wrapperInvocation, ()->{
+ checkVisibility(wrapperInvocation, targetAdapter, property);
+ checkUsability(wrapperInvocation, targetAdapter, property);
});
var argumentAdapter = property.getObjectManager().adapt(singleArg);
- runValidationTask(()->{
+ runValidationTask(wrapperInvocation, ()->{
var interactionResult = property.isAssociationValid(
- targetAdapter, argumentAdapter,
getInteractionInitiatedBy())
+ targetAdapter, argumentAdapter,
getInteractionInitiatedBy(wrapperInvocation))
.getInteractionResult();
notifyListenersAndVetoIfRequired(interactionResult);
});
- return runExecutionTask(()->{
- property.set(targetAdapter, argumentAdapter,
getInteractionInitiatedBy());
+ return runExecutionTask(wrapperInvocation, ()->{
+ property.set(targetAdapter, argumentAdapter,
getInteractionInitiatedBy(wrapperInvocation));
return null;
});
}
private Object handleGetterMethodOnCollection(
+ final WrapperInvocation wrapperInvocation,
final ManagedObject targetAdapter,
final Object[] args,
final OneToManyAssociation collection,
@@ -404,13 +398,13 @@ private Object handleGetterMethodOnCollection(
zeroArgsElseThrow(args, "get");
- runValidationTask(()->{
- checkVisibility(targetAdapter, collection);
+ runValidationTask(wrapperInvocation, ()->{
+ checkVisibility(wrapperInvocation, targetAdapter, collection);
});
- return runExecutionTask(()->{
+ return runExecutionTask(wrapperInvocation, ()->{
- var interactionInitiatedBy = getInteractionInitiatedBy();
+ var interactionInitiatedBy =
getInteractionInitiatedBy(wrapperInvocation);
var currentReferencedAdapter = collection.get(targetAdapter,
interactionInitiatedBy);
var currentReferencedObj =
MmUnwrapUtils.single(currentReferencedAdapter);
@@ -418,51 +412,47 @@ private Object handleGetterMethodOnCollection(
var collectionAccessEvent = new
CollectionAccessEvent(currentReferencedObj, collection.getFeatureIdentifier());
if (currentReferencedObj instanceof Collection) {
- var collectionViewObject = lookupWrappingObject(
- (Collection<?>) currentReferencedObj, collection);
- context().notifyListeners(collectionAccessEvent);
+ var collectionViewObject = wrapCollection(
+ (Collection<?>) currentReferencedObj,
+ collection);
+ mmc.getWrapperFactory().notifyListeners(collectionAccessEvent);
return collectionViewObject;
} else if (currentReferencedObj instanceof Map) {
- var mapViewObject = lookupWrappingObject((Map<?, ?>)
currentReferencedObj,
+ var mapViewObject = wrapMap(
+ (Map<?, ?>) currentReferencedObj,
collection);
- context().notifyListeners(collectionAccessEvent);
+ mmc.getWrapperFactory().notifyListeners(collectionAccessEvent);
return mapViewObject;
}
var msg = String.format("Collection type '%s' not supported by
framework", currentReferencedObj.getClass().getName());
throw new IllegalArgumentException(msg);
-
});
}
- private Collection<?> lookupWrappingObject(
+ private Collection<?> wrapCollection(
final Collection<?> collectionToLookup,
final OneToManyAssociation otma) {
- if (collectionToLookup instanceof WrappingObject) {
- return collectionToLookup;
- }
if(proxyGenerator == null) {
throw new IllegalStateException("Unable to create proxy for
collection; "
+ "proxyContextHandler not provided");
}
- return proxyGenerator.collectionProxy(collectionToLookup,
context().syncControl(), otma);
+ return proxyGenerator.collectionProxy(collectionToLookup, otma);
}
- private Map<?, ?> lookupWrappingObject(
+ private Map<?, ?> wrapMap(
final Map<?, ?> mapToLookup,
final OneToManyAssociation otma) {
- if (mapToLookup instanceof WrappingObject) {
- return mapToLookup;
- }
if(proxyGenerator == null) {
throw new IllegalStateException("Unable to create proxy for
collection; "
+ "proxyContextHandler not provided");
}
- return proxyGenerator.mapProxy(mapToLookup, context().syncControl(),
otma);
+ return proxyGenerator.mapProxy(mapToLookup, otma);
}
private Object handleActionMethod(
+ final WrapperInvocation wrapperInvocation,
final ManagedObject targetAdapter,
final Object[] args,
final ObjectAction objectAction) {
@@ -479,14 +469,14 @@ private Object handleActionMethod(
: ManagedObject.empty(paramSpec);
}));
- runValidationTask(()->{
- checkVisibility(targetAdapter, objectAction);
- checkUsability(targetAdapter, objectAction);
- checkValidity(head, objectAction, argAdapters);
+ runValidationTask(wrapperInvocation, ()->{
+ checkVisibility(wrapperInvocation, targetAdapter, objectAction);
+ checkUsability(wrapperInvocation, targetAdapter, objectAction);
+ checkValidity(wrapperInvocation, head, objectAction, argAdapters);
});
- return runExecutionTask(()->{
- var interactionInitiatedBy = getInteractionInitiatedBy();
+ return runExecutionTask(wrapperInvocation, ()->{
+ var interactionInitiatedBy =
getInteractionInitiatedBy(wrapperInvocation);
var returnedAdapter = objectAction.execute(
head, argAdapters,
@@ -498,12 +488,13 @@ private Object handleActionMethod(
}
private void checkValidity(
+ final WrapperInvocation wrapperInvocation,
final ActionInteractionHead head,
final ObjectAction objectAction,
final Can<ManagedObject> argAdapters) {
var interactionResult = objectAction
- .isArgumentSetValid(head, argAdapters,
getInteractionInitiatedBy())
+ .isArgumentSetValid(head, argAdapters,
getInteractionInitiatedBy(wrapperInvocation))
.getInteractionResult();
notifyListenersAndVetoIfRequired(interactionResult);
}
@@ -523,21 +514,23 @@ private Object underlying(final Object arg) {
private final Where where = Where.ANYWHERE;
private void checkVisibility(
+ final WrapperInvocation wrapperInvocation,
final ManagedObject targetObjectAdapter,
final ObjectMember objectMember) {
- var visibleConsent = objectMember.isVisible(targetObjectAdapter,
getInteractionInitiatedBy(), where);
+ var visibleConsent = objectMember.isVisible(targetObjectAdapter,
getInteractionInitiatedBy(wrapperInvocation), where);
var interactionResult = visibleConsent.getInteractionResult();
notifyListenersAndVetoIfRequired(interactionResult);
}
private void checkUsability(
+ final WrapperInvocation wrapperInvocation,
final ManagedObject targetObjectAdapter,
final ObjectMember objectMember) {
var interactionResult = objectMember.isUsable(
targetObjectAdapter,
- getInteractionInitiatedBy(),
+ getInteractionInitiatedBy(wrapperInvocation),
where)
.getInteractionResult();
notifyListenersAndVetoIfRequired(interactionResult);
@@ -547,7 +540,8 @@ private void checkUsability(
private void notifyListenersAndVetoIfRequired(final InteractionResult
interactionResult) {
var interactionEvent = interactionResult.getInteractionEvent();
- context().notifyListeners(interactionEvent);
+
+ mmc.getWrapperFactory().notifyListeners(interactionEvent);
if (interactionEvent.isVeto()) {
throw toException(interactionEvent);
}
@@ -579,39 +573,31 @@ private InteractionException toException(final
InteractionEvent interactionEvent
// -- HELPER
- private boolean shouldEnforceRules() {
- return
!context().syncControl().getExecutionModes().contains(ExecutionMode.SKIP_RULE_VALIDATION);
- }
-
- private boolean shouldExecute() {
- return
!context().syncControl().getExecutionModes().contains(ExecutionMode.SKIP_EXECUTION);
- }
-
- private void runValidationTask(final Runnable task) {
- if(!shouldEnforceRules()) {
+ private void runValidationTask(final WrapperInvocation wrapperInvocation,
final Runnable task) {
+ if(!wrapperInvocation.shouldEnforceRules()) {
return;
}
try {
task.run();
} catch(Exception ex) {
- handleException(ex);
+ handleException(wrapperInvocation, ex);
}
}
- private <X> X runExecutionTask(final Supplier<X> task) {
- if(!shouldExecute()) {
+ private <X> X runExecutionTask(final WrapperInvocation wrapperInvocation,
final Supplier<X> task) {
+ if(!wrapperInvocation.shouldExecute()) {
return null;
}
try {
return task.get();
} catch(Exception ex) {
- return _Casts.uncheckedCast(handleException(ex));
+ return _Casts.uncheckedCast(handleException(wrapperInvocation,
ex));
}
}
@SneakyThrows
- private Object handleException(final Exception ex) {
- var exceptionHandler = context().syncControl().getExceptionHandler()
+ private Object handleException(WrapperInvocation wrapperInvocation, final
Exception ex) {
+ var exceptionHandler =
wrapperInvocation.origin().syncControl().getExceptionHandler()
.orElse(null);
if(exceptionHandler==null) {
diff --git
a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/PluralInvocationHandler.java
b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/PluralInvocationHandler.java
index d7fcbfdfcf7..40904c94911 100644
---
a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/PluralInvocationHandler.java
+++
b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/PluralInvocationHandler.java
@@ -18,11 +18,11 @@
*/
package org.apache.causeway.core.runtimeservices.wrapper.handlers;
+import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;
-import org.apache.causeway.applib.services.wrapper.control.SyncControl;
import
org.apache.causeway.applib.services.wrapper.events.CollectionMethodEvent;
import org.apache.causeway.commons.internal.assertions._Assert;
import org.apache.causeway.commons.semantics.CollectionSemantics;
@@ -37,16 +37,15 @@
*/
record PluralInvocationHandler<T, P>(
P collectionOrMapToBeProxied,
- WrapperInvocationHandler.Context context,
+ WrapperInvocationHandler.ClassMetaData classMetaData,
OneToManyAssociation oneToManyAssociation,
CollectionSemantics collectionSemantics
- ) implements WrapperInvocationHandler {
+ ) implements InvocationHandler {
// -- FACTORIES
static <T, C extends Collection<?>> PluralInvocationHandler<T, C>
forCollection(
final C collectionToBeProxied,
- final SyncControl syncControl,
final OneToManyAssociation otma) {
_Assert.assertTrue(Collection.class.isAssignableFrom(collectionToBeProxied.getClass()),
@@ -54,14 +53,13 @@ static <T, C extends Collection<?>>
PluralInvocationHandler<T, C> forCollection(
PluralInvocationHandler.class.getName() +
".forCollection(..)",
collectionToBeProxied.getClass()));
- return new PluralInvocationHandler<>(collectionToBeProxied,
syncControl, otma,
+ return new PluralInvocationHandler<>(collectionToBeProxied, otma,
CollectionSemantics
.valueOfElseFail(collectionToBeProxied.getClass()));
}
static <T, M extends Map<?,?>> PluralInvocationHandler<T, M> forMap(
final M mapToBeProxied,
- final SyncControl syncControl,
final OneToManyAssociation otma) {
_Assert.assertTrue(Map.class.isAssignableFrom(mapToBeProxied.getClass()),
@@ -69,7 +67,7 @@ static <T, M extends Map<?,?>> PluralInvocationHandler<T, M>
forMap(
PluralInvocationHandler.class.getName() + ".forMap(..)",
mapToBeProxied.getClass()));
- return new PluralInvocationHandler<>(mapToBeProxied, syncControl, otma,
+ return new PluralInvocationHandler<>(mapToBeProxied, otma,
CollectionSemantics.MAP);
}
@@ -77,13 +75,11 @@ static <T, M extends Map<?,?>> PluralInvocationHandler<T,
M> forMap(
private PluralInvocationHandler(
final P collectionOrMapToBeProxied,
- final SyncControl syncControl,
final OneToManyAssociation otma,
final CollectionSemantics collectionSemantics) {
this(collectionOrMapToBeProxied,
-
WrapperInvocationHandler.Context.of(otma.getMetaModelContext(),
- collectionOrMapToBeProxied, syncControl),
+
WrapperInvocationHandler.ClassMetaData.of(collectionOrMapToBeProxied),
otma, collectionSemantics);
}
@@ -103,7 +99,7 @@ public Object invoke(final Object collectionObject, final
Method method, final O
method.getName(),
args,
returnValueObj);
- context().notifyListeners(event);
+ oneToManyAssociation().getWrapperFactory().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 245827857b1..259038c1d88 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
@@ -18,6 +18,7 @@
*/
package org.apache.causeway.core.runtimeservices.wrapper.handlers;
+import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Collection;
import java.util.Map;
@@ -45,10 +46,9 @@ public <T> T objectProxy(
domainObject,
null, // mixeeAdapter ignored
adapter,
- syncControl,
this);
- return instantiateProxy(invocationHandler, new
WrappingObject.Origin(domainObject));
+ return instantiateProxy(invocationHandler, new
WrappingObject.Origin(domainObject, syncControl));
}
public <T> T mixinProxy(
@@ -61,10 +61,9 @@ public <T> T mixinProxy(
mixin,
mixeeAdapter,
mixinAdapter,
- syncControl,
this);
- return instantiateProxy(invocationHandler, new
WrappingObject.Origin(mixin));
+ return instantiateProxy(invocationHandler, new
WrappingObject.Origin(mixin, syncControl));
}
/**
@@ -73,11 +72,10 @@ public <T> T mixinProxy(
*/
public <T, E> Collection<E> collectionProxy(
final Collection<E> collectionToBeProxied,
- final SyncControl syncControl,
final OneToManyAssociation otma) {
var collectionInvocationHandler = PluralInvocationHandler
- .forCollection(collectionToBeProxied, syncControl, otma);
+ .forCollection(collectionToBeProxied, otma);
var proxyBase = CollectionSemantics
.valueOfElseFail(collectionToBeProxied.getClass())
@@ -93,19 +91,18 @@ public <T, E> Collection<E> collectionProxy(
*/
public <T, P, Q> Map<P, Q> mapProxy(
final Map<P, Q> mapToBeProxied,
- final SyncControl syncControl,
final OneToManyAssociation otma) {
var proxyBase = Map.class;
return instantiatePluralProxy(_Casts.uncheckedCast(proxyBase),
- PluralInvocationHandler.forMap(mapToBeProxied, syncControl,
otma));
+ PluralInvocationHandler.forMap(mapToBeProxied, otma));
}
// -- HELPER
<T> T instantiateProxy(final WrapperInvocationHandler handler,
WrappingObject.Origin origin) {
- return
_Casts.uncheckedCast(instantiateProxy(handler.context().pojoClass(), handler,
origin));
+ return
_Casts.uncheckedCast(instantiateProxy(handler.classMetaData().pojoClass(),
handler, origin));
}
/**
@@ -128,5 +125,21 @@ private <T, P> P instantiatePluralProxy(final Class<T>
base, final PluralInvocat
pluralInvocationHandler);
return _Casts.uncheckedCast(proxyWithoutFields);
}
+
+ public <T> InvocationHandler handlerForRegular(@NonNull T domainObject,
ManagedObject targetAdapter) {
+ return new DomainObjectInvocationHandler<>(
+ domainObject,
+ null, // mixeeAdapter ignored
+ targetAdapter,
+ null);
+ }
+
+ public <T> InvocationHandler handlerForMixin(T mixin, ManagedObject
mixeeAdapter, ManagedObject mixinAdapter) {
+ return new DomainObjectInvocationHandler<>(
+ mixin,
+ mixeeAdapter,
+ mixinAdapter,
+ null);
+ }
}
diff --git
a/core/runtimeservices/src/test/java/org/apache/causeway/core/runtimeservices/wrapper/WrapperFactoryDefaultTest.java
b/core/runtimeservices/src/test/java/org/apache/causeway/core/runtimeservices/wrapper/WrapperFactoryDefaultTest.java
index 57176acd31a..3534620326a 100644
---
a/core/runtimeservices/src/test/java/org/apache/causeway/core/runtimeservices/wrapper/WrapperFactoryDefaultTest.java
+++
b/core/runtimeservices/src/test/java/org/apache/causeway/core/runtimeservices/wrapper/WrapperFactoryDefaultTest.java
@@ -55,7 +55,7 @@ public void __causeway_save() {
@Override
public WrappingObject.Origin __causeway_origin() {
- return new WrappingObject.Origin(wrappedObject);
+ return new WrappingObject.Origin(wrappedObject,
SyncControl.control());
}
@Override
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 32732eb18a9..d562f6887ac 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
@@ -18,7 +18,6 @@
*/
package org.apache.causeway.core.runtimeservices.wrapper.handlers;
-import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
@@ -32,6 +31,7 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.apache.causeway.applib.services.wrapper.WrappingObject;
+import org.apache.causeway.applib.services.wrapper.control.SyncControl;
import
org.apache.causeway.core.codegen.bytebuddy.services.ProxyFactoryServiceByteBuddy;
import org.apache.causeway.core.runtime.wrap.WrapperInvocationHandler;
@@ -60,16 +60,9 @@ public void setName(final String name) {
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(
- Employee.class, null, null, null, null, null);
+ private final WrapperInvocationHandler.ClassMetaData classMetaData =
new WrapperInvocationHandler.ClassMetaData(
+ Employee.class, null, null, null);
-
- @Override
- public Object invoke(final Object proxy, final Method method, final
Object[] args) throws Throwable {
- invoked.add(method.getName());
- return "hi";
- }
-
@Getter @Setter
private boolean resolveObjectChangedEnabled = false;
@@ -78,8 +71,14 @@ public boolean wasInvoked(final String methodName) {
}
@Override
- public WrapperInvocationHandler.Context context() {
- return context;
+ public WrapperInvocationHandler.ClassMetaData classMetaData() {
+ return classMetaData;
+ }
+
+ @Override
+ public Object invoke(WrapperInvocation wrapperInvocation) throws
Throwable {
+ invoked.add(wrapperInvocation.method().getName());
+ return "hi";
}
}
@@ -88,7 +87,7 @@ public WrapperInvocationHandler.Context context() {
void proxyShouldDelegateCalls() {
final WrapperInvocationHandlerForTest handler = new
WrapperInvocationHandlerForTest();
- final Employee proxyOfEmployee =
proxyGenerator.instantiateProxy(handler, new
WrappingObject.Origin(handler.delegate));
+ final Employee proxyOfEmployee =
proxyGenerator.instantiateProxy(handler, new
WrappingObject.Origin(handler.delegate, SyncControl.control()));
assertNotNull(proxyOfEmployee);