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 2023/08/30 09:31:49 UTC

[causeway] branch master updated: CAUSEWAY-3556: _ClassCache regression: keep toString() methods when overwritten

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/causeway.git


The following commit(s) were added to refs/heads/master by this push:
     new dc5414e845 CAUSEWAY-3556: _ClassCache regression: keep toString() methods when overwritten
dc5414e845 is described below

commit dc5414e845833d5e8a3951a63e422fa2deb9d1cc
Author: Andi Huber <ah...@apache.org>
AuthorDate: Wed Aug 30 11:31:44 2023 +0200

    CAUSEWAY-3556: _ClassCache regression: keep toString() methods when
    overwritten
---
 .../commons/internal/reflection/_ClassCache.java   |  7 +++----
 .../commons/internal/reflection/_Reflect.java      | 23 ++++++++++++++++++++--
 .../core/metamodel/commons/ClassExtensions.java    |  6 ------
 .../causeway/core/metamodel/commons/ClassUtil.java |  2 --
 .../ignore/javalang/RemoveMethodsFacetFactory.java |  3 +--
 .../object/support/ObjectSupportFacetFactory.java  |  2 --
 .../methods/TitleFacetFromToStringMethod.java      |  4 ++--
 .../core/metamodel/methods/MethodFinderPAT.java    |  4 ++--
 .../title/TitleFacetViaMethodsFactoryTest.java     |  2 +-
 9 files changed, 30 insertions(+), 23 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 a9d42d70b3..073555e9fe 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
@@ -255,7 +255,9 @@ public final class _ClassCache implements AutoCloseable {
         return method.isBridge()
                 || Modifier.isStatic(method.getModifiers())
                 || method.getDeclaringClass().equals(Object.class)
-                || _Reflect.isNonFinalObjectMethod(method)
+                || (_Reflect.isNonFinalObjectMethod(method)
+                        // keep overwritten toString() methods, see TitleFacetFromToStringMethod
+                        && !_Reflect.isOverwrittenToString(method))
                 || _Reflect.hasGenericBounds(method);
     }
 
@@ -432,7 +434,4 @@ public final class _ClassCache implements AutoCloseable {
         }
         return _Strings.decapitalize(fieldName);
     }
-
-
-
 }
diff --git a/commons/src/main/java/org/apache/causeway/commons/internal/reflection/_Reflect.java b/commons/src/main/java/org/apache/causeway/commons/internal/reflection/_Reflect.java
index d2a6f8b17a..e0ac8932e2 100644
--- a/commons/src/main/java/org/apache/causeway/commons/internal/reflection/_Reflect.java
+++ b/commons/src/main/java/org/apache/causeway/commons/internal/reflection/_Reflect.java
@@ -781,19 +781,38 @@ public final class _Reflect {
 
     }
 
-    public Method guardAgainstSynthetic(final Method method) {
+    public Method guardAgainstSynthetic(final @NonNull Method method) {
         _Assert.assertFalse(method.isSynthetic(), ()->
             String.format("unsupported synthetic method %s", method));
         return method;
     }
 
-    public boolean isNonFinalObjectMethod(final Method method) {
+    // -- SPECIAL PREDICATES
+
+    public boolean isNonFinalObjectMethod(final @NonNull Method method) {
         for(val m : _Constants.nonFinalObjectMethods) {
             if(methodsSame(m, method)) return true;
         }
         return false;
     }
 
+    /**
+     * Whether given {@link Method} overrides {@link Object#toString()}
+     * and its declaring {@link Class} is a non Java API class.
+     * @see #isJavaApiClass(Class)
+     */
+    public boolean isOverwrittenToString(final @NonNull Method method) {
+        return method.getName().equals("toString")
+                && method.getParameterCount() == 0
+                && !isJavaApiClass(method.getDeclaringClass());
+    }
+
+    public boolean isJavaApiClass(final @NonNull Class<?> cls) {
+        val className = cls.getName();
+        return className.startsWith("java.")
+                || className.startsWith("sun.");
+    }
+
     //XXX no longer needed
 //    /**
 //     * Lookup regular method for a synthetic one in the method's declaring class type-hierarchy.
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/commons/ClassExtensions.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/commons/ClassExtensions.java
index 9662b7861c..45f7abc528 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/commons/ClassExtensions.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/commons/ClassExtensions.java
@@ -88,12 +88,6 @@ public final class ClassExtensions {
         return Modifier.isAbstract(extendee.getModifiers());
     }
 
-    public static boolean isJavaClass(final Class<?> extendee) {
-        final String className = extendee.getName();
-        return className.startsWith(ClassUtil.JAVA_CLASS_PREFIX) ||
-                extendee.getName().startsWith("sun.");
-    }
-
     static Class<?> implementingClassOrNull(final Class<?> extendee, final Class<?> requiredClass, final Class<?> constructorParamType) {
         if (extendee == null) {
             return null;
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/commons/ClassUtil.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/commons/ClassUtil.java
index 42d4204427..56094c1b44 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/commons/ClassUtil.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/commons/ClassUtil.java
@@ -31,8 +31,6 @@ import lombok.experimental.UtilityClass;
 @UtilityClass
 public final class ClassUtil {
 
-    final String JAVA_CLASS_PREFIX = "java.";
-
     private final Map<String, Class<?>> primitiveByName = Map.of(
             void.class.getName(), void.class,
             boolean.class.getName(), boolean.class,
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/ignore/javalang/RemoveMethodsFacetFactory.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/ignore/javalang/RemoveMethodsFacetFactory.java
index 3407a9d829..4acb91022f 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/ignore/javalang/RemoveMethodsFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/ignore/javalang/RemoveMethodsFacetFactory.java
@@ -27,7 +27,6 @@ import org.apache.causeway.commons.internal._Constants;
 import org.apache.causeway.commons.internal.collections._Lists;
 import org.apache.causeway.commons.internal.reflection._Annotations;
 import org.apache.causeway.commons.internal.reflection._Reflect;
-import org.apache.causeway.core.metamodel.commons.ClassExtensions;
 import org.apache.causeway.core.metamodel.context.MetaModelContext;
 import org.apache.causeway.core.metamodel.facetapi.Facet;
 import org.apache.causeway.core.metamodel.facetapi.FeatureType;
@@ -132,7 +131,7 @@ public class RemoveMethodsFacetFactory extends FacetFactoryAbstract {
             return;
         }
 
-        if (!ClassExtensions.isJavaClass(type)) {
+        if (!_Reflect.isJavaApiClass(type)) {
             removeSuperclassMethods(type.getSuperclass(), processClassContext);
             return;
         }
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/support/ObjectSupportFacetFactory.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/support/ObjectSupportFacetFactory.java
index 1c5e8597b8..72f83f1009 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/support/ObjectSupportFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/support/ObjectSupportFacetFactory.java
@@ -122,7 +122,6 @@ extends MethodPrefixBasedFacetFactoryAbstract {
             addFacetIfPresent(TitleFacetFromToStringMethod
                     .create(method, processClassContext.getFacetHolder()));
         });
-
     }
 
     private void processObjectSupport(
@@ -130,7 +129,6 @@ extends MethodPrefixBasedFacetFactoryAbstract {
             final ObjectSupportMethod objectSupportMethodEnum,
             final BiFunction<Method, FacetHolder, Optional<? extends Facet>> ojectSupportFacetConstructor) {
 
-
         MethodFinder
         .objectSupport(
                 processClassContext.getCls(),
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/title/methods/TitleFacetFromToStringMethod.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/title/methods/TitleFacetFromToStringMethod.java
index 0abe6045f0..fca18f6279 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/title/methods/TitleFacetFromToStringMethod.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/title/methods/TitleFacetFromToStringMethod.java
@@ -24,7 +24,7 @@ import java.util.function.BiConsumer;
 
 import org.springframework.lang.Nullable;
 
-import org.apache.causeway.core.metamodel.commons.ClassExtensions;
+import org.apache.causeway.commons.internal.reflection._Reflect;
 import org.apache.causeway.core.metamodel.facetapi.FacetHolder;
 import org.apache.causeway.core.metamodel.facets.HasImperativeAspect;
 import org.apache.causeway.core.metamodel.facets.ImperativeAspect;
@@ -46,7 +46,7 @@ implements HasImperativeAspect {
             final FacetHolder holder) {
 
         return Optional.ofNullable(methodIfAny)
-        .filter(method->!ClassExtensions.isJavaClass(method.getDeclaringClass()))
+        .filter(method->!_Reflect.isJavaApiClass(method.getDeclaringClass()))
         .map(method->
             new TitleFacetFromToStringMethod(
                     ImperativeAspect.singleRegularMethod(method, Intent.UI_HINT),
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/methods/MethodFinderPAT.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/methods/MethodFinderPAT.java
index 920cfca2af..77bef5b2e9 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/methods/MethodFinderPAT.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/methods/MethodFinderPAT.java
@@ -27,7 +27,7 @@ import org.springframework.util.ClassUtils;
 
 import org.apache.causeway.commons.collections.Can;
 import org.apache.causeway.commons.internal.reflection._ClassCache;
-import org.apache.causeway.core.metamodel.commons.ClassExtensions;
+import org.apache.causeway.commons.internal.reflection._Reflect;
 import org.apache.causeway.core.metamodel.commons.MethodUtil;
 
 import lombok.NonNull;
@@ -73,7 +73,7 @@ public final class MethodFinderPAT {
 
         // just an optimization, not strictly required
         if(ClassUtils.isPrimitiveOrWrapper(patCandidate)
-                || ClassExtensions.isJavaClass(patCandidate)) {
+                || _Reflect.isJavaApiClass(patCandidate)) {
             return Optional.empty();
         }
 
diff --git a/core/metamodel/src/test/java/org/apache/causeway/core/metamodel/facets/object/ident/title/TitleFacetViaMethodsFactoryTest.java b/core/metamodel/src/test/java/org/apache/causeway/core/metamodel/facets/object/ident/title/TitleFacetViaMethodsFactoryTest.java
index c49276a169..3b42311bef 100644
--- a/core/metamodel/src/test/java/org/apache/causeway/core/metamodel/facets/object/ident/title/TitleFacetViaMethodsFactoryTest.java
+++ b/core/metamodel/src/test/java/org/apache/causeway/core/metamodel/facets/object/ident/title/TitleFacetViaMethodsFactoryTest.java
@@ -68,7 +68,7 @@ extends ObjectSupportFacetFactoryTestAbstract {
             assertTrue(facet instanceof TitleFacetFromToStringMethod);
             val titleFacetViaTitleMethod = (TitleFacetFromToStringMethod) facet;
             assertMethodEqualsFirstIn(toStringMethod, titleFacetViaTitleMethod);
-            assertMethodWasRemoved(toStringMethod);
+            assertMethodWasRemoved(toStringMethod); // no longer part of class cache methods
         });
     }