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 2022/05/30 15:58:10 UTC
[isis] branch master updated: ISIS-3063: adds support for aliased object and service spec lookup
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 395a7b38f8 ISIS-3063: adds support for aliased object and service spec lookup
395a7b38f8 is described below
commit 395a7b38f8df16f053a397497a7ea57fca3fce3c
Author: Andi Huber <ah...@apache.org>
AuthorDate: Mon May 30 17:58:05 2022 +0200
ISIS-3063: adds support for aliased object and service spec lookup
---
.../metamodel/specloader/LogicalTypeResolver.java | 12 ++++-
.../specloader/LogicalTypeResolverDefault.java | 56 +++++++++++++++-------
.../specloader/SpecificationLoaderDefault.java | 22 ++++++---
.../DomainModelTest_usingGoodDomain.java | 22 +++++++++
.../model/good/ProperServiceWithAlias.java | 41 ++++++++++++++++
5 files changed, 130 insertions(+), 23 deletions(-)
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/LogicalTypeResolver.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/LogicalTypeResolver.java
index eea39ba348..720c70c20b 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/LogicalTypeResolver.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/LogicalTypeResolver.java
@@ -47,13 +47,23 @@ interface LogicalTypeResolver {
/**
* Collects concrete types, ignores abstract types and interfaces.
* Allows types to override their concrete super types.
+ * <p>
+ * Acts as an identity operator with side-effects.
* @param spec - type's ObjectSpecification
*/
- void register(@NonNull ObjectSpecification spec);
+ ObjectSpecification register(@NonNull ObjectSpecification spec);
/**
* Removes all entries from the lookup table.
*/
void clear();
+ /**
+ * Collects aliases for concrete types, ignores abstract types and interfaces.
+ * <p>
+ * Acts as an identity operator with side-effects.
+ * @param spec - type's ObjectSpecification
+ */
+ ObjectSpecification registerAliases(@NonNull ObjectSpecification spec);
+
}
\ No newline at end of file
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/LogicalTypeResolverDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/LogicalTypeResolverDefault.java
index 8f92d4d553..8336b837bd 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/LogicalTypeResolverDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/LogicalTypeResolverDefault.java
@@ -45,30 +45,33 @@ class LogicalTypeResolverDefault implements LogicalTypeResolver {
}
@Override
- public void register(final @NonNull ObjectSpecification spec) {
+ public ObjectSpecification register(final @NonNull ObjectSpecification spec) {
+
+ val logicalTypeName = spec.getLogicalTypeName();
+
+ if(logicalTypeByName.containsKey(logicalTypeName)) {
+ return spec;
+ }
// collect concrete classes (do not collect abstract or anonymous types or interfaces)
if(!spec.isAbstract()
&& hasTypeIdentity(spec)) {
- val key = spec.getLogicalTypeName();
-
- val previousMapping = logicalTypeByName.put(key, spec.getLogicalType());
-
- if(previousMapping!=null) {
+ putWithWarnOnOverride(logicalTypeName, spec);
+ }
+ return spec;
+ }
- val msg = String.format("Overriding existing mapping\n"
- + "%s -> %s,\n"
- + "with\n "
- + "%s -> %s\n "
- + "This will result in the meta-model validation to fail.",
- key, previousMapping.getCorrespondingClass(),
- key, spec.getCorrespondingClass());
+ @Override
+ public ObjectSpecification registerAliases(final @NonNull ObjectSpecification spec) {
- log.warn(msg);
+ // adding aliases to the lookup map
+ spec.getAliases()
+ .forEach(alias->{
+ putWithWarnOnOverride(alias.getLogicalTypeName(), spec);
+ });
- }
- }
+ return spec;
}
// -- HELPER
@@ -79,4 +82,25 @@ class LogicalTypeResolverDefault implements LogicalTypeResolver {
return spec.getCorrespondingClass().getCanonicalName()!=null;
}
+ private void putWithWarnOnOverride(
+ final String logicalTypeName,
+ final ObjectSpecification spec) {
+
+ final LogicalType previousMapping =
+ logicalTypeByName.put(logicalTypeName, spec.getLogicalType());
+
+ if(previousMapping!=null
+ && !spec.getLogicalType().equals(previousMapping)) {
+ val msg = String.format("Overriding existing mapping\n"
+ + "%s -> %s,\n"
+ + "with\n "
+ + "%s -> %s\n "
+ + "This will result in the meta-model validation to fail.",
+ logicalTypeName, previousMapping.getCorrespondingClass(),
+ logicalTypeName, spec.getCorrespondingClass());
+ log.warn(msg);
+ }
+
+ }
+
}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderDefault.java
index 6de0a67735..e1193ad8f6 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderDefault.java
@@ -450,7 +450,7 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
return logicalType;
}
- //TODO[2533] if the logicalTypeName is not available and instead a fqcn was passed in, that should also be supported
+ //XXX[2533] if the logicalTypeName is not available and instead a fqcn was passed in, that should also be supported
// falling back assuming the logicalTypeName equals the fqn of the corresponding class
// which might not always be true,
@@ -558,14 +558,24 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
val substitutedType = substitute.apply(type);
- val spec = cache.computeIfAbsent(substitutedType, __->{
- val newSpec = createSpecification(beanClassifier.apply(substitutedType));
- logicalTypeResolver.register(newSpec);
- return newSpec;
- });
+ val spec = cache.computeIfAbsent(substitutedType, _spec->
+ logicalTypeResolver
+ .register(
+ createSpecification(beanClassifier.apply(substitutedType))));
spec.introspectUpTo(upTo);
+ if(spec.getAliases().isNotEmpty()) {
+ //XXX[3063] hitting this a couple of times (~10) per spec (with aliases)
+ // even though already registered;
+ // room for performance optimizations, but at the time of writing
+ // don't want to add a ObjectSpecification flag to keep track of alias registered state;
+ // as an alternative purge the aliased facets and introspect aliased attributes from annotations
+ // much earlier in the bootstrap process, same as we do with @Named processing
+ logicalTypeResolver
+ .registerAliases(spec);
+ }
+
return spec;
}
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 2f2cc35eda..aefd5b42b8 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
@@ -41,6 +41,7 @@ import static org.junit.jupiter.api.Assertions.fail;
import org.apache.isis.applib.annotation.Introspection.EncapsulationPolicy;
import org.apache.isis.applib.annotation.Introspection.MemberAnnotationPolicy;
+import org.apache.isis.applib.id.LogicalType;
import org.apache.isis.applib.services.jaxb.JaxbService;
import org.apache.isis.applib.services.metamodel.BeanSort;
import org.apache.isis.applib.services.metamodel.Config;
@@ -84,6 +85,7 @@ import org.apache.isis.testdomain.model.good.ProperMemberInheritance_usingAbstra
import org.apache.isis.testdomain.model.good.ProperMemberInheritance_usingInterface;
import org.apache.isis.testdomain.model.good.ProperMemberSupport;
import org.apache.isis.testdomain.model.good.ProperMemberSupportDiscovery;
+import org.apache.isis.testdomain.model.good.ProperServiceWithAlias;
import org.apache.isis.testdomain.model.good.ProperServiceWithMixin;
import org.apache.isis.testdomain.model.good.ViewModelWithAnnotationOptionalUsingPrivateSupport;
import org.apache.isis.testdomain.model.good.ViewModelWithEncapsulatedMembers;
@@ -508,6 +510,26 @@ class DomainModelTest_usingGoodDomain {
}
+ @Test
+ void aliasesOnDomainServices_shouldBeHonored() {
+
+ val objectSpec = specificationLoader.specForTypeElseFail(ProperServiceWithAlias.class);
+ assertTrue(objectSpec.isInjectable());
+ assertTrue(objectSpec.getAction("now").isPresent());
+
+ assertEquals(Can.of(
+ "testdomain.v1.ProperServiceWithAlias",
+ "testdomain.v2.ProperServiceWithAlias"),
+ objectSpec.getAliases().map(LogicalType::getLogicalTypeName));
+
+ assertEquals(objectSpec,
+ specificationLoader.specForLogicalTypeName("testdomain.v1.ProperServiceWithAlias")
+ .orElse(null));
+ assertEquals(objectSpec,
+ specificationLoader.specForLogicalTypeName("testdomain.v2.ProperServiceWithAlias")
+ .orElse(null));
+ }
+
@Test
void viewmodelWithEncapsulatedMembers() {
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperServiceWithAlias.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperServiceWithAlias.java
new file mode 100644
index 0000000000..2735c2090c
--- /dev/null
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperServiceWithAlias.java
@@ -0,0 +1,41 @@
+/*
+ * 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.testdomain.model.good;
+
+import javax.inject.Named;
+
+import org.joda.time.LocalDateTime;
+
+import org.apache.isis.applib.annotation.Action;
+import org.apache.isis.applib.annotation.DomainService;
+import org.apache.isis.applib.annotation.NatureOfService;
+
+@Named("testdomain.ProperServiceWithAlias")
+@DomainService(nature = NatureOfService.VIEW,
+ aliased = {
+ "testdomain.v1.ProperServiceWithAlias",
+ "testdomain.v2.ProperServiceWithAlias",
+ })
+public class ProperServiceWithAlias {
+
+ @Action public LocalDateTime now() {
+ return LocalDateTime.now();
+ }
+
+}