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/07 07:45:43 UTC
[isis] branch master updated: ISIS-2721: properly detect and
register value types
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 bf521d3 ISIS-2721: properly detect and register value types
bf521d3 is described below
commit bf521d310809f3d4727b35a8b5493bfbce8a5be3
Author: Andi Huber <ah...@apache.org>
AuthorDate: Mon Jun 7 09:45:27 2021 +0200
ISIS-2721: properly detect and register value types
fixes Blob/Clob not detected as value types
---
.../java/org/apache/isis/applib/value/Clob.java | 3 +-
.../commons/internal/functions/_Predicates.java | 8 ++++
.../IsisBeanFactoryPostProcessorForSpring.java | 3 +-
.../core/config/beans/IsisBeanTypeClassifier.java | 32 +++++++++++++---
.../config/beans/IsisBeanTypeClassifierImpl.java | 24 ++++++++++--
.../core/config/beans/IsisBeanTypeRegistry.java | 2 +
.../config/beans/IsisBeanTypeRegistryDefault.java | 2 +
.../beans/IsisComponentScanInterceptorImpl.java | 2 +-
.../specloader/SpecificationLoaderDefault.java | 44 ++++++++++++++--------
.../jdo/metamodel/beans/JdoBeanTypeClassifier.java | 6 ++-
10 files changed, 97 insertions(+), 29 deletions(-)
diff --git a/api/applib/src/main/java/org/apache/isis/applib/value/Clob.java b/api/applib/src/main/java/org/apache/isis/applib/value/Clob.java
index 37d3e2a..cfb8b5e 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/value/Clob.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/value/Clob.java
@@ -36,7 +36,6 @@ import org.apache.isis.applib.jaxb.PrimitiveJaxbAdapters;
import org.apache.isis.commons.internal.base._Strings;
import lombok.val;
-import lombok.extern.log4j.Log4j2;
/**
* Represents a character large object.
@@ -64,7 +63,7 @@ import lombok.extern.log4j.Log4j2;
"org.apache.isis.core.metamodel.facets.value.clobs.ClobValueSemanticsProvider")
@DomainObject(logicalTypeName = IsisModuleApplib.NAMESPACE + ".value.Clob")
@XmlJavaTypeAdapter(Clob.JaxbToStringAdapter.class) // for JAXB view model support
-@Log4j2
+//@Log4j2
public final class Clob implements NamedWithMimeType {
/**
diff --git a/commons/src/main/java/org/apache/isis/commons/internal/functions/_Predicates.java b/commons/src/main/java/org/apache/isis/commons/internal/functions/_Predicates.java
index bf2a148..62b9b62 100644
--- a/commons/src/main/java/org/apache/isis/commons/internal/functions/_Predicates.java
+++ b/commons/src/main/java/org/apache/isis/commons/internal/functions/_Predicates.java
@@ -62,6 +62,14 @@ public final class _Predicates {
}
/**
+ *
+ * @return a Predicate that always tests false
+ */
+ public static <T> Predicate<T> alwaysFalse() {
+ return __->false;
+ }
+
+ /**
* @return a Predicate that tests for the operand to be not null
*/
public static <T> Predicate<T> isPresent() {
diff --git a/core/config/src/main/java/org/apache/isis/core/config/beans/IsisBeanFactoryPostProcessorForSpring.java b/core/config/src/main/java/org/apache/isis/core/config/beans/IsisBeanFactoryPostProcessorForSpring.java
index dc984cf..f7cbe38 100644
--- a/core/config/src/main/java/org/apache/isis/core/config/beans/IsisBeanFactoryPostProcessorForSpring.java
+++ b/core/config/src/main/java/org/apache/isis/core/config/beans/IsisBeanFactoryPostProcessorForSpring.java
@@ -67,8 +67,7 @@ implements
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
- val environment = applicationContext.getEnvironment();
- isisBeanTypeClassifier = IsisBeanTypeClassifier.createInstance(environment);
+ isisBeanTypeClassifier = IsisBeanTypeClassifier.createInstance(applicationContext);
isisComponentScanInterceptor = IsisComponentScanInterceptor.createInstance(isisBeanTypeClassifier);
}
diff --git a/core/config/src/main/java/org/apache/isis/core/config/beans/IsisBeanTypeClassifier.java b/core/config/src/main/java/org/apache/isis/core/config/beans/IsisBeanTypeClassifier.java
index f3b7703..9e1335b 100644
--- a/core/config/src/main/java/org/apache/isis/core/config/beans/IsisBeanTypeClassifier.java
+++ b/core/config/src/main/java/org/apache/isis/core/config/beans/IsisBeanTypeClassifier.java
@@ -18,7 +18,12 @@
*/
package org.apache.isis.core.config.beans;
-import org.springframework.core.env.Environment;
+import java.util.Set;
+import java.util.function.Predicate;
+
+import javax.annotation.Nullable;
+
+import org.springframework.context.ApplicationContext;
import org.apache.isis.applib.services.metamodel.BeanSort;
import org.apache.isis.commons.collections.Can;
@@ -39,10 +44,11 @@ public interface IsisBeanTypeClassifier {
* Returns the bean classification for given {@code type}.
*
* @apiNote Initially used to collect all concrete types that are considered by Spring
- * for type inspection, but later used by the {@code SpecificationLoader} to also
+ * for type inspection, most likely without any {@code context} yet being available,
+ * but later used by the {@code SpecificationLoader} to also
* classify non-concrete types (interfaces and abstract classes).
*/
- BeanClassification classify(Class<?> type);
+ BeanClassification classify(Class<?> type, @Nullable BeanClassificationContext context);
// -- FACTORY
@@ -53,8 +59,9 @@ public interface IsisBeanTypeClassifier {
return new IsisBeanTypeClassifierImpl(Can.empty());
}
- static IsisBeanTypeClassifier createInstance(final @NonNull Environment environment) {
- return new IsisBeanTypeClassifierImpl(Can.ofArray(environment.getActiveProfiles()));
+ static IsisBeanTypeClassifier createInstance(final @NonNull ApplicationContext applicationContext) {
+ return new IsisBeanTypeClassifierImpl(
+ Can.ofArray(applicationContext.getEnvironment().getActiveProfiles()));
}
// -- LOOKUP
@@ -63,6 +70,17 @@ public interface IsisBeanTypeClassifier {
return Can.ofCollection(_Plugin.loadAll(IsisBeanTypeClassifier.class));
}
+ // -- BEAN CLASSIFICATION CONTEXT
+
+ @Value
+ public static class BeanClassificationContext {
+ private final @NonNull Predicate<Class<?>> isRegisteredValueType;
+ }
+
+ static BeanClassificationContext newContext(final Set<Class<?>> registeredValueTypes) {
+ return new BeanClassificationContext(registeredValueTypes::contains);
+ }
+
// -- BEAN CLASSIFICATION RESULT
@Value(staticConstructor = "of")
@@ -92,4 +110,8 @@ public interface IsisBeanTypeClassifier {
}
+
+
+
+
}
diff --git a/core/config/src/main/java/org/apache/isis/core/config/beans/IsisBeanTypeClassifierImpl.java b/core/config/src/main/java/org/apache/isis/core/config/beans/IsisBeanTypeClassifierImpl.java
index 1dba6f2..48bf001 100644
--- a/core/config/src/main/java/org/apache/isis/core/config/beans/IsisBeanTypeClassifierImpl.java
+++ b/core/config/src/main/java/org/apache/isis/core/config/beans/IsisBeanTypeClassifierImpl.java
@@ -23,6 +23,7 @@ import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Locale;
+import javax.annotation.Nullable;
import javax.enterprise.inject.Vetoed;
import javax.persistence.Entity;
import javax.persistence.Table;
@@ -54,7 +55,9 @@ implements IsisBeanTypeClassifier {
private final Can<IsisBeanTypeClassifier> classifierPlugins = IsisBeanTypeClassifier.get();
@Override
- public BeanClassification classify(final @NonNull Class<?> type) {
+ public BeanClassification classify(
+ final @NonNull Class<?> type,
+ final @Nullable BeanClassificationContext beanClassificationContext) {
// handle arbitrary types ...
@@ -80,7 +83,7 @@ implements IsisBeanTypeClassifier {
return BeanClassification.delegated(BeanSort.ABSTRACT);
}
- // handle actual bean types ...
+ // handle vetoing ...
if(findNearestAnnotation(type, Vetoed.class).isPresent()
|| findNearestAnnotation(type, Programmatic.class).isPresent()) {
@@ -95,6 +98,21 @@ implements IsisBeanTypeClassifier {
return BeanClassification.selfManaged(BeanSort.VETOED); // reject
}
+ // handle value types ...
+
+ if(beanClassificationContext!=null
+ && beanClassificationContext.getIsRegisteredValueType().test(type)) {
+ return BeanClassification.delegated(BeanSort.VALUE);
+ }
+
+ val aValue = findNearestAnnotation(type, org.apache.isis.applib.annotation.Value.class)
+ .orElse(null);
+ if(aValue!=null) {
+ return BeanClassification.delegated(BeanSort.VALUE);
+ }
+
+ // handle actual bean types ...
+
val aDomainService = findNearestAnnotation(type, DomainService.class);
if(aDomainService.isPresent()) {
return BeanClassification
@@ -104,7 +122,7 @@ implements IsisBeanTypeClassifier {
// allow ServiceLoader plugins to have a say, eg. when classifying entity types
for(val classifier : classifierPlugins) {
- val classification = classifier.classify(type);
+ val classification = classifier.classify(type, beanClassificationContext);
if(classification!=null) {
return classification;
}
diff --git a/core/config/src/main/java/org/apache/isis/core/config/beans/IsisBeanTypeRegistry.java b/core/config/src/main/java/org/apache/isis/core/config/beans/IsisBeanTypeRegistry.java
index f58751e..168c239 100644
--- a/core/config/src/main/java/org/apache/isis/core/config/beans/IsisBeanTypeRegistry.java
+++ b/core/config/src/main/java/org/apache/isis/core/config/beans/IsisBeanTypeRegistry.java
@@ -36,6 +36,8 @@ public interface IsisBeanTypeRegistry {
Set<Class<?>> getEntityTypes();
Set<Class<?>> getMixinTypes();
Set<Class<?>> getViewModelTypes();
+ /** discovered per {@code @Value} annotation (vs. registered using ValueTypeResgistry)*/
+ Set<Class<?>> getDiscoveredValueTypes();
// -- LOOKUPS
diff --git a/core/config/src/main/java/org/apache/isis/core/config/beans/IsisBeanTypeRegistryDefault.java b/core/config/src/main/java/org/apache/isis/core/config/beans/IsisBeanTypeRegistryDefault.java
index ea91ada..684ec1a 100644
--- a/core/config/src/main/java/org/apache/isis/core/config/beans/IsisBeanTypeRegistryDefault.java
+++ b/core/config/src/main/java/org/apache/isis/core/config/beans/IsisBeanTypeRegistryDefault.java
@@ -63,6 +63,7 @@ public class IsisBeanTypeRegistryDefault implements IsisBeanTypeRegistry {
@Getter(onMethod_ = {@Override}) private final Set<Class<?>> entityTypes = new HashSet<>();
@Getter(onMethod_ = {@Override}) private final Set<Class<?>> mixinTypes = new HashSet<>();
@Getter(onMethod_ = {@Override}) private final Set<Class<?>> viewModelTypes = new HashSet<>();
+ @Getter(onMethod_ = {@Override}) private final Set<Class<?>> discoveredValueTypes = new HashSet<>();
// -- LOOKUPS
@@ -108,6 +109,7 @@ public class IsisBeanTypeRegistryDefault implements IsisBeanTypeRegistry {
case MANAGED_BEAN_NOT_CONTRIBUTING:
case COLLECTION:
case VALUE:
+ discoveredValueTypes.add(cls);
case ABSTRACT: // <-- unexpected code reach
case VETOED:
case UNKNOWN:
diff --git a/core/config/src/main/java/org/apache/isis/core/config/beans/IsisComponentScanInterceptorImpl.java b/core/config/src/main/java/org/apache/isis/core/config/beans/IsisComponentScanInterceptorImpl.java
index acdc89c..55dd225 100644
--- a/core/config/src/main/java/org/apache/isis/core/config/beans/IsisComponentScanInterceptorImpl.java
+++ b/core/config/src/main/java/org/apache/isis/core/config/beans/IsisComponentScanInterceptorImpl.java
@@ -79,7 +79,7 @@ implements IsisComponentScanInterceptor {
}
val type = classOrFailure.getUnderlyingClass();
- val classification = isisBeanTypeClassifier.classify(type);
+ val classification = isisBeanTypeClassifier.classify(type, /*BeanClassificationContext*/null);
val delegated = classification.isDelegateLifecycleManagement();
typeMeta.setInjectable(delegated);
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 0ef398e..34eea97 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
@@ -20,12 +20,15 @@ package org.apache.isis.core.metamodel.specloader;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashSet;
import java.util.Optional;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
@@ -49,6 +52,7 @@ import org.apache.isis.commons.internal.base._Blackhole;
import org.apache.isis.commons.internal.base._Lazy;
import org.apache.isis.commons.internal.base._Timing;
import org.apache.isis.commons.internal.collections._Lists;
+import org.apache.isis.commons.internal.collections._Maps;
import org.apache.isis.commons.internal.exceptions._Exceptions;
import org.apache.isis.core.config.IsisConfiguration;
import org.apache.isis.core.config.beans.IsisBeanMetaData;
@@ -114,6 +118,7 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
private final IsisBeanTypeRegistry isisBeanTypeRegistry;
private final ClassSubstitutorRegistry classSubstitutorRegistry;
private final ValueTypeRegistry valueTypeRegistry;
+ private final IsisBeanTypeClassifier.BeanClassificationContext beanClassificationContext;
private final ProgrammingModel programmingModel;
private final PostProcessor postProcessor;
@@ -171,6 +176,10 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
this.isisBeanTypeRegistry = isisBeanTypeRegistry;
this.valueTypeRegistry = valueTypeRegistry;
this.classSubstitutorRegistry = classSubstitutorRegistry;
+ this.beanClassificationContext = IsisBeanTypeClassifier
+ .newContext(valueTypeRegistry
+ .streamRegisteredClasses()
+ .collect(Collectors.toCollection(HashSet::new)));
}
/** JUnit Test Support */
@@ -230,18 +239,21 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
// (an optimization, not strictly required)
loadSpecifications(ApplicationFeatureSort.class/*, ...*/);
- log.info(" - adding types from ValueTypeProviders");
+ log.info(" - adding value types from from class-path scan and ValueTypeProviders");
- val valueTypeSpecs = _Lists.<ObjectSpecification>newArrayList();
+ val valueTypeSpecs = _Maps.<Class<?>, ObjectSpecification>newHashMap();
- valueTypeRegistry.streamRegisteredClasses()
- .forEach(cls -> {
- val spec = loadSpecification(cls, IntrospectionState.NOT_INTROSPECTED);
- if(spec!=null) {
- knownSpecs.add(spec);
- valueTypeSpecs.add(spec);
- }
- });
+ Stream
+ .concat(
+ isisBeanTypeRegistry.getDiscoveredValueTypes().stream(),
+ valueTypeRegistry.streamRegisteredClasses())
+ .forEach(valueType -> {
+ val valueSpec = loadSpecification(valueType, IntrospectionState.NOT_INTROSPECTED);
+ if(valueSpec!=null) {
+ knownSpecs.add(valueSpec);
+ valueTypeSpecs.put(valueType, valueSpec);
+ }
+ });
log.info(" - categorizing types from class-path scan");
@@ -278,12 +290,12 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
introspect(Can.ofCollection(knownSpecs), IntrospectionState.TYPE_INTROSPECTED);
log.info(" - introspecting {} value types", valueTypeSpecs.size());
- introspect(Can.ofCollection(valueTypeSpecs), IntrospectionState.FULLY_INTROSPECTED);
+ introspect(Can.ofCollection(valueTypeSpecs.values()), IntrospectionState.FULLY_INTROSPECTED);
log.info(" - introspecting {} mixins", isisBeanTypeRegistry.getMixinTypes().size());
introspect(Can.ofCollection(mixinSpecs), IntrospectionState.FULLY_INTROSPECTED);
- log.info(" - introspecting {} managed beans contributing (aka domain services)", isisBeanTypeRegistry.getManagedBeansContributing().size());
+ log.info(" - introspecting {} managed beans contributing (domain services)", isisBeanTypeRegistry.getManagedBeansContributing().size());
// log.info(" - introspecting {}/{} entities (JDO/JPA)",
// isisBeanTypeRegistry.getEntityTypesJdo().size(),
// isisBeanTypeRegistry.getEntityTypesJpa().size());
@@ -378,7 +390,8 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
__->isisBeanTypeRegistry
.lookupIntrospectableType(type)
.map(IsisBeanMetaData::getBeanSort)
- .orElseGet(()->isisBeanTypeClassifier.classify(type).getBeanSort()),
+ .orElseGet(()->isisBeanTypeClassifier.classify(type, beanClassificationContext)
+ .getBeanSort()),
upTo);
}
@@ -557,8 +570,9 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
if(isMetamodelFullyIntrospected()
&& isisConfiguration.getCore().getMetaModel().getIntrospector().isLockAfterFullIntrospection()) {
- val category = isisBeanTypeClassifier.classify(cls);
- val sort = category.getBeanSort();
+ val sort = isisBeanTypeClassifier
+ .classify(cls, beanClassificationContext)
+ .getBeanSort();
// ISIS-2256:
// throw _Exceptions.illegalState(
diff --git a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/beans/JdoBeanTypeClassifier.java b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/beans/JdoBeanTypeClassifier.java
index 84edc36..8d31c09 100644
--- a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/beans/JdoBeanTypeClassifier.java
+++ b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/beans/JdoBeanTypeClassifier.java
@@ -20,6 +20,7 @@ package org.apache.isis.persistence.jdo.metamodel.beans;
import java.util.Locale;
+import javax.annotation.Nullable;
import javax.jdo.annotations.EmbeddedOnly;
import org.apache.isis.applib.annotation.DomainObject;
@@ -40,7 +41,9 @@ import lombok.val;
public class JdoBeanTypeClassifier implements IsisBeanTypeClassifier {
@Override
- public BeanClassification classify(Class<?> type) {
+ public BeanClassification classify(
+ final Class<?> type,
+ final @Nullable BeanClassificationContext context) {
val persistenceCapableAnnot = findNearestAnnotation(type, javax.jdo.annotations.PersistenceCapable.class);
if(persistenceCapableAnnot.isPresent()) {
@@ -86,4 +89,5 @@ public class JdoBeanTypeClassifier implements IsisBeanTypeClassifier {
return null; // we don't feel responsible to classify given type
}
+
}