You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2021/09/02 13:57:55 UTC
[isis] 02/02: ISIS-2774: adds support for enforcing member
annotations
This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git
commit 9bd81d798eec9d40314fa0b1830195d24942c4b1
Author: Andi Huber <ah...@apache.org>
AuthorDate: Thu Sep 2 15:57:40 2021 +0200
ISIS-2774: adds support for enforcing member annotations
fixes iconName facet not being imperative
some fixes to imperative orphaned method checking: ignore the event rank
when enumerating imperative facets
---
.../isis/core/metamodel/facetapi/FacetHolder.java | 7 +--
.../metamodel/facetapi/FacetHolderAbstract.java | 5 ++
.../core/metamodel/facetapi/HasFacetHolder.java | 13 +++--
.../choices/enums/EnumValueSemanticsProvider.java | 2 +-
.../method/CssClassFacetMethodFactory.java | 2 +-
.../object/icon/method/IconFacetMethodFactory.java | 22 ++++----
...Method.java => IconFacetViaIconNameMethod.java} | 29 ++++++++--
.../facets/object/layout/LayoutFacetFactory.java | 2 +-
.../annotation/TitleAnnotationFacetFactory.java | 47 ++++++++--------
.../title/methods/TitleFacetViaMethodsFactory.java | 2 +-
...tionEnforcesMetamodelContributionValidator.java | 6 ++-
.../metamodel/methods/MethodFinderOptions.java | 63 +++++++++++++---------
.../core/metamodel/methods/MethodFinderUtils.java | 25 ++++-----
.../metamodel/methods/MethodLiteralConstants.java | 19 +++++++
.../ident/icon/IconFacetMethodFactoryTest.java | 4 +-
.../object/ident/icon/IconFacetMethodTest.java | 6 +--
.../DomainModelTest_usingGoodDomain.java | 17 ++++++
.../good/ProperMemberInheritanceAbstract.java | 2 +
.../good/ProperMemberInheritanceInterface.java | 6 ++-
.../model/good/ProperMemberSupport_action.java | 15 +++---
.../model/good/ProperMemberSupport_action2.java | 13 ++---
.../model/good/ProperMemberSupport_action3.java | 13 ++---
...lWithAnnotationOptionalUsingPrivateSupport.java | 12 ++++-
23 files changed, 217 insertions(+), 115 deletions(-)
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/FacetHolder.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/FacetHolder.java
index 04f4731..25eaa64 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/FacetHolder.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/FacetHolder.java
@@ -80,7 +80,7 @@ public interface FacetHolder extends HasMetaModelContext {
* Convenience; saves having to {@link #getFacet(Class)} and then check if
* <tt>null</tt> and not a fallback.
*/
- default boolean containsNonFallbackFacet(Class<? extends Facet> facetType) {
+ default boolean containsNonFallbackFacet(final Class<? extends Facet> facetType) {
val facet = getFacet(facetType);
return facet != null
&& !facet.getPrecedence().isFallback();
@@ -90,7 +90,7 @@ public interface FacetHolder extends HasMetaModelContext {
* As {@link #containsNonFallbackFacet(Class)}, with additional requirement, that the
* facet is <i>explicit</i>, not {@link Facet.Precedence#isInferred() inferred}.
*/
- default boolean containsExplicitNonFallbackFacet(Class<? extends Facet> facetType) {
+ default boolean containsExplicitNonFallbackFacet(final Class<? extends Facet> facetType) {
val facet = getFacet(facetType);
return facet != null
&& !facet.getPrecedence().isFallback()
@@ -99,7 +99,7 @@ public interface FacetHolder extends HasMetaModelContext {
Stream<Facet> streamFacets();
- default <F extends Facet> Stream<F> streamFacets(Class<F> requiredType) {
+ default <F extends Facet> Stream<F> streamFacets(final Class<F> requiredType) {
return streamFacets()
.filter(facet->requiredType.isAssignableFrom(facet.getClass()))
.map(requiredType::cast);
@@ -117,6 +117,7 @@ public interface FacetHolder extends HasMetaModelContext {
// -- VALIDATION SUPPORT
+ Stream<FacetRanking> streamFacetRankings();
Optional<FacetRanking> getFacetRanking(Class<? extends Facet> facetType);
}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/FacetHolderAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/FacetHolderAbstract.java
index fec986b..b577e11 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/FacetHolderAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/FacetHolderAbstract.java
@@ -109,6 +109,11 @@ implements FacetHolder {
// -- VALIDATION SUPPORT
@Override
+ public Stream<FacetRanking> streamFacetRankings() {
+ return rankingByType.values().stream();
+ }
+
+ @Override
public Optional<FacetRanking> getFacetRanking(final Class<? extends Facet> facetType) {
return Optional.ofNullable(rankingByType.get(facetType));
}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/HasFacetHolder.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/HasFacetHolder.java
index e9db430..4240743 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/HasFacetHolder.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/HasFacetHolder.java
@@ -35,12 +35,12 @@ public interface HasFacetHolder extends FacetHolder {
}
@Override
- default <T extends Facet> T getFacet(Class<T> cls) {
+ default <T extends Facet> T getFacet(final Class<T> cls) {
return getFacetHolder().getFacet(cls);
}
@Override
- default boolean containsFacet(Class<? extends Facet> facetType) {
+ default boolean containsFacet(final Class<? extends Facet> facetType) {
return getFacetHolder().containsFacet(facetType);
}
@@ -50,12 +50,17 @@ public interface HasFacetHolder extends FacetHolder {
}
@Override
- default void addFacet(Facet facet) {
+ default void addFacet(final Facet facet) {
getFacetHolder().addFacet(facet);
}
@Override
- default Optional<FacetRanking> getFacetRanking(Class<? extends Facet> facetType) {
+ default Stream<FacetRanking> streamFacetRankings() {
+ return getFacetHolder().streamFacetRankings();
+ }
+
+ @Override
+ default Optional<FacetRanking> getFacetRanking(final Class<? extends Facet> facetType) {
return getFacetHolder().getFacetRanking(facetType);
}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/choices/enums/EnumValueSemanticsProvider.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/choices/enums/EnumValueSemanticsProvider.java
index fd912c0..08ddb3d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/choices/enums/EnumValueSemanticsProvider.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/choices/enums/EnumValueSemanticsProvider.java
@@ -83,7 +83,7 @@ implements EnumFacet {
defaultFor(adaptedClass));
titleMethod = MethodFinderUtils.findMethod_returningText(
- MethodFinderOptions.layoutSupport(introspectionPolicy),
+ MethodFinderOptions.objectSupport(introspectionPolicy),
getAdaptedClass(),
TITLE,
null);
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/cssclass/method/CssClassFacetMethodFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/cssclass/method/CssClassFacetMethodFactory.java
index bd66e0b..5001ed3 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/cssclass/method/CssClassFacetMethodFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/cssclass/method/CssClassFacetMethodFactory.java
@@ -48,7 +48,7 @@ extends MethodPrefixBasedFacetFactoryAbstract {
final Method method = MethodFinderUtils.findMethod(
MethodFinderOptions
- .layoutSupport(processClassContext.getIntrospectionPolicy()),
+ .objectSupport(processClassContext.getIntrospectionPolicy()),
cls, PREFIX, String.class, NO_ARG);
if (method == null) {
return;
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/icon/method/IconFacetMethodFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/icon/method/IconFacetMethodFactory.java
index 1eb9ef6..0b42c28 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/icon/method/IconFacetMethodFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/icon/method/IconFacetMethodFactory.java
@@ -19,43 +19,41 @@
package org.apache.isis.core.metamodel.facets.object.icon.method;
-import java.lang.reflect.Method;
-
import javax.inject.Inject;
import org.apache.isis.commons.collections.Can;
import org.apache.isis.core.metamodel.context.MetaModelContext;
-import org.apache.isis.core.metamodel.facetapi.FacetHolder;
-import org.apache.isis.core.metamodel.facetapi.FacetUtil;
import org.apache.isis.core.metamodel.facetapi.FeatureType;
import org.apache.isis.core.metamodel.methods.MethodFinderOptions;
import org.apache.isis.core.metamodel.methods.MethodFinderUtils;
import org.apache.isis.core.metamodel.methods.MethodLiteralConstants;
import org.apache.isis.core.metamodel.methods.MethodPrefixBasedFacetFactoryAbstract;
+import lombok.val;
+
public class IconFacetMethodFactory
extends MethodPrefixBasedFacetFactoryAbstract {
- private static final String PREFIX = MethodLiteralConstants.ICON_NAME;
+ private static final String METHOD_NAME = MethodLiteralConstants.ICON_NAME;
@Inject
public IconFacetMethodFactory(final MetaModelContext mmc) {
- super(mmc, FeatureType.OBJECTS_ONLY, OrphanValidation.VALIDATE, Can.ofSingleton(PREFIX));
+ super(mmc, FeatureType.OBJECTS_ONLY, OrphanValidation.VALIDATE, Can.ofSingleton(METHOD_NAME));
}
@Override
public void process(final ProcessClassContext processClassContext) {
- final Class<?> cls = processClassContext.getCls();
- final FacetHolder facetHolder = processClassContext.getFacetHolder();
+ val cls = processClassContext.getCls();
+ val facetHolder = processClassContext.getFacetHolder();
- final Method method = MethodFinderUtils.findMethod(
+ val method = MethodFinderUtils.findMethod(
MethodFinderOptions
- .layoutSupport(processClassContext.getIntrospectionPolicy()),
- cls, PREFIX, String.class, NO_ARG);
+ .objectSupport(processClassContext.getIntrospectionPolicy()),
+ cls, METHOD_NAME, String.class, NO_ARG);
if (method == null) {
return;
}
processClassContext.removeMethod(method);
- FacetUtil.addFacet(new IconFacetMethod(method, facetHolder));
+ addFacet(new IconFacetViaIconNameMethod(method, facetHolder));
}
}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/icon/method/IconFacetMethod.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/icon/method/IconFacetViaIconNameMethod.java
similarity index 66%
rename from core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/icon/method/IconFacetMethod.java
rename to core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/icon/method/IconFacetViaIconNameMethod.java
index 7bb3802..8c83d44 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/icon/method/IconFacetMethod.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/icon/method/IconFacetViaIconNameMethod.java
@@ -22,26 +22,32 @@ package org.apache.isis.core.metamodel.facets.object.icon.method;
import java.lang.reflect.Method;
import java.util.function.BiConsumer;
+import org.apache.isis.commons.collections.Can;
import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.ImperativeFacet;
import org.apache.isis.core.metamodel.facets.object.icon.IconFacetAbstract;
import org.apache.isis.core.metamodel.spec.ManagedObject;
import org.apache.isis.core.metamodel.spec.ManagedObjects;
+import lombok.Getter;
import lombok.NonNull;
+import lombok.val;
-public class IconFacetMethod
-extends IconFacetAbstract {
+public class IconFacetViaIconNameMethod
+extends IconFacetAbstract
+implements ImperativeFacet {
- private final @NonNull Method method;
+ @Getter(onMethod_ = {@Override}) private final @NonNull Can<Method> methods;
- public IconFacetMethod(final Method method, final FacetHolder holder) {
+ public IconFacetViaIconNameMethod(final Method method, final FacetHolder holder) {
super(holder);
- this.method = method;
+ this.methods = ImperativeFacet.singleMethod(method);
}
@Override
public String iconName(final ManagedObject owningAdapter) {
try {
+ val method = methods.getFirstOrFail();
return (String) ManagedObjects.InvokeUtil.invoke(method, owningAdapter);
} catch (final RuntimeException ex) {
return null;
@@ -49,8 +55,21 @@ extends IconFacetAbstract {
}
@Override
+ public Intent getIntent(final Method method) {
+ return Intent.UI_HINT;
+ }
+
+ @Override
+ protected String toStringValues() {
+ val method = methods.getFirstOrFail();
+ return "method=" + method;
+ }
+
+ @Override
public void visitAttributes(final BiConsumer<String, Object> visitor) {
+ val method = methods.getFirstOrFail();
super.visitAttributes(visitor);
+ ImperativeFacet.visitAttributes(this, visitor);
visitor.accept("method", method);
}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layout/LayoutFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layout/LayoutFacetFactory.java
index 15ca351..c12f40b 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layout/LayoutFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/layout/LayoutFacetFactory.java
@@ -46,7 +46,7 @@ extends MethodPrefixBasedFacetFactoryAbstract {
final Method method = MethodFinderUtils.findMethod(
MethodFinderOptions
- .layoutSupport(processClassContext.getIntrospectionPolicy()),
+ .objectSupport(processClassContext.getIntrospectionPolicy()),
cls, PREFIX, String.class, NO_ARG);
final LayoutFacet layoutFacet;
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/annotation/TitleAnnotationFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/annotation/TitleAnnotationFacetFactory.java
index 02d8bbc..dc74a6f 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/annotation/TitleAnnotationFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/annotation/TitleAnnotationFacetFactory.java
@@ -19,7 +19,6 @@
package org.apache.isis.core.metamodel.facets.object.title.annotation;
-import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@@ -42,6 +41,7 @@ import org.apache.isis.core.metamodel.facets.fallback.FallbackFacetFactory;
import org.apache.isis.core.metamodel.facets.object.title.methods.TitleFacetViaMethodsFactory;
import org.apache.isis.core.metamodel.methods.MethodFinderOptions;
import org.apache.isis.core.metamodel.methods.MethodFinderUtils;
+import org.apache.isis.core.metamodel.methods.MethodLiteralConstants;
import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
import org.apache.isis.core.metamodel.spec.ObjectSpecification;
import org.apache.isis.core.metamodel.specloader.specimpl.ObjectSpecificationAbstract;
@@ -147,43 +147,46 @@ implements MetaModelRefiner {
/**
- * Violation if there is a class that has both a <tt>title()</tt> method and also any non-inherited method
- * annotated with <tt>@Title</tt>.
- *
+ * Violation if there is a class that has both a <tt>title()</tt> method
+ * and also any declared (non-inherited) method annotated with <tt>@Title</tt>.
* <p>
- * If there are only inherited methods annotated with <tt>@Title</tt> then this is <i>not</i> a violation; but
- * (from the implementation of {@link TitleFacetViaMethodsFactory} the imperative <tt>title()</tt> method will take
+ * If there are only inherited methods annotated with <tt>@Title</tt>
+ * then this is <i>not</i> a violation;
+ * but (from the implementation of {@link TitleFacetViaMethodsFactory}
+ * the imperative <tt>title()</tt> method will take
* precedence.
*/
@Override
public void refineProgrammingModel(final ProgrammingModel programmingModel) {
- programmingModel.addVisitingValidatorSkipManagedBeans(objectSpec -> {
+ programmingModel.addVisitingValidatorSkipManagedBeans(_objectSpec -> {
- final Class<?> cls = objectSpec.getCorrespondingClass();
- final var introspectionPolicy = ((ObjectSpecificationAbstract)objectSpec).getIntrospectionPolicy();
+ final var objectSpec = (ObjectSpecificationAbstract)_objectSpec;
+ final var cls = objectSpec.getCorrespondingClass();
+ final var introspectionPolicy = objectSpec.getIntrospectionPolicy();
- final Method titleMethod = MethodFinderUtils.findMethod(
- MethodFinderOptions.layoutSupport(introspectionPolicy),
+ final var titleMethod = MethodFinderUtils.findMethod(
+ MethodFinderOptions.objectSupport(introspectionPolicy),
cls, TITLE_METHOD_NAME, String.class, null);
if (titleMethod == null) {
return;
}
// determine if cls contains an @Title annotated method, not inherited from superclass
- final ObjectSpecification supClass = objectSpec.superclass();
- if (supClass == null) {
+ final ObjectSpecification superSpec = objectSpec.superclass();
+ if (superSpec == null) {
return;
}
- final var superIntrospectionPolicy = ((ObjectSpecificationAbstract)supClass).getIntrospectionPolicy();
+ final var superIntrospectionPolicy = ((ObjectSpecificationAbstract)superSpec).getIntrospectionPolicy();
+ final var superCls = superSpec.getCorrespondingClass();
- final List<Method> methods = methodsWithTitleAnnotation(superIntrospectionPolicy, cls);
- final List<Method> superClassMethods = methodsWithTitleAnnotation(superIntrospectionPolicy, supClass.getCorrespondingClass());
- if (methods.size() > superClassMethods.size()) {
+ if (countMethodsWithTitleAnnotation(introspectionPolicy, cls)
+ > countMethodsWithTitleAnnotation(superIntrospectionPolicy, superCls)) {
ValidationFailure.raiseFormatted(
objectSpec,
- "%s: conflict for determining a strategy for retrieval of title for class, contains a method '%s' and an annotation '@%s'",
+ "%s: conflict for determining a strategy for retrieval of title for class, "
+ + "contains a method '%s' and an annotation '@%s'",
objectSpec.getFeatureIdentifier().getClassName(),
TITLE_METHOD_NAME,
Title.class.getName());
@@ -192,11 +195,13 @@ implements MetaModelRefiner {
});
}
- private static List<Method> methodsWithTitleAnnotation(
+ private static long countMethodsWithTitleAnnotation(
final IntrospectionPolicy introspectionPolicy,
final Class<?> cls) {
- return MethodFinderUtils.findMethodsWithAnnotation(
- MethodFinderOptions.layoutSupport(introspectionPolicy), cls, Title.class);
+ return MethodFinderUtils.streamMethodsWithAnnotation(
+ MethodFinderOptions.objectSupport(introspectionPolicy), cls, Title.class)
+ .filter(method->!method.getName().equals(MethodLiteralConstants.TITLE))
+ .count();
}
}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/methods/TitleFacetViaMethodsFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/methods/TitleFacetViaMethodsFactory.java
index dcd98ae..29888c2 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/methods/TitleFacetViaMethodsFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/methods/TitleFacetViaMethodsFactory.java
@@ -70,7 +70,7 @@ extends MethodPrefixBasedFacetFactoryAbstract {
val titleMethod = MethodFinderUtils.findMethod_returningText(
MethodFinderOptions
- .layoutSupport(processClassContext.getIntrospectionPolicy()),
+ .objectSupport(processClassContext.getIntrospectionPolicy()),
cls,
TITLE,
NO_ARG);
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/DomainIncludeAnnotationEnforcesMetamodelContributionValidator.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/DomainIncludeAnnotationEnforcesMetamodelContributionValidator.java
index a6420ac..d68313a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/DomainIncludeAnnotationEnforcesMetamodelContributionValidator.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/DomainIncludeAnnotationEnforcesMetamodelContributionValidator.java
@@ -21,6 +21,7 @@ package org.apache.isis.core.metamodel.methods;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.List;
+import java.util.Optional;
import java.util.TreeSet;
import java.util.stream.Collectors;
@@ -93,7 +94,10 @@ extends MetaModelVisitingValidatorAbstract {
spec
.streamFacetHolders()
- .flatMap(FacetHolder::streamFacets)
+ .flatMap(FacetHolder::streamFacetRankings)
+ .map(facetRanking->facetRanking.getWinnerNonEvent(facetRanking.facetType()))
+ .filter(Optional::isPresent)
+ .map(Optional::get)
.filter(ImperativeFacet.class::isInstance)
.map(ImperativeFacet.class::cast)
.map(ImperativeFacet::getMethods)
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/MethodFinderOptions.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/MethodFinderOptions.java
index e3f29bd..656ff50 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/MethodFinderOptions.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/MethodFinderOptions.java
@@ -25,11 +25,14 @@ import java.util.function.Predicate;
import org.apache.isis.applib.annotation.Domain;
import org.apache.isis.applib.annotation.Introspection.EncapsulationPolicy;
import org.apache.isis.applib.annotation.Introspection.IntrospectionPolicy;
+import org.apache.isis.commons.collections.Can;
import org.apache.isis.commons.internal.functions._Predicates;
import org.apache.isis.commons.internal.reflection._Annotations;
import org.apache.isis.commons.internal.reflection._Reflect;
+import lombok.NonNull;
import lombok.Value;
+import lombok.val;
@Value(staticConstructor = "of")
public class MethodFinderOptions {
@@ -53,32 +56,32 @@ public class MethodFinderOptions {
return havingAnyOrNoAnnotation(memberIntrospectionPolicy);
}
- public static MethodFinderOptions memberSupport(
- final IntrospectionPolicy memberIntrospectionPolicy) {
- return havingAnnotationIfEnforcedByPolicyOrAccessibility(
- memberIntrospectionPolicy, Domain.Include.class);
- }
-
public static MethodFinderOptions objectSupport(
final IntrospectionPolicy memberIntrospectionPolicy) {
return havingAnnotationIfEnforcedByPolicyOrAccessibility(
- memberIntrospectionPolicy, Domain.Include.class);
+ memberIntrospectionPolicy,
+ Domain.Include.class,
+ MethodLiteralConstants.ConflictingAnnotations.OBJECT_SUPPORT.getProhibits());
}
public static MethodFinderOptions livecycleCallback(
final IntrospectionPolicy memberIntrospectionPolicy) {
return havingAnnotationIfEnforcedByPolicyOrAccessibility(
- memberIntrospectionPolicy, Domain.Include.class);
+ memberIntrospectionPolicy,
+ Domain.Include.class,
+ MethodLiteralConstants.ConflictingAnnotations.OBJECT_LIFECYCLE.getProhibits());
}
- public static MethodFinderOptions layoutSupport(
+ public static MethodFinderOptions memberSupport(
final IntrospectionPolicy memberIntrospectionPolicy) {
return havingAnnotationIfEnforcedByPolicyOrAccessibility(
- memberIntrospectionPolicy, Domain.Include.class);
+ memberIntrospectionPolicy,
+ Domain.Include.class,
+ MethodLiteralConstants.ConflictingAnnotations.MEMBER_SUPPORT.getProhibits());
}
- private final EncapsulationPolicy encapsulationPolicy;
- private final Predicate<Method> mustSatisfy;
+ private final @NonNull EncapsulationPolicy encapsulationPolicy;
+ private final @NonNull Predicate<Method> mustSatisfy;
// -- HELPER
@@ -91,7 +94,8 @@ public class MethodFinderOptions {
private static MethodFinderOptions havingAnnotationIfEnforcedByPolicyOrAccessibility(
final IntrospectionPolicy memberIntrospectionPolicy,
- final Class<? extends Annotation> annotationType) {
+ final Class<? extends Annotation> annotationType,
+ final Can<Class<? extends Annotation>> conflictingAnnotations) {
//MemberAnnotationPolicy
// when REQUIRED -> annot. on support also required
@@ -100,22 +104,33 @@ public class MethodFinderOptions {
return of(
EncapsulationPolicy.ENCAPSULATED_MEMBERS_SUPPORTED, // support methods are always allowed private
memberIntrospectionPolicy.getMemberAnnotationPolicy().isMemberAnnotationsRequired()
- ? method->_Annotations.synthesizeInherited(method, annotationType).isPresent()
+ ? method->havingAnnotation(method, annotationType, conflictingAnnotations)
: method-> !_Reflect.isAccessible(method)
- ? _Annotations.synthesizeInherited(method, annotationType).isPresent()
+ ? havingAnnotation(method, annotationType, conflictingAnnotations)
: true);
}
+ //FIXME[ISIS-2774] if annotation appears on an abstract method that was inherited with given method,
+ // its not detected here
+ private static boolean havingAnnotation(
+ final Method method,
+ final Class<? extends Annotation> annotationType,
+ final Can<Class<? extends Annotation>> conflictingAnnotations) {
+
+ val isMarkerAnnotationPresent = _Annotations.synthesizeInherited(method, annotationType).isPresent();
+ if(isMarkerAnnotationPresent) {
+
+ val isConflictingAnnotationPresent = conflictingAnnotations
+ .stream()
+ .anyMatch(conflictingAnnotationType->
+ _Annotations.synthesizeInherited(method, conflictingAnnotationType).isPresent());
+
+ // do not pickup this method if conflicting - so meta-model validation will fail later on
+ return !isConflictingAnnotationPresent;
+ }
+ return isMarkerAnnotationPresent;
+ }
-// private static MethodFinderOptions havingAnnotation(
-// final IntrospectionPolicy memberIntrospectionPolicy,
-// final Class<? extends Annotation> associatedAnnotationType) {
-// return of(
-// memberIntrospectionPolicy.getEncapsulationPolicy(),
-// memberIntrospectionPolicy.getMemberAnnotationPolicy().isMemberAnnotationsRequired()
-// ? method->_Annotations.synthesizeInherited(method, associatedAnnotationType).isPresent()
-// : _Predicates.alwaysTrue());
-// }
}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/MethodFinderUtils.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/MethodFinderUtils.java
index 83c7d3f..82575d3 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/MethodFinderUtils.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/MethodFinderUtils.java
@@ -23,10 +23,8 @@ import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Collection;
-import java.util.List;
import java.util.Map;
import java.util.Optional;
-import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.isis.applib.services.i18n.TranslatableString;
@@ -108,6 +106,10 @@ public final class MethodFinderUtils {
}
}
+ if(!options.getMustSatisfy().test(method)) {
+ return null;
+ }
+
return method;
}
@@ -165,21 +167,15 @@ public final class MethodFinderUtils {
}
}
- public static List<Method> findMethodsWithAnnotation(
- final MethodFinderOptions options,
- final Class<?> type,
- final Class<? extends Annotation> annotationClass) {
-
- // Validate arguments
- if (type == null || annotationClass == null) {
- throw new IllegalArgumentException("One or more arguments are 'null' valued");
- }
+ public static Stream<Method> streamMethodsWithAnnotation(
+ final @NonNull MethodFinderOptions options,
+ final @NonNull Class<?> type,
+ final @NonNull Class<? extends Annotation> annotationClass) {
// Find methods annotated with the specified annotation
return streamMethods(options, type)
.filter(method -> !MethodUtil.isStatic(method))
- .filter(method -> method.isAnnotationPresent(annotationClass))
- .collect(Collectors.toList());
+ .filter(method -> method.isAnnotationPresent(annotationClass));
}
public static void removeMethod(final MethodRemover methodRemover, final Method method) {
@@ -368,7 +364,8 @@ public final class MethodFinderUtils {
val methodCache = _MethodCache.getInstance();
return options.getEncapsulationPolicy().isEncapsulatedMembersSupported()
? methodCache.streamPublicOrDeclaredMethods(type)
- : methodCache.streamPublicMethods(type);
+ : methodCache.streamPublicMethods(type)
+ .filter(options.getMustSatisfy()::test);
}
}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/MethodLiteralConstants.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/MethodLiteralConstants.java
index 531fa0d..9ea4df7 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/MethodLiteralConstants.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/MethodLiteralConstants.java
@@ -18,15 +18,22 @@
*/
package org.apache.isis.core.metamodel.methods;
+import java.lang.annotation.Annotation;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.function.IntFunction;
import org.springframework.lang.Nullable;
+import org.apache.isis.applib.annotation.MemberSupport;
+import org.apache.isis.applib.annotation.ObjectLifecycle;
+import org.apache.isis.applib.annotation.ObjectSupport;
import org.apache.isis.commons.collections.Can;
import org.apache.isis.core.metamodel.commons.StringExtensions;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
public final class MethodLiteralConstants {
// -- ACCESSORS
@@ -77,6 +84,18 @@ public final class MethodLiteralConstants {
public static final String TO_STRING = "toString";
+ // -- CONFLICTING MARKER ANNOTATIONS
+
+ @RequiredArgsConstructor @Getter
+ public static enum ConflictingAnnotations {
+ OBJECT_SUPPORT(Can.of(ObjectLifecycle.class, MemberSupport.class)),
+ OBJECT_LIFECYCLE(Can.of(ObjectSupport.class, MemberSupport.class)),
+ MEMBER_SUPPORT(Can.of(ObjectSupport.class, ObjectLifecycle.class));
+ final Can<Class<? extends Annotation>> prohibits;
+ }
+
+ // -- METHOD NAMING CONVENTIONS
+
@FunctionalInterface
public static interface SupportingMethodNameProviderForAction {
@Nullable String getActionSupportingMethodName(Method actionMethod, String prefix, boolean isMixin);
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/ident/icon/IconFacetMethodFactoryTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/ident/icon/IconFacetMethodFactoryTest.java
index 382b575..fbcfebd 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/ident/icon/IconFacetMethodFactoryTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/ident/icon/IconFacetMethodFactoryTest.java
@@ -30,7 +30,7 @@ import org.apache.isis.core.metamodel.facetapi.Facet;
import org.apache.isis.core.metamodel.facets.AbstractFacetFactoryTest;
import org.apache.isis.core.metamodel.facets.FacetFactory.ProcessClassContext;
import org.apache.isis.core.metamodel.facets.object.icon.IconFacet;
-import org.apache.isis.core.metamodel.facets.object.icon.method.IconFacetMethod;
+import org.apache.isis.core.metamodel.facets.object.icon.method.IconFacetViaIconNameMethod;
import org.apache.isis.core.metamodel.facets.object.icon.method.IconFacetMethodFactory;
public class IconFacetMethodFactoryTest extends AbstractFacetFactoryTest {
@@ -64,7 +64,7 @@ public class IconFacetMethodFactoryTest extends AbstractFacetFactoryTest {
final Facet facet = facetedMethod.getFacet(IconFacet.class);
assertThat(facet, is(notNullValue()));
- assertThat(facet, is(instanceOf(IconFacetMethod.class)));
+ assertThat(facet, is(instanceOf(IconFacetViaIconNameMethod.class)));
assertTrue(methodRemover.getRemovedMethodMethodCalls().contains(iconNameMethod));
}
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/ident/icon/IconFacetMethodTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/ident/icon/IconFacetMethodTest.java
index bd156f2..8a4ccf3 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/ident/icon/IconFacetMethodTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/ident/icon/IconFacetMethodTest.java
@@ -29,7 +29,7 @@ import org.junit.Before;
import org.junit.Test;
import org.apache.isis.core.metamodel.facetapi.FacetHolder;
-import org.apache.isis.core.metamodel.facets.object.icon.method.IconFacetMethod;
+import org.apache.isis.core.metamodel.facets.object.icon.method.IconFacetViaIconNameMethod;
import org.apache.isis.core.metamodel.spec.ManagedObject;
import static org.hamcrest.CoreMatchers.is;
@@ -40,7 +40,7 @@ public class IconFacetMethodTest {
private final Mockery mockery = new JUnit4Mockery();
- private IconFacetMethod facet;
+ private IconFacetViaIconNameMethod facet;
private FacetHolder mockFacetHolder;
private ManagedObject mockOwningAdapter;
@@ -60,7 +60,7 @@ public class IconFacetMethodTest {
mockFacetHolder = mockery.mock(FacetHolder.class);
mockOwningAdapter = mockery.mock(ManagedObject.class);
final Method iconNameMethod = DomainObjectWithProblemInIconNameMethod.class.getMethod("iconName");
- facet = new IconFacetMethod(iconNameMethod, mockFacetHolder);
+ facet = new IconFacetViaIconNameMethod(iconNameMethod, mockFacetHolder);
mockery.checking(new Expectations() {
{
diff --git a/regressiontests/stable-domainmodel/src/test/java/org/apache/isis/testdomain/domainmodel/DomainModelTest_usingGoodDomain.java b/regressiontests/stable-domainmodel/src/test/java/org/apache/isis/testdomain/domainmodel/DomainModelTest_usingGoodDomain.java
index a5d79f7..e8a0912 100644
--- a/regressiontests/stable-domainmodel/src/test/java/org/apache/isis/testdomain/domainmodel/DomainModelTest_usingGoodDomain.java
+++ b/regressiontests/stable-domainmodel/src/test/java/org/apache/isis/testdomain/domainmodel/DomainModelTest_usingGoodDomain.java
@@ -489,6 +489,23 @@ class DomainModelTest_usingGoodDomain {
coll.assertCollectionElements(List.of("Foo"));
}
+// @Test
+// void quicktest() {
+// val testerFactory = new DomainObjectTesterFactory(serviceInjector);
+// val prop = testerFactory.propertyTester(DomainObjectList.class, "elementTypeFqcn");
+// prop.assertExists(true);
+//
+// val objectSpec = specificationLoader.specForTypeElseFail(DomainObjectList.class);
+//
+// val titleFacet = objectSpec.getFacetRanking(TitleFacet.class).get().getWinnerNonEvent(TitleFacet.class).get();
+// assertNotNull(titleFacet);
+// assertTrue(titleFacet instanceof ImperativeFacet, "no imperative: " + titleFacet.getClass());
+//
+// ((ImperativeFacet)titleFacet).getMethods()
+// .forEach(System.err::println);
+//
+// }
+
@Test
void viewmodelWithAnnotationOptional_usingPrivateSupport() {
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberInheritanceAbstract.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberInheritanceAbstract.java
index 2c2b879..873431a 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberInheritanceAbstract.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberInheritanceAbstract.java
@@ -32,10 +32,12 @@ import lombok.Setter;
abstract class ProperMemberInheritanceAbstract {
+ //@Title //FIXME[ISIS-2774] either not picked up, or validation fails when abstract
public String title() {
return "inherited title";
}
+ //@ObjectSupport //FIXME[ISIS-2774] either not picked up, or validation fails when abstract
public String iconName() {
return "inherited icon";
}
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberInheritanceInterface.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberInheritanceInterface.java
index 2f2a1ed..1680ed6 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberInheritanceInterface.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberInheritanceInterface.java
@@ -24,15 +24,19 @@ import org.apache.isis.applib.annotation.Action;
import org.apache.isis.applib.annotation.ActionLayout;
import org.apache.isis.applib.annotation.Collection;
import org.apache.isis.applib.annotation.CollectionLayout;
+import org.apache.isis.applib.annotation.ObjectSupport;
import org.apache.isis.applib.annotation.Property;
import org.apache.isis.applib.annotation.PropertyLayout;
+import org.apache.isis.applib.annotation.Title;
public interface ProperMemberInheritanceInterface {
+ @Title
default String title() {
return "inherited title";
}
+ @ObjectSupport
default String iconName() {
return "inherited icon";
}
@@ -63,7 +67,7 @@ public interface ProperMemberInheritanceInterface {
@Action
@ActionLayout(named = "foo", describedAs = "bar")
- default void sampleActionOverrideWithParam(String x) {
+ default void sampleActionOverrideWithParam(final String x) {
}
@Property
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberSupport_action.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberSupport_action.java
index 4f93a318..404611b 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberSupport_action.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberSupport_action.java
@@ -37,7 +37,8 @@ public class ProperMemberSupport_action {
// proper mix-in action
//@Action // <-- inferred by annotation on type above
- public ProperMemberSupport act(String p0, String p1) {
+ @MemberSupport
+ public ProperMemberSupport act(final String p0, final String p1) {
return holder;
}
@@ -52,17 +53,17 @@ public class ProperMemberSupport_action {
}
@MemberSupport
- public String validateAct(String p0, String p1) {
+ public String validateAct(final String p0, final String p1) {
return null;
}
@MemberSupport
- public Set<String> autoComplete0Act(@MinLength(3) String search) {
+ public Set<String> autoComplete0Act(@MinLength(3) final String search) {
return null;
}
@MemberSupport
- public Set<String> autoComplete1Act(@MinLength(3) String search) {
+ public Set<String> autoComplete1Act(@MinLength(3) final String search) {
return null;
}
@@ -77,7 +78,7 @@ public class ProperMemberSupport_action {
}
@MemberSupport
- public Set<String> choices1Act(String p0) {
+ public Set<String> choices1Act(final String p0) {
return null;
}
@@ -92,12 +93,12 @@ public class ProperMemberSupport_action {
}
@MemberSupport
- public String validate0Act(String p0) {
+ public String validate0Act(final String p0) {
return null;
}
@MemberSupport
- public String validate1Act(String p1) {
+ public String validate1Act(final String p1) {
return null;
}
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberSupport_action2.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberSupport_action2.java
index 03158aa..29b3adf 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberSupport_action2.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberSupport_action2.java
@@ -35,7 +35,8 @@ public class ProperMemberSupport_action2 {
// proper mix-in action
- public ProperMemberSupport act(String p0, String p1) {
+ @MemberSupport
+ public ProperMemberSupport act(final String p0, final String p1) {
return holder;
}
@@ -50,17 +51,17 @@ public class ProperMemberSupport_action2 {
}
@MemberSupport
- public String validateAct(String p0, String p1) {
+ public String validateAct(final String p0, final String p1) {
return null;
}
@MemberSupport
- public Set<String> autoComplete0Act(@MinLength(3) String search) {
+ public Set<String> autoComplete0Act(@MinLength(3) final String search) {
return null;
}
@MemberSupport
- public Set<String> autoComplete1Act(@MinLength(3) String search) {
+ public Set<String> autoComplete1Act(@MinLength(3) final String search) {
return null;
}
@@ -97,12 +98,12 @@ public class ProperMemberSupport_action2 {
}
@MemberSupport
- public String validate0Act(String p0) {
+ public String validate0Act(final String p0) {
return null;
}
@MemberSupport
- public String validate1Act(String p1) {
+ public String validate1Act(final String p1) {
return null;
}
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberSupport_action3.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberSupport_action3.java
index 7bad058..48fca58 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberSupport_action3.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberSupport_action3.java
@@ -36,7 +36,8 @@ public class ProperMemberSupport_action3 {
// proper mix-in action
- public ProperMemberSupport act(List<String> p0, List<String> p1) {
+ @MemberSupport
+ public ProperMemberSupport act(final List<String> p0, final List<String> p1) {
return holder;
}
@@ -51,17 +52,17 @@ public class ProperMemberSupport_action3 {
}
@MemberSupport
- public String validateAct(List<String> p0, List<String> p1) {
+ public String validateAct(final List<String> p0, final List<String> p1) {
return null;
}
@MemberSupport
- public Set<String> autoComplete0Act(@MinLength(3) String search) {
+ public Set<String> autoComplete0Act(@MinLength(3) final String search) {
return null;
}
@MemberSupport
- public Set<String> autoComplete1Act(@MinLength(3) String search) {
+ public Set<String> autoComplete1Act(@MinLength(3) final String search) {
return null;
}
@@ -98,12 +99,12 @@ public class ProperMemberSupport_action3 {
}
@MemberSupport
- public String validate0Act(List<String> p0) {
+ public String validate0Act(final List<String> p0) {
return null;
}
@MemberSupport
- public String validate1Act(List<String> p1) {
+ public String validate1Act(final List<String> p1) {
return null;
}
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ViewModelWithAnnotationOptionalUsingPrivateSupport.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ViewModelWithAnnotationOptionalUsingPrivateSupport.java
index d0ba85e..33c9e91 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ViewModelWithAnnotationOptionalUsingPrivateSupport.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ViewModelWithAnnotationOptionalUsingPrivateSupport.java
@@ -27,7 +27,9 @@ import org.apache.isis.applib.annotation.DomainObject;
import org.apache.isis.applib.annotation.Introspection;
import org.apache.isis.applib.annotation.MemberSupport;
import org.apache.isis.applib.annotation.Nature;
+import org.apache.isis.applib.annotation.ObjectSupport;
import org.apache.isis.applib.annotation.Property;
+import org.apache.isis.applib.annotation.Title;
import lombok.Getter;
import lombok.Setter;
@@ -46,6 +48,12 @@ implements Serializable {
private static final long serialVersionUID = 1L;
+ // allowed to be private since 2.0.0-M7
+ @Title
+ private String title() {
+ return "view-model with annotation optional using private support";
+ }
+
// -- PUBLIC ACTION WITH PRIVATE SUPPORT
@Action
@@ -86,13 +94,13 @@ implements Serializable {
// -- PRIVATE OBJECT SUPPORT
// allowed to be private since 2.0.0-M7
- @MemberSupport//FIXME[ISIS-2774] be more specific, don't allow @MemberSupport
+ @ObjectSupport
private String disabled() {
return "object disabled for testing purposes";
}
// allowed to be private since 2.0.0-M7
- @MemberSupport//FIXME[ISIS-2774] be more specific, don't allow @MemberSupport
+ @ObjectSupport
private boolean hidden() {
return false;
}