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/05/04 07:15:00 UTC
[isis] branch master updated: ISIS-2642: introduce _Generics
utility to consolidate type argument logic
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 a5c3884 ISIS-2642: introduce _Generics utility to consolidate type argument logic
a5c3884 is described below
commit a5c38849d27bac9e8fbaece883fda553e48798fb
Author: Andi Huber <ah...@apache.org>
AuthorDate: Tue May 4 09:14:43 2021 +0200
ISIS-2642: introduce _Generics utility to consolidate type argument
logic
---
.../commons/internal/reflection/_Generics.java | 153 +++++++++++++++++++++
.../specloader/specimpl/FacetedMethodsBuilder.java | 6 +
.../specloader/typeextract/TypeExtractor.java | 45 +-----
.../DomainModelTest_usingGoodDomain.java | 19 ++-
.../model/good/ElementTypeInterface.java | 3 -
.../testdomain/model/good/ProperElementTypeVm.java | 8 +-
6 files changed, 186 insertions(+), 48 deletions(-)
diff --git a/commons/src/main/java/org/apache/isis/commons/internal/reflection/_Generics.java b/commons/src/main/java/org/apache/isis/commons/internal/reflection/_Generics.java
new file mode 100644
index 0000000..91813e3
--- /dev/null
+++ b/commons/src/main/java/org/apache/isis/commons/internal/reflection/_Generics.java
@@ -0,0 +1,153 @@
+/*
+ * 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.commons.internal.reflection;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.WildcardType;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+import javax.annotation.Nullable;
+
+import org.apache.isis.commons.internal.functions._Predicates;
+
+import lombok.NonNull;
+import lombok.val;
+
+/**
+ * <h1>- internal use only -</h1>
+ * <p>
+ * <b>WARNING</b>: Do <b>NOT</b> use any of the classes provided by this package! <br/>
+ * These may be changed or removed without notice!
+ * </p>
+ * @since 2.0
+ */
+public final class _Generics {
+
+ /**
+ * Visits given {@code genericType} for its actual type arguments
+ * and calls back {@code onTypeArgument} on each type argument found.
+ * @param genericType
+ * @param onTypeArgument
+ */
+ public static void visitGenericTypeArgumentsOf(
+ final @NonNull Type genericType,
+ final @NonNull Consumer<Class<?>> onTypeArgument) {
+ visitGenericTypeArgumentsOf(genericType, _Predicates.alwaysTrue(), onTypeArgument);
+ }
+
+ /**
+ * Visits given {@code genericTypes} for their actual type arguments
+ * and calls back {@code onTypeArgument} on each type argument found.
+ * @param genericTypes
+ * @param onTypeArgument
+ */
+ public static void visitGenericTypeArgumentsOf(
+ final @Nullable Type[] genericTypes,
+ final @NonNull Consumer<Class<?>> onTypeArgument) {
+ visitGenericTypeArgumentsOf(genericTypes, _Predicates.alwaysTrue(), onTypeArgument);
+ }
+
+ /**
+ * Visits given {@code genericType} for its actual type arguments
+ * and calls back {@code onTypeArgument} on each type argument found, that passes
+ * given {@code typeArgumentFilter}.
+ * @param genericType
+ * @param typeArgumentFilter
+ * @param onTypeArgument
+ */
+ public static void visitGenericTypeArgumentsOf(
+ final @NonNull Type genericType,
+ final @NonNull Predicate<Class<?>> typeArgumentFilter,
+ final @NonNull Consumer<Class<?>> onTypeArgument) {
+
+ if (genericType instanceof ParameterizedType) {
+ for (val type : ((ParameterizedType) genericType).getActualTypeArguments()) {
+ visitTypeArgument((Class<?>) type, typeArgumentFilter, onTypeArgument);
+ }
+ }
+ }
+
+ /**
+ * Visits given {@code genericTypes} for their actual type arguments
+ * and calls back {@code onTypeArgument} on each type argument found, that passes
+ * given {@code typeArgumentFilter}.
+ * @param genericTypes
+ * @param typeArgumentFilter
+ * @param onTypeArgument
+ */
+ public static void visitGenericTypeArgumentsOf(
+ final @Nullable Type[] genericTypes,
+ final @NonNull Predicate<Class<?>> typeArgumentFilter,
+ final @NonNull Consumer<Class<?>> onTypeArgument) {
+
+ if(genericTypes==null) {
+ return; // no-op
+ }
+ for (val genericType : genericTypes) {
+ visitGenericTypeArgumentsOf(genericType, typeArgumentFilter, onTypeArgument);
+ }
+ }
+
+ // -- HELPER
+
+ private static void visitTypeArgument(
+ final Type type,
+ final Predicate<Class<?>> filter,
+ final Consumer<Class<?>> onClass) {
+
+ if (type instanceof WildcardType) {
+ acceptWildcardType((WildcardType) type, filter, onClass);
+ }
+ if (type instanceof Class) {
+ acceptNonWildcardType((Class<?>) type, filter, onClass);
+ }
+ // unexpected code reach
+ }
+
+ private static void acceptWildcardType(
+ final WildcardType wildcardType,
+ final Predicate<Class<?>> filter,
+ final Consumer<Class<?>> onClass) {
+
+ for (val lower : wildcardType.getLowerBounds()) {
+ if (lower instanceof Class) {
+ visitTypeArgument((Class<?>) lower, filter, onClass);
+ }
+ }
+ for (val upper : wildcardType.getUpperBounds()) {
+ if (upper instanceof Class) {
+ visitTypeArgument((Class<?>) upper, filter, onClass);
+ }
+ }
+ }
+
+ private static void acceptNonWildcardType(
+ final Class<?> cls,
+ final Predicate<Class<?>> filter,
+ final Consumer<Class<?>> onClass) {
+
+ if(filter.test(cls)) {
+ onClass.accept(cls);
+ }
+
+ }
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java
index f5959e4..34a63d7 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java
@@ -38,6 +38,7 @@ import org.apache.isis.applib.exceptions.unrecoverable.MetaModelException;
import org.apache.isis.commons.internal.base._NullSafe;
import org.apache.isis.commons.internal.collections._Lists;
import org.apache.isis.commons.internal.collections._Sets;
+import org.apache.isis.commons.internal.debug._Probe;
import org.apache.isis.commons.internal.reflection._Annotations;
import org.apache.isis.core.metamodel.commons.CanBeVoid;
import org.apache.isis.core.metamodel.commons.MethodUtil;
@@ -228,6 +229,11 @@ public class FacetedMethodsBuilder {
TypeExtractor.streamMethodReturn(associationCandidateMethods)
.filter(typeToLoad->typeToLoad!=introspectedClass)
+ .peek(typeToLoad->{
+ if(getClassName().contains("ProperElementTypeVm")) {
+ _Probe.errOut("load %s", typeToLoad);
+ }
+ })
.forEach(typeToLoad->specLoader.loadSpecification(typeToLoad, IntrospectionState.TYPE_INTROSPECTED));
// now create FacetedMethods for collections and for properties
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/typeextract/TypeExtractor.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/typeextract/TypeExtractor.java
index 2e7d96d..32922dc 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/typeextract/TypeExtractor.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/typeextract/TypeExtractor.java
@@ -19,13 +19,11 @@
package org.apache.isis.core.metamodel.specloader.typeextract;
import java.lang.reflect.Method;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.lang.reflect.WildcardType;
import java.util.function.Consumer;
import java.util.stream.Stream;
import org.apache.isis.commons.internal.collections._Sets;
+import org.apache.isis.commons.internal.reflection._Generics;
import lombok.val;
import lombok.experimental.UtilityClass;
@@ -62,7 +60,7 @@ public class TypeExtractor {
continue;
}
acceptNonVoid(set::add, method.getParameterTypes());
- visitParameterizedTypes(set::add, method.getGenericParameterTypes());
+ _Generics.visitGenericTypeArgumentsOf(method.getGenericParameterTypes(), set::add);
}
return set.stream();
@@ -92,7 +90,7 @@ public class TypeExtractor {
continue;
}
acceptNonVoid(set::add, method.getReturnType());
- visitParameterizedTypes(set::add, method.getGenericReturnType());
+ _Generics.visitGenericTypeArgumentsOf(method.getGenericReturnType(), set::add);
}
return set.stream();
@@ -108,7 +106,7 @@ public class TypeExtractor {
continue;
}
acceptNonVoid(set::add, method.getReturnType());
- visitParameterizedTypes(set::add, method.getGenericReturnType());
+ _Generics.visitGenericTypeArgumentsOf(method.getGenericReturnType(), set::add);
}
return set.stream();
@@ -116,39 +114,6 @@ public class TypeExtractor {
// -- HELPER
- private static void visitParameterizedTypes(
- final Consumer<Class<?>> onClass,
- final Type... genericTypes) {
-
- for (val genericType : genericTypes) {
- if (genericType instanceof ParameterizedType) {
- final ParameterizedType parameterizedType = (ParameterizedType) genericType;
- final Type[] typeArguments = parameterizedType.getActualTypeArguments();
- for (val type : typeArguments) {
- if (type instanceof Class) {
- acceptNonVoid(onClass, (Class<?>) type);
- }
- if (type instanceof WildcardType) {
- acceptWildcardType(onClass, (WildcardType) type);
- }
- }
- }
- }
- }
-
- private static void acceptWildcardType(Consumer<Class<?>> onClass, WildcardType wildcardType) {
- for (val lower : wildcardType.getLowerBounds()) {
- if (lower instanceof Class) {
- acceptNonVoid(onClass, (Class<?>) lower);
- }
- }
- for (val upper : wildcardType.getUpperBounds()) {
- if (upper instanceof Class) {
- acceptNonVoid(onClass, (Class<?>) upper);
- }
- }
- }
-
private static void acceptNonVoid(
final Consumer<Class<?>> onClass,
final Class<?>... classes) {
@@ -161,6 +126,4 @@ public class TypeExtractor {
}
}
-
-
}
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 2f7dcd2..34934b1 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
@@ -292,9 +292,22 @@ class DomainModelTest_usingGoodDomain {
val interfaceColl = vmSpec.getCollectionElseFail("interfaceColl");
val interfaceCollSpec = interfaceColl.getSpecification();
- //FIXME yet test fails
- //assertEquals(ElementTypeInterface.class, interfaceCollSpec.getCorrespondingClass());
- //assertEquals(BeanSort.ABSTRACT, interfaceCollSpec.getBeanSort());
+ assertEquals(ElementTypeInterface.class, interfaceCollSpec.getCorrespondingClass());
+ assertEquals(BeanSort.ABSTRACT, interfaceCollSpec.getBeanSort());
+
+ // when using generic type wild-cards
+
+ val concreteColl2 = vmSpec.getCollectionElseFail("concreteColl2");
+ val concreteCollSpec2 = concreteColl2.getSpecification();
+
+ assertEquals(ElementTypeConcrete.class, concreteCollSpec2.getCorrespondingClass());
+ assertEquals(BeanSort.VIEW_MODEL, concreteCollSpec2.getBeanSort());
+
+ val interfaceColl2 = vmSpec.getCollectionElseFail("interfaceColl2");
+ val interfaceCollSpec2 = interfaceColl2.getSpecification();
+
+ assertEquals(ElementTypeInterface.class, interfaceCollSpec2.getCorrespondingClass());
+ assertEquals(BeanSort.ABSTRACT, interfaceCollSpec2.getBeanSort());
// TODO for the abstract case, we also want to see any members and the title-facet
}
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ElementTypeInterface.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ElementTypeInterface.java
index 12a059a..8d0d788 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ElementTypeInterface.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ElementTypeInterface.java
@@ -18,9 +18,6 @@
*/
package org.apache.isis.testdomain.model.good;
-import org.apache.isis.applib.annotation.DomainObject;
-
-@DomainObject(objectType = "isis.testdomain.ElementTypeInterface")
public interface ElementTypeInterface {
default String title() {
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperElementTypeVm.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperElementTypeVm.java
index b92621c..afd6990 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperElementTypeVm.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/model/good/ProperElementTypeVm.java
@@ -31,9 +31,15 @@ import lombok.Setter;
public class ProperElementTypeVm {
@Collection
- @Getter @Setter private List<? extends ElementTypeInterface> interfaceColl;
+ @Getter @Setter private List<ElementTypeInterface> interfaceColl;
@Collection
@Getter @Setter private List<ElementTypeConcrete> concreteColl;
+ @Collection
+ @Getter @Setter private List<? extends ElementTypeInterface> interfaceColl2;
+
+ @Collection
+ @Getter @Setter private List<? extends ElementTypeConcrete> concreteColl2;
+
}