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 2018/12/27 21:09:06 UTC
[isis] 01/02: ISIS-2054: simplify type hierarchy traversal when
including interfaces
This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch 2033-IoC
in repository https://gitbox.apache.org/repos/asf/isis.git
commit 77de83314f1dbd64f1615237f535b18c988c5378
Author: andi-huber <ah...@apache.org>
AuthorDate: Thu Dec 27 21:40:47 2018 +0100
ISIS-2054: simplify type hierarchy traversal when including interfaces
Task-Url: https://issues.apache.org/jira/browse/ISIS-2054
---
.../isis/commons/internal/reflection/_Reflect.java | 45 ++-----
.../commons/internal/reflection/ReflectTest.java | 132 +++++++++++++++++++++
2 files changed, 141 insertions(+), 36 deletions(-)
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/reflection/_Reflect.java b/core/commons/src/main/java/org/apache/isis/commons/internal/reflection/_Reflect.java
index 638fdef..f8db6a5 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/internal/reflection/_Reflect.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/reflection/_Reflect.java
@@ -146,7 +146,7 @@ public final class _Reflect {
@Nullable Class<?> type,
final boolean ignoreAccess) {
- return streamTypeHierarchyAndInterfaces(type)
+ return streamTypeHierarchy(type, /*includeInterfaces*/ false) // interfaces don't have fields
.filter(Object.class::equals) // do not process Object class.
.flatMap(t->streamFields(t, ignoreAccess));
}
@@ -182,7 +182,7 @@ public final class _Reflect {
final boolean ignoreAccess
) {
- return streamTypeHierarchyAndInterfaces(type)
+ return streamTypeHierarchy(type, /*includeInterfaces*/ true)
.filter(t->!t.equals(Object.class)) // do not process Object class.
.flatMap(t->streamMethods(t, ignoreAccess));
}
@@ -192,9 +192,10 @@ public final class _Reflect {
/**
* Stream all types of given {@code type}, up the super class hierarchy starting with self
* @param type (nullable)
+ * @param includeInterfaces - whether to include all interfaces implemented by given {@code type}.
* @return non-null
*/
- public static Stream<Class<?>> streamTypeHierarchy(@Nullable Class<?> type) {
+ public static Stream<Class<?>> streamTypeHierarchy(@Nullable Class<?> type, boolean includeInterfaces) {
// https://stackoverflow.com/questions/40240450/java8-streaming-a-class-hierarchy?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa
// Java 9+ will allow ...
@@ -208,31 +209,15 @@ public final class _Reflect {
public boolean tryAdvance(Consumer<? super Class<?>> action) {
if(current == null) return false;
action.accept(current);
+ if(includeInterfaces) {
+ for(Class<?> subIface : current.getInterfaces()) {
+ recur(subIface, action);
+ }
+ }
current = current.getSuperclass();
return true;
}
- }, false);
- }
-
- /**
- * Stream all interfaces implemented by given {@code type}.
- * @param type (nullable)
- * @return non-null
- */
- public static Stream<Class<?>> streamAllInterfaces(@Nullable Class<?> type) {
- return StreamSupport.stream(
- new Spliterators.AbstractSpliterator<Class<?>>(Long.MAX_VALUE,
- Spliterator.ORDERED|Spliterator.IMMUTABLE|Spliterator.NONNULL) {
- Class<?> current = type;
- @Override
- public boolean tryAdvance(Consumer<? super Class<?>> action) {
- if(current == null) return false;
- recur(current, action);
- current = current.getSuperclass();
- return true;
- }
-
private void recur(Class<?> iface, Consumer<? super Class<?>> action) {
action.accept(iface);
for(Class<?> subIface : iface.getInterfaces()) {
@@ -243,18 +228,6 @@ public final class _Reflect {
}, false);
}
- /**
- * Stream all types of given {@code type}, up the super class hierarchy starting with self,
- * then append all interfaces of given {@code type}.
- * @param type (nullable)
- * @return non-null
- */
- public static Stream<Class<?>> streamTypeHierarchyAndInterfaces(
- @Nullable Class<?> type) {
-
- return Stream.concat(streamTypeHierarchy(type), streamAllInterfaces(type));
- }
-
// -- ANNOTATIONS
/**
diff --git a/core/detached-tests/src/test/java/org/apache/isis/commons/internal/reflection/ReflectTest.java b/core/detached-tests/src/test/java/org/apache/isis/commons/internal/reflection/ReflectTest.java
new file mode 100644
index 0000000..eed91e9
--- /dev/null
+++ b/core/detached-tests/src/test/java/org/apache/isis/commons/internal/reflection/ReflectTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.Method;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import javax.xml.bind.JAXBContext;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.services.jaxb.JaxbServiceDefault;
+import org.apache.isis.core.metamodel.services.user.UserServiceDefault;
+
+//TODO we are using real word classes from the framework, we could instead isolate these tests
+// if we provide some custom classes for hierarchy traversal here (could be nested);
+// then move this test to the 'commons' module, where it belongs
+class ReflectTest {
+
+ @Test
+ void typeHierarchy() {
+
+ Class<?> type = UserServiceDefault.SudoServiceSpi.class;
+
+ String typeListLiteral = _Reflect.streamTypeHierarchy(type, false)
+ .map(t->t.getName())
+ .collect(Collectors.joining(", "));
+
+ Assertions.assertEquals(""
+ + "org.apache.isis.core.metamodel.services.user.UserServiceDefault$SudoServiceSpi, "
+ + "java.lang.Object",
+ typeListLiteral);
+
+ }
+
+ @Test
+ void typeHierarchyAndInterfaces() {
+
+ Class<?> type = UserServiceDefault.SudoServiceSpi.class;
+
+ String typeListLiteral = _Reflect.streamTypeHierarchy(type, true)
+ .map(t->t.getName())
+ .collect(Collectors.joining(", "));
+
+ Assertions.assertEquals(
+ "org.apache.isis.core.metamodel.services.user.UserServiceDefault$SudoServiceSpi, "
+ + "org.apache.isis.applib.services.sudo.SudoService$Spi, "
+ + "java.lang.Object",
+ typeListLiteral);
+
+ }
+
+ @Test
+ void allMethods() {
+
+ Class<?> type = UserServiceDefault.SudoServiceSpi.class;
+
+ String typeListLiteral = _Reflect.streamAllMethods(type, true)
+ .map(m->m.toString())
+ .collect(Collectors.joining(", "));
+
+ Assertions.assertEquals(
+ "public void org.apache.isis.core.metamodel.services.user.UserServiceDefault$SudoServiceSpi.runAs(java.lang.String,java.util.List), "
+ + "public void org.apache.isis.core.metamodel.services.user.UserServiceDefault$SudoServiceSpi.releaseRunAs(), "
+ + "public abstract void org.apache.isis.applib.services.sudo.SudoService$Spi.runAs(java.lang.String,java.util.List), "
+ + "public abstract void org.apache.isis.applib.services.sudo.SudoService$Spi.releaseRunAs()",
+ typeListLiteral);
+
+ }
+
+ @Test
+ void annotationLookup() throws NoSuchMethodException, SecurityException {
+
+ Class<?> type = UserServiceDefault.SudoServiceSpi.class;
+ Method method = type.getMethod("runAs", new Class[] {String.class, List.class});
+
+ Programmatic annot = _Reflect.getAnnotation(method, Programmatic.class, true, true);
+
+ Assertions.assertNotNull(annot);
+ }
+
+ @Test
+ void typeHierarchyAndInterfaces2() {
+
+ Class<?> type = JaxbServiceDefault.class;
+
+ String typeListLiteral = _Reflect.streamTypeHierarchy(type, true)
+ .map(t->t.getName())
+ .collect(Collectors.joining(", "));
+
+ Assertions.assertEquals(
+ "org.apache.isis.applib.services.jaxb.JaxbServiceDefault, "
+ + "org.apache.isis.applib.services.jaxb.JaxbService$Simple, "
+ + "org.apache.isis.applib.services.jaxb.JaxbService, "
+ + "java.lang.Object",
+ typeListLiteral);
+
+ }
+
+
+ @Test
+ void annotationLookup2() throws NoSuchMethodException, SecurityException {
+
+ Class<?> type = JaxbServiceDefault.class;
+ Method method = type.getMethod("fromXml", new Class[] {JAXBContext.class, String.class, Map.class});
+
+ Programmatic annot = _Reflect.getAnnotation(method, Programmatic.class, true, true);
+
+ Assertions.assertNotNull(annot);
+
+ }
+
+}