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/06/26 06:18:21 UTC
[isis] branch master updated: ISIS-1720: add facet post-processor
to synthesize a ObjectNamedFacetSynthesized,
which in any case must provide both noun-forms of a domain-object
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
The following commit(s) were added to refs/heads/master by this push:
new 654835f ISIS-1720: add facet post-processor to synthesize a ObjectNamedFacetSynthesized, which in any case must provide both noun-forms of a domain-object
654835f is described below
commit 654835f49d0341143a8561354da13b03145e3ca9
Author: Andi Huber <ah...@apache.org>
AuthorDate: Sat Jun 26 08:18:12 2021 +0200
ISIS-1720: add facet post-processor to synthesize a
ObjectNamedFacetSynthesized, which in any case must provide both
noun-forms of a domain-object
with that we also introduced a new Facet.Precedence: SYNTHESIZED
---
.../apache/isis/core/metamodel/facetapi/Facet.java | 9 ++
.../metamodel/facets/all/i8n/noun/NounForms.java | 11 +-
.../facets/all/named/ObjectNamedFacetAbstract.java | 13 ++-
.../all/named/ObjectNamedFacetSynthesized.java | 21 ++++
.../NamedFacetForDomainObjectLayoutAnnotation.java | 3 -
.../NamedFacetForDomainObjectXml.java | 3 -
...NamedFacetForDomainServiceLayoutAnnotation.java | 28 ++---
.../all/i18n/SynthesizeObjectNaming.java | 114 +++++++++++++++++++++
.../dflt/ProgrammingModelFacetsJava8.java | 4 +
.../specimpl/ObjectSpecificationAbstract.java | 4 +-
10 files changed, 173 insertions(+), 37 deletions(-)
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/Facet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/Facet.java
index e4ed23a..8a35304a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/Facet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/Facet.java
@@ -25,6 +25,7 @@ import java.util.function.Consumer;
import org.apache.isis.applib.Identifier;
import org.apache.isis.commons.internal.exceptions._Exceptions;
import org.apache.isis.core.metamodel.facets.actions.action.invocation.ActionInvocationFacet;
+import org.apache.isis.core.metamodel.facets.all.named.ObjectNamedFacet;
public interface Facet
extends
@@ -69,6 +70,14 @@ extends
HIGH,
/**
+ * Higher precedence than {@link #HIGH}. In other words, overrules {@link #HIGH}.
+ * <p>
+ * Reserved for facet post-processing, when synthesizing a 'virtual' facet
+ * from facets of lower rank. (eg. {@link ObjectNamedFacet} with its singular and plural noun-form support)
+ */
+ SYNTHESIZED,
+
+ /**
* Highest precedence, with special behavior and restrictions:
* <ul>
* <li>
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/all/i8n/noun/NounForms.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/all/i8n/noun/NounForms.java
index d8dd489..48fba49 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/all/i8n/noun/NounForms.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/all/i8n/noun/NounForms.java
@@ -41,23 +41,19 @@ import lombok.val;
@Value @Builder
public class NounForms {
- public static NounFormsBuilder preferredSingular(@Nullable final String singular) {
+ public static NounFormsBuilder builderSingular(@Nullable final String singular) {
return NounForms.builder()
- .preferredNounForm(NounForm.SINGULAR)
.singular(singular);
}
- public static NounFormsBuilder preferredPlural(@Nullable final String plural) {
+ public static NounFormsBuilder builderPlural(@Nullable final String plural) {
return NounForms.builder()
- .preferredNounForm(NounForm.PLURAL)
.plural(plural);
}
private final @Nullable String singular;
private final @Nullable String plural;
- private final @NonNull NounForm preferredNounForm;
-
@Getter(lazy = true)
final ImmutableEnumSet<NounForm> supportedNounForms = supportedNounForms();
@@ -98,8 +94,7 @@ public class NounForms {
final TranslationContext context) {
val builder = NounForms
- .builder()
- .preferredNounForm(preferredNounForm);
+ .builder();
getSupportedNounForms()
.forEach(nounForm->{
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/all/named/ObjectNamedFacetAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/all/named/ObjectNamedFacetAbstract.java
index 72bc2f1..b53d86c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/all/named/ObjectNamedFacetAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/all/named/ObjectNamedFacetAbstract.java
@@ -39,10 +39,21 @@ implements ObjectNamedFacet {
protected ObjectNamedFacetAbstract(
final NounForms nounForms,
final FacetHolder holder) {
+ this(
+ nounForms,
+ holder,
+ Precedence.DEFAULT);
+ }
+
+ protected ObjectNamedFacetAbstract(
+ final NounForms nounForms,
+ final FacetHolder holder,
+ final Precedence precedence) {
super(type(),
TranslationContext.forTranslationContextHolder(holder.getFeatureIdentifier()),
nounForms,
- holder);
+ holder,
+ precedence);
}
}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/all/named/ObjectNamedFacetSynthesized.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/all/named/ObjectNamedFacetSynthesized.java
new file mode 100644
index 0000000..d50fff9
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/all/named/ObjectNamedFacetSynthesized.java
@@ -0,0 +1,21 @@
+package org.apache.isis.core.metamodel.facets.all.named;
+
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.all.i8n.noun.NounForms;
+
+/**
+ * To be installed by facet-post-processing only,
+ * which in any case must provide both noun-forms (non-empty).
+ *
+ * @since 2.0
+ */
+public class ObjectNamedFacetSynthesized
+extends ObjectNamedFacetAbstract {
+
+ public ObjectNamedFacetSynthesized(
+ final NounForms nounForms,
+ final FacetHolder holder) {
+ super(nounForms, holder, Precedence.SYNTHESIZED);
+ }
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobjectlayout/NamedFacetForDomainObjectLayoutAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobjectlayout/NamedFacetForDomainObjectLayoutAnnotation.java
index a96f47d..4066caa 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobjectlayout/NamedFacetForDomainObjectLayoutAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobjectlayout/NamedFacetForDomainObjectLayoutAnnotation.java
@@ -23,7 +23,6 @@ import java.util.Optional;
import org.apache.isis.applib.annotation.DomainObjectLayout;
import org.apache.isis.commons.internal.base._Strings;
import org.apache.isis.core.metamodel.facetapi.FacetHolder;
-import org.apache.isis.core.metamodel.facets.all.i8n.noun.NounForm;
import org.apache.isis.core.metamodel.facets.all.i8n.noun.NounForms;
import org.apache.isis.core.metamodel.facets.all.named.ObjectNamedFacet;
import org.apache.isis.core.metamodel.facets.all.named.ObjectNamedFacetAbstract;
@@ -46,10 +45,8 @@ extends ObjectNamedFacetAbstract {
val singular = _Strings.emptyToNull(domainObjectLayout.named());
val plural = _Strings.emptyToNull(domainObjectLayout.plural());
- //TODO[1720] if singular is not explicit (is empty), infer
val nounForms = NounForms
.builder()
- .preferredNounForm(singular!=null ? NounForm.SINGULAR : NounForm.PLURAL)
.singular(singular)
.plural(plural)
.build();
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobjectlayout/NamedFacetForDomainObjectXml.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobjectlayout/NamedFacetForDomainObjectXml.java
index 52deac4..561398a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobjectlayout/NamedFacetForDomainObjectXml.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobjectlayout/NamedFacetForDomainObjectXml.java
@@ -24,7 +24,6 @@ import java.util.Optional;
import org.apache.isis.applib.layout.component.DomainObjectLayoutData;
import org.apache.isis.commons.internal.base._Strings;
import org.apache.isis.core.metamodel.facetapi.FacetHolder;
-import org.apache.isis.core.metamodel.facets.all.i8n.noun.NounForm;
import org.apache.isis.core.metamodel.facets.all.i8n.noun.NounForms;
import org.apache.isis.core.metamodel.facets.all.named.ObjectNamedFacet;
import org.apache.isis.core.metamodel.facets.all.named.ObjectNamedFacetAbstract;
@@ -45,10 +44,8 @@ extends ObjectNamedFacetAbstract {
val singular = _Strings.emptyToNull(domainObjectLayout.getNamed());
val plural = _Strings.emptyToNull(domainObjectLayout.getPlural());
- //TODO[1720] if singular is not explicit (is empty), infer
val nounForms = NounForms
.builder()
- .preferredNounForm(singular!=null ? NounForm.SINGULAR : NounForm.PLURAL)
.singular(singular)
.plural(plural)
.build();
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainservicelayout/NamedFacetForDomainServiceLayoutAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainservicelayout/NamedFacetForDomainServiceLayoutAnnotation.java
index a0a6d0f..a3b279c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainservicelayout/NamedFacetForDomainServiceLayoutAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainservicelayout/NamedFacetForDomainServiceLayoutAnnotation.java
@@ -18,7 +18,6 @@
*/
package org.apache.isis.core.metamodel.facets.object.domainservicelayout;
-import java.util.Objects;
import java.util.Optional;
import org.apache.isis.applib.annotation.DomainServiceLayout;
@@ -28,8 +27,6 @@ import org.apache.isis.core.metamodel.facets.all.i8n.noun.NounForms;
import org.apache.isis.core.metamodel.facets.all.named.ObjectNamedFacet;
import org.apache.isis.core.metamodel.facets.all.named.ObjectNamedFacetAbstract;
-import lombok.val;
-
public class NamedFacetForDomainServiceLayoutAnnotation
extends ObjectNamedFacetAbstract {
@@ -37,24 +34,15 @@ extends ObjectNamedFacetAbstract {
final Optional<DomainServiceLayout> domainServiceLayoutIfAny,
final FacetHolder facetHolder) {
- val serviceNamed = domainServiceLayoutIfAny
+ return domainServiceLayoutIfAny
.map(DomainServiceLayout::named)
- .map(_Strings::emptyToNull)
- .filter(Objects::nonNull)
- .orElse(null);
-
- if(_Strings.isEmpty(serviceNamed)) {
- return Optional.empty();
- }
-
- val nounForms = NounForms
- .preferredSingular(serviceNamed)
- .build();
-
- return Optional.of(
- new NamedFacetForDomainServiceLayoutAnnotation(
- nounForms,
- facetHolder));
+ .filter(_Strings::isNotEmpty)
+ .map(serviceNamed->NounForms
+ .builderSingular(serviceNamed)
+ .build())
+ .map(nounForms->new NamedFacetForDomainServiceLayoutAnnotation(
+ nounForms,
+ facetHolder));
}
private NamedFacetForDomainServiceLayoutAnnotation(
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/postprocessors/all/i18n/SynthesizeObjectNaming.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/postprocessors/all/i18n/SynthesizeObjectNaming.java
new file mode 100644
index 0000000..6c18cd6
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/postprocessors/all/i18n/SynthesizeObjectNaming.java
@@ -0,0 +1,114 @@
+/*
+ * 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.isis.core.metamodel.postprocessors.all.i18n;
+
+
+import javax.inject.Inject;
+
+import org.apache.isis.commons.collections.Can;
+import org.apache.isis.commons.internal.base._Strings;
+import org.apache.isis.core.metamodel.commons.StringExtensions;
+import org.apache.isis.core.metamodel.context.MetaModelContext;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facetapi.FacetUtil;
+import org.apache.isis.core.metamodel.facets.all.i8n.noun.NounForm;
+import org.apache.isis.core.metamodel.facets.all.i8n.noun.NounForms;
+import org.apache.isis.core.metamodel.facets.all.named.ObjectNamedFacet;
+import org.apache.isis.core.metamodel.facets.all.named.ObjectNamedFacetSynthesized;
+import org.apache.isis.core.metamodel.postprocessors.ObjectSpecificationPostProcessorAbstract;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
+import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
+
+import lombok.val;
+
+public class SynthesizeObjectNaming
+extends ObjectSpecificationPostProcessorAbstract {
+
+ @Inject
+ public SynthesizeObjectNaming(final MetaModelContext metaModelContext) {
+ super(metaModelContext);
+ }
+
+ @Override
+ protected void doPostProcess(final ObjectSpecification objectSpecification) {
+
+ val topRank = objectSpecification
+ .lookupFacet(ObjectNamedFacet.class)
+ .flatMap(Facet::getSharedFacetRanking)
+ .map(facetRanking->facetRanking.getTopRank(ObjectNamedFacet.class))
+ .orElse(Can.empty())
+ .reverse(); // historically last have higher precedence, so when reverted we can use findFirst logic
+
+ val singular = topRank
+ .stream()
+ .filter(objectNamedFacet->objectNamedFacet.getSupportedNounForms().contains(NounForm.SINGULAR))
+ .findFirst()
+ .map(ObjectNamedFacet::singular)
+ .filter(_Strings::isNotEmpty)
+ .orElseGet(()->getSingularFallbackNoun(objectSpecification));
+
+ val plural = topRank
+ .stream()
+ .filter(objectNamedFacet->objectNamedFacet.getSupportedNounForms().contains(NounForm.PLURAL))
+ .findFirst()
+ .map(ObjectNamedFacet::plural)
+ .filter(_Strings::isNotEmpty)
+ .orElseGet(()->getPluralFallbackNoun(singular));
+
+ FacetUtil.addFacet(
+ new ObjectNamedFacetSynthesized(
+ NounForms.builder()
+ .singular(singular)
+ .plural(plural)
+ .build(),
+ objectSpecification)
+ );
+
+ }
+
+ @Override
+ protected void doPostProcess(final ObjectSpecification objectSpecification, final ObjectAction act) {
+ }
+
+ @Override
+ protected void doPostProcess(final ObjectSpecification objectSpecification, final ObjectAction objectAction, final ObjectActionParameter param) {
+ }
+
+ @Override
+ protected void doPostProcess(final ObjectSpecification objectSpecification, final OneToOneAssociation prop) {
+ }
+
+ @Override
+ protected void doPostProcess(final ObjectSpecification objectSpecification, final OneToManyAssociation coll) {
+ }
+
+ // -- HELEPR
+
+ private String getSingularFallbackNoun(final ObjectSpecification spec) {
+ return spec.getFeatureIdentifier().getClassNaturalName();
+ }
+
+ private String getPluralFallbackNoun(final String singular) {
+ return StringExtensions.asPluralName(singular);
+ }
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/progmodels/dflt/ProgrammingModelFacetsJava8.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/progmodels/dflt/ProgrammingModelFacetsJava8.java
index b8b7fdb..6df91c9 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/progmodels/dflt/ProgrammingModelFacetsJava8.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/progmodels/dflt/ProgrammingModelFacetsJava8.java
@@ -145,6 +145,7 @@ import org.apache.isis.core.metamodel.methods.MethodByClassMap;
import org.apache.isis.core.metamodel.methods.OrphanedSupportingMethodValidator;
import org.apache.isis.core.metamodel.postprocessors.DeriveMixinMembersPostProcessor;
import org.apache.isis.core.metamodel.postprocessors.all.DeriveDescribedAsFromTypePostProcessor;
+import org.apache.isis.core.metamodel.postprocessors.all.i18n.SynthesizeObjectNaming;
import org.apache.isis.core.metamodel.postprocessors.all.i18n.TranslationPostProcessor;
import org.apache.isis.core.metamodel.postprocessors.allbutparam.authorization.AuthorizationFacetPostProcessor;
import org.apache.isis.core.metamodel.postprocessors.collparam.DeriveCollectionParamDefaultsAndChoicesPostProcessor;
@@ -384,6 +385,9 @@ extends ProgrammingModelAbstract {
// only after this point have any mixin members been resolved and are available on the ObjectSpecification.
+ // must run before Object nouns are used
+ addPostProcessor(PostProcessingOrder.A1_BUILTIN, new SynthesizeObjectNaming(mmc));
+
addPostProcessor(PostProcessingOrder.A1_BUILTIN, new DeriveDescribedAsFromTypePostProcessor(mmc));
addPostProcessor(PostProcessingOrder.A1_BUILTIN, new DeriveTypicalLengthFromTypePostProcessor(mmc));
addPostProcessor(PostProcessingOrder.A1_BUILTIN, new DeriveDefaultFromTypePostProcessor(mmc));
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java
index dfbf254..b09e3f0 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java
@@ -486,14 +486,14 @@ implements ObjectSpecification {
public String getSingularName() {
return lookupFacet(ObjectNamedFacet.class)
.flatMap(textFacet->textFacet.translated(NounForm.SINGULAR))
- .orElseGet(this::getFullIdentifier);
+ .orElseGet(this::getFullIdentifier); // unexpected code reach, however keep for JUnit testing
}
@Override
public String getPluralName() {
return lookupFacet(ObjectNamedFacet.class)
.flatMap(textFacet->textFacet.translated(NounForm.PLURAL))
- .orElseGet(this::getFullIdentifier);
+ .orElseGet(this::getFullIdentifier); // unexpected code reach, however keep for JUnit testing
}
/**