You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@causeway.apache.org by ah...@apache.org on 2024/11/12 04:38:55 UTC

(causeway) branch v3 updated: CAUSEWAY-2297: move attribute enum to class cache

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch v3
in repository https://gitbox.apache.org/repos/asf/causeway.git


The following commit(s) were added to refs/heads/v3 by this push:
     new d09ede6c23e CAUSEWAY-2297: move attribute enum to class cache
d09ede6c23e is described below

commit d09ede6c23e2cd121b79e95b1ef4374a8ca6a366
Author: Andi Huber <ah...@apache.org>
AuthorDate: Tue Nov 12 05:38:51 2024 +0100

    CAUSEWAY-2297: move attribute enum to class cache
---
 .../commons/internal/reflection/_ClassCache.java   | 75 ++++++++++++----------
 .../config/beans/CausewayBeanTypeClassifier.java   | 72 +++++++--------------
 .../config/beans/CausewayComponentCollector.java   |  4 +-
 .../RemoveAnnotatedMethodsFacetFactory.java        |  5 +-
 .../specimpl/dflt/ObjectSpecificationDefault.java  |  6 +-
 5 files changed, 69 insertions(+), 93 deletions(-)

diff --git a/commons/src/main/java/org/apache/causeway/commons/internal/reflection/_ClassCache.java b/commons/src/main/java/org/apache/causeway/commons/internal/reflection/_ClassCache.java
index 931bdd25dbf..acf7a702014 100644
--- a/commons/src/main/java/org/apache/causeway/commons/internal/reflection/_ClassCache.java
+++ b/commons/src/main/java/org/apache/causeway/commons/internal/reflection/_ClassCache.java
@@ -18,6 +18,7 @@
  */
 package org.apache.causeway.commons.internal.reflection;
 
+import java.lang.annotation.Annotation;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
@@ -37,6 +38,7 @@ import jakarta.xml.bind.annotation.XmlRootElement;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.MergedAnnotation;
 import org.springframework.core.annotation.MergedAnnotations;
 import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
 import org.springframework.lang.Nullable;
@@ -80,6 +82,17 @@ import lombok.SneakyThrows;
  */
 @RequiredArgsConstructor(access = AccessLevel.PRIVATE)
 public final class _ClassCache implements AutoCloseable {
+    
+    public enum Attribute {
+        /**
+         * Corresponds to the bean name of Spring managed beans.  
+         */
+        SPRING_NAMED,
+        /**
+         * Corresponds to DomainObject#mixinMethod().
+         */
+        MIXIN_MAIN_METHOD_NAME;
+    }
 
     public static _ClassCache getInstance() {
         return _Context.computeIfAbsent(_ClassCache.class, ()->new _ClassCache(_Context.getDefaultClassLoader()));
@@ -107,14 +120,14 @@ public final class _ClassCache implements AutoCloseable {
         return classModel(type).head().named()!=null;
     }
     
-    public void setNamed(Class<?> beanClass, String beanDefinitionName) {
+    public void setSpringNamed(Class<?> beanClass, String beanDefinitionName) {
         _Assert.assertNotEmpty(beanDefinitionName);
-        classModel(beanClass).attributeMap().put("NAMED", beanDefinitionName);
+        classModel(beanClass).head().attributeMap().put(Attribute.SPRING_NAMED, beanDefinitionName);
     }
     
     public String getLogicalName(final Class<?> type) {
         var model = classModel(type);
-        return Optional.ofNullable(model.attributeMap().get("NAMED"))
+        return Optional.ofNullable(model.head().attributeMap().get(Attribute.SPRING_NAMED))
                 .or(()->Optional.ofNullable(model.head().named()))
                 .or(()->Optional.ofNullable(type.getCanonicalName()))
                 .orElseGet(type::getName);
@@ -244,49 +257,47 @@ public final class _ClassCache implements AutoCloseable {
         }
     }
 
-    // -- ATTRIBUTES
-
-    public _ClassCache setAttribute(
-            final Class<?> type,
-            final String attributeName,
-            final String value) {
-        var classModel = classModel(type);
-        classModel.attributeMap.put(attributeName, value);
-        return this;
-    }
-
-    public Optional<String> lookupAttribute(
-            final Class<?> type,
-            final String attributeName) {
-        var classModel = classModel(type);
-        return Optional.ofNullable(classModel.attributeMap.get(attributeName));
-    }
-
     // -- IMPLEMENATION DETAILS
 
     public record ClassModelHead(
             MergedAnnotations mergedAnnotations,
             /** explicit name if any */
-            @Nullable String named) {
+            @Nullable String named,
+            Map<Attribute, String> attributeMap) {
         
         static ClassModelHead create(final Class<?> type) {
             var mergedAnnotations = MergedAnnotations.from(type, SearchStrategy.TYPE_HIERARCHY);
-            return new ClassModelHead(mergedAnnotations, _ClassCacheUtil.inferName(type, mergedAnnotations));
+            return new ClassModelHead(mergedAnnotations, _ClassCacheUtil.inferName(type, mergedAnnotations), 
+                    new ConcurrentHashMap<>());
+        }
+        
+        /**
+         * @see MergedAnnotations#get(Class)
+         */
+        public <A extends Annotation> MergedAnnotation<A> annotation(Class<A> annotationType) { 
+            return mergedAnnotations.get(annotationType);
+        }
+        
+        /**
+         * whether type is annotated with annotationType
+         */
+        public boolean hasAnnotation(Class<? extends Annotation> annotationType) { 
+            return mergedAnnotations.get(annotationType).isPresent();
         }
         
         /**
          * whether type is annotated with {@link BeanInternal} or {@link Configuration}
          */
         public boolean hasInternalBeanSemantics() { 
-            return mergedAnnotations.get(BeanInternal.class).isPresent() 
-                    || mergedAnnotations.get(Configuration.class).isPresent();
+            return hasAnnotation(BeanInternal.class) 
+                    || hasAnnotation(Configuration.class);
         }
 
         /**
          * whether type is annotated with {@link XmlRootElement}
          */
         public boolean hasJaxbRootElementSemantics() { 
-            return mergedAnnotations.get(XmlRootElement.class).isPresent();
+            return hasAnnotation(XmlRootElement.class);
         }
         
         /**
@@ -308,10 +319,8 @@ public final class _ClassCache implements AutoCloseable {
             Map<MethodKey, ResolvedMethod> resolvedMethodsByKey,
             Map<MethodKey, ResolvedMethod> publicMethodsByKey,
             Map<MethodKey, ResolvedMethod> postConstructMethodsByKey,
-
-            Map<String, Can<ResolvedMethod>> declaredMethodsByAttribute,
-            Map<String, String> attributeMap
-            ) {
+            
+            Map<String, Can<ResolvedMethod>> declaredMethodsByAttribute) {
 
         ClassModel(
                 ClassModelHead head,
@@ -319,16 +328,14 @@ public final class _ClassCache implements AutoCloseable {
             this(head,
                     declaredFields,
                     new HashMap<>(), new HashMap<>(), new HashMap<>(), 
-                    new HashMap<>(), new HashMap<>(), new HashMap<>(), 
-                    new ConcurrentHashMap<>());
+                    new HashMap<>(), new HashMap<>(), new HashMap<>());
         }
 
         public static ClassModel headOnly(ClassModelHead head) {
             return new ClassModel(head,
                 Can.empty(), 
                 Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap(), 
-                Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap(),
-                Collections.emptyMap());
+                Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap());
         }
         
     }
diff --git a/core/config/src/main/java/org/apache/causeway/core/config/beans/CausewayBeanTypeClassifier.java b/core/config/src/main/java/org/apache/causeway/core/config/beans/CausewayBeanTypeClassifier.java
index 43deaa3b753..f00e44e578c 100644
--- a/core/config/src/main/java/org/apache/causeway/core/config/beans/CausewayBeanTypeClassifier.java
+++ b/core/config/src/main/java/org/apache/causeway/core/config/beans/CausewayBeanTypeClassifier.java
@@ -20,7 +20,6 @@ package org.apache.causeway.core.config.beans;
 
 import java.io.Serializable;
 import java.lang.reflect.Modifier;
-import java.util.Optional;
 import java.util.function.Supplier;
 
 import jakarta.persistence.Entity;
@@ -50,27 +49,6 @@ public record CausewayBeanTypeClassifier(
         @NonNull Can<String> activeProfiles,
         @NonNull _ClassCache classCache) {
     
-    public enum Attributes {
-        /**
-         * Corresponds to presence of a {@link DomainService} annotation.
-         * @see _ClassCache#lookupAttribute(Class, String)
-         */
-        HAS_DOMAIN_SERVICE_SEMANTICS,
-
-        /**
-         * Corresponds to {@link DomainObject#mixinMethod()}.
-         * @see _ClassCache#lookupAttribute(Class, String)
-         */
-        MIXIN_MAIN_METHOD_NAME;
-
-        public void set(final _ClassCache classCache, final Class<?> type, final String attributeValue) {
-            classCache.setAttribute(type, this.name(), attributeValue);
-        }
-        public Optional<String> lookup(final _ClassCache classCache, final Class<?> type) {
-            return classCache.lookupAttribute(type, this.name());
-        }
-    }
-    
     // -- CONSTRUCTION
     
     CausewayBeanTypeClassifier(final ApplicationContext applicationContext) {
@@ -133,43 +111,37 @@ public record CausewayBeanTypeClassifier(
             return CausewayBeanMetaData.notManaged(discoveredBy, BeanSort.VETOED, named.get()); // reject
         }
 
-        // handle value types ...
-
-        var aValue = _Annotations.synthesize(type, org.apache.causeway.applib.annotation.Value.class)
-                .orElse(null);
-        if(aValue!=null) {
-            return CausewayBeanMetaData.notManaged(discoveredBy, BeanSort.VALUE, named.get());
+        //[CAUSEWAY-3585] when implements ViewModel, then don't consider alternatives, yield VIEW_MODEL
+        if(org.apache.causeway.applib.ViewModel.class.isAssignableFrom(type)) {
+            return CausewayBeanMetaData.causewayManaged(discoveredBy, BeanSort.VIEW_MODEL, named.get());
         }
         
-        // handle internal bean types ...
+        var typeHead = classCache().head(type);
         
-        if(classCache.head(type).hasInternalBeanSemantics()) {
+        // value types
+        if(typeHead.hasAnnotation(org.apache.causeway.applib.annotation.Value.class)) {
+            return CausewayBeanMetaData.notManaged(discoveredBy, BeanSort.VALUE, named.get());
+        }
+        
+        // internal bean types
+        if(typeHead.hasInternalBeanSemantics()) {
             return CausewayBeanMetaData.springManaged(discoveredBy, BeanSort.MANAGED_BEAN_NOT_CONTRIBUTING, logicalType);
         }
 
-        // handle actual bean types ...
-
-        var aDomainService = _Annotations.synthesize(type, DomainService.class);
-        if(aDomainService.isPresent()) {
-            Attributes.HAS_DOMAIN_SERVICE_SEMANTICS.set(classCache, type, "true");
+        // domain service
+        if(typeHead.hasAnnotation(DomainService.class)) {
             return CausewayBeanMetaData.springManaged(discoveredBy, BeanSort.MANAGED_BEAN_CONTRIBUTING, logicalType);
         }
 
-        //[CAUSEWAY-3585] when implements ViewModel, then don't consider alternatives, yield VIEW_MODEL
-        if(org.apache.causeway.applib.ViewModel.class.isAssignableFrom(type)) {
-            return CausewayBeanMetaData.causewayManaged(discoveredBy, BeanSort.VIEW_MODEL, named.get());
-        }
-
-        // JDO entity support
-        if(classCache.head(type).isJdoPersistenceCapable()){
+        // entity support
+        if(typeHead.isJdoPersistenceCapable()){
             return CausewayBeanMetaData.entity(discoveredBy, PersistenceStack.JDO, named.get());
         }
-  
-        var entityAnnotation = _Annotations.synthesize(type, Entity.class).orElse(null);
-        if(entityAnnotation!=null) {
+        if(typeHead.hasAnnotation(Entity.class)) {
             return CausewayBeanMetaData.entity(discoveredBy, PersistenceStack.JPA, named.get());
-        }
-
+        }  
+        
+        // domain object
         var aDomainObject = _Annotations.synthesize(type, DomainObject.class).orElse(null);
         if(aDomainObject!=null) {
             switch (aDomainObject.nature()) {
@@ -177,7 +149,7 @@ public record CausewayBeanTypeClassifier(
                 return CausewayBeanMetaData.unspecified(discoveredBy, BeanSort.MANAGED_BEAN_CONTRIBUTING, named.get());
             case MIXIN:
                 // memoize mixin main name
-                Attributes.MIXIN_MAIN_METHOD_NAME.set(classCache, type, aDomainObject.mixinMethod());
+                typeHead.attributeMap().put(_ClassCache.Attribute.MIXIN_MAIN_METHOD_NAME, aDomainObject.mixinMethod());
                 return CausewayBeanMetaData.causewayManaged(discoveredBy, BeanSort.MIXIN, named.get());
             case ENTITY:
                 return CausewayBeanMetaData.entity(discoveredBy, PersistenceStack.UNSPECIFIED, named.get());
@@ -188,11 +160,11 @@ public record CausewayBeanTypeClassifier(
             }
         }
 
-        if(_ClassCache.getInstance().head(type).hasJaxbRootElementSemantics()) {
+        if(typeHead.hasJaxbRootElementSemantics()) {
             return CausewayBeanMetaData.causewayManaged(discoveredBy, BeanSort.VIEW_MODEL, named.get());
         }
 
-        if(_Annotations.isPresent(type, Component.class)) {
+        if(typeHead.hasAnnotation(Component.class)) {
             return CausewayBeanMetaData.unspecified(discoveredBy, BeanSort.MANAGED_BEAN_NOT_CONTRIBUTING, logicalType);
         }
 
diff --git a/core/config/src/main/java/org/apache/causeway/core/config/beans/CausewayComponentCollector.java b/core/config/src/main/java/org/apache/causeway/core/config/beans/CausewayComponentCollector.java
index fc9e14c5457..0ded0d72a3f 100644
--- a/core/config/src/main/java/org/apache/causeway/core/config/beans/CausewayComponentCollector.java
+++ b/core/config/src/main/java/org/apache/causeway/core/config/beans/CausewayComponentCollector.java
@@ -71,13 +71,13 @@ record CausewayComponentCollector(
             case UNSPECIFIED -> {
                 if(isRenamed) {
                     //rename(beanDefinition, beanDefinitionName, typeMeta.logicalType().logicalName()); //TODO does not work yet
-                    _ClassCache.getInstance().setNamed(beanClass, beanDefinitionName);
+                    _ClassCache.getInstance().setSpringNamed(beanClass, beanDefinitionName);
                 }
             }
             case SPRING -> {
                 if(isRenamed) {
                     // renaming not allowed, report back to class-cache
-                    _ClassCache.getInstance().setNamed(beanClass, beanDefinitionName);
+                    _ClassCache.getInstance().setSpringNamed(beanClass, beanDefinitionName);
                 }
             }
         }
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/ignore/annotation/RemoveAnnotatedMethodsFacetFactory.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/ignore/annotation/RemoveAnnotatedMethodsFacetFactory.java
index ff512a37b87..2d8d9dab8e5 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/ignore/annotation/RemoveAnnotatedMethodsFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/ignore/annotation/RemoveAnnotatedMethodsFacetFactory.java
@@ -23,8 +23,8 @@ import java.util.function.Predicate;
 import jakarta.inject.Inject;
 
 import org.apache.causeway.commons.internal.functions._Predicates;
+import org.apache.causeway.commons.internal.reflection._ClassCache.Attribute;
 import org.apache.causeway.commons.internal.reflection._GenericResolver.ResolvedMethod;
-import org.apache.causeway.core.config.beans.CausewayBeanTypeClassifier.Attributes;
 import org.apache.causeway.core.config.progmodel.ProgrammingModelConstants;
 import org.apache.causeway.core.metamodel.context.MetaModelContext;
 import org.apache.causeway.core.metamodel.facetapi.FeatureType;
@@ -100,8 +100,7 @@ extends FacetFactoryAbstract {
         }
         // lookup attribute from class-cache as it should have been already processed by the BeanTypeClassifier
         var cls = processClassContext.getCls();
-        var mixinMainMethodName = Attributes.MIXIN_MAIN_METHOD_NAME.lookup(getClassCache(), cls)
-            .orElse(null);
+        var mixinMainMethodName = getClassCache().head(cls).attributeMap().get(Attribute.MIXIN_MAIN_METHOD_NAME);
         return method->method.name().equals(mixinMainMethodName);
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
index 4f7a8f09b31..a3ba504ac6f 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
@@ -27,6 +27,7 @@ import java.util.stream.Stream;
 import org.springframework.lang.Nullable;
 
 import org.apache.causeway.applib.Identifier;
+import org.apache.causeway.applib.annotation.DomainService;
 import org.apache.causeway.applib.annotation.Introspection.IntrospectionPolicy;
 import org.apache.causeway.commons.collections.Can;
 import org.apache.causeway.commons.collections.ImmutableEnumSet;
@@ -41,7 +42,6 @@ import org.apache.causeway.commons.internal.reflection._GenericResolver.Resolved
 import org.apache.causeway.commons.internal.reflection._MethodFacades.MethodFacade;
 import org.apache.causeway.commons.internal.reflection._Reflect;
 import org.apache.causeway.core.config.beans.CausewayBeanMetaData;
-import org.apache.causeway.core.config.beans.CausewayBeanTypeClassifier.Attributes;
 import org.apache.causeway.core.metamodel.commons.ToString;
 import org.apache.causeway.core.metamodel.context.MetaModelContext;
 import org.apache.causeway.core.metamodel.facetapi.FacetHolder;
@@ -353,9 +353,7 @@ implements FacetHolder {
     }
 
     private _Lazy<Boolean> isDomainServiceLazy = _Lazy.threadSafe(()->
-        Attributes.HAS_DOMAIN_SERVICE_SEMANTICS.lookup(_ClassCache.getInstance(), getCorrespondingClass())
-            .map("true"::equals)
-            .orElse(false));
+        _ClassCache.getInstance().head(getCorrespondingClass()).hasAnnotation(DomainService.class));
 
     @Override
     public boolean isDomainService() {