From ea320d83635615c8074e8b89d4410707b9e7b167 Mon Sep 17 00:00:00 2001 From: Leonard Husmann Date: Mon, 29 May 2023 21:31:14 +0200 Subject: [PATCH] add `JavaMember.getAllInvolvedRawTypes()` Convenience method to find all `JavaClass`es involved in any member's signature. For a field these are only the raw types involved in the field type, for methods and constructors it's the union of all raw types involved in parameter types, return types and type parameters. Issue: #723 Signed-off-by: Leonard Husmann Signed-off-by: Peter Gafert --- .../archunit/core/domain/JavaCodeUnit.java | 18 +++++++++++++ .../archunit/core/domain/JavaField.java | 9 +++++++ .../archunit/core/domain/JavaMember.java | 9 +++++++ .../core/domain/JavaCodeUnitTest.java | 19 ++++++++++++++ .../archunit/core/domain/JavaFieldTest.java | 25 +++++++++++++++++++ 5 files changed, 80 insertions(+) create mode 100644 archunit/src/test/java/com/tngtech/archunit/core/domain/JavaFieldTest.java diff --git a/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaCodeUnit.java b/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaCodeUnit.java index efe43febbb..f0473a1990 100644 --- a/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaCodeUnit.java +++ b/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaCodeUnit.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.stream.Stream; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; @@ -43,6 +44,7 @@ import static com.tngtech.archunit.PublicAPI.Usage.ACCESS; import static com.tngtech.archunit.core.domain.Formatters.formatMethod; import static com.tngtech.archunit.core.domain.properties.HasName.Utils.namesOf; +import static java.util.stream.Collectors.toSet; /** * Represents a unit of code containing accesses to other units of code. A unit of code can be @@ -169,6 +171,22 @@ public JavaClass getRawReturnType() { return returnType.getRaw(); } + /** + * @return All raw types involved in this code unit's signature, + * which is the union of all raw types involved in the {@link #getReturnType() return type}, + * the {@link #getParameterTypes() parameter types} and the {@link #getTypeParameters() type parameters} of this code unit. + * For a definition of "all raw types involved" consult {@link JavaType#getAllInvolvedRawTypes()}. + */ + @Override + @PublicAPI(usage = ACCESS) + public Set getAllInvolvedRawTypes() { + return Stream.of( + Stream.of(this.returnType.get()), + this.parameters.getParameterTypes().stream(), + this.typeParameters.stream() + ).flatMap(s -> s).map(JavaType::getAllInvolvedRawTypes).flatMap(Set::stream).collect(toSet()); + } + @PublicAPI(usage = ACCESS) public Set getFieldAccesses() { return fieldAccesses; diff --git a/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaField.java b/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaField.java index 335f0e93b5..2022429a21 100644 --- a/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaField.java +++ b/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaField.java @@ -62,6 +62,15 @@ public JavaClass getRawType() { return type.toErasure(); } + /** + * @return All raw types involved in this field's signature, which is equivalent to {@link #getType()}.{@link JavaType#getAllInvolvedRawTypes() getAllInvolvedRawTypes()}. + */ + @Override + @PublicAPI(usage = ACCESS) + public Set getAllInvolvedRawTypes() { + return getType().getAllInvolvedRawTypes(); + } + @Override @PublicAPI(usage = ACCESS) public Set getAccessesToSelf() { diff --git a/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaMember.java b/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaMember.java index ae0213b2f6..4b7f0e57b1 100644 --- a/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaMember.java +++ b/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaMember.java @@ -63,6 +63,15 @@ public abstract class JavaMember implements this.modifiers = checkNotNull(builder.getModifiers()); } + /** + * Similar to {@link JavaType#getAllInvolvedRawTypes()}, this method returns all raw types involved in this {@link JavaMember member's} signature. + * For more concrete details refer to {@link JavaField#getAllInvolvedRawTypes()} and {@link JavaCodeUnit#getAllInvolvedRawTypes()}. + * + * @return All raw types involved in the signature of this member + */ + @PublicAPI(usage = ACCESS) + public abstract Set getAllInvolvedRawTypes(); + @Override @PublicAPI(usage = ACCESS) public Set> getAnnotations() { diff --git a/archunit/src/test/java/com/tngtech/archunit/core/domain/JavaCodeUnitTest.java b/archunit/src/test/java/com/tngtech/archunit/core/domain/JavaCodeUnitTest.java index e2b61efd45..726c56230b 100644 --- a/archunit/src/test/java/com/tngtech/archunit/core/domain/JavaCodeUnitTest.java +++ b/archunit/src/test/java/com/tngtech/archunit/core/domain/JavaCodeUnitTest.java @@ -1,8 +1,11 @@ package com.tngtech.archunit.core.domain; import java.io.File; +import java.io.Serializable; +import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Set; import com.google.common.collect.ImmutableList; import com.tngtech.archunit.core.importer.ClassFileImporter; @@ -20,12 +23,28 @@ import static com.tngtech.archunit.core.domain.properties.HasType.Functions.GET_RAW_TYPE; import static com.tngtech.archunit.testutil.Assertions.assertThat; import static com.tngtech.archunit.testutil.Assertions.assertThatAnnotation; +import static com.tngtech.archunit.testutil.Assertions.assertThatTypes; import static com.tngtech.java.junit.dataprovider.DataProviders.testForEach; import static org.assertj.core.api.Assertions.assertThatThrownBy; @RunWith(DataProviderRunner.class) public class JavaCodeUnitTest { + @Test + public void offers_all_involved_raw_types() { + class SampleClass & Serializable> { + @SuppressWarnings("unused") + T method(List>> input) { + return null; + } + } + + JavaMethod method = new ClassFileImporter().importClass(SampleClass.class).getMethod("method", List.class); + + assertThatTypes(method.getAllInvolvedRawTypes()) + .matchInAnyOrder(Collection.class, File.class, Serializable.class, List.class, Map.class, Number.class, Set.class, String.class); + } + @Test public void offers_all_calls_from_Self() { JavaMethod method = importClassWithContext(ClassAccessingOtherClass.class).getMethod("access", ClassBeingAccessed.class); diff --git a/archunit/src/test/java/com/tngtech/archunit/core/domain/JavaFieldTest.java b/archunit/src/test/java/com/tngtech/archunit/core/domain/JavaFieldTest.java new file mode 100644 index 0000000000..2d93d7e879 --- /dev/null +++ b/archunit/src/test/java/com/tngtech/archunit/core/domain/JavaFieldTest.java @@ -0,0 +1,25 @@ +package com.tngtech.archunit.core.domain; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.tngtech.archunit.core.importer.ClassFileImporter; +import org.junit.Test; + +import static com.tngtech.archunit.testutil.Assertions.assertThatTypes; + +public class JavaFieldTest { + @Test + public void offers_all_involved_raw_types() { + class SomeClass { + @SuppressWarnings("unused") + List>> field; + } + + JavaField field = new ClassFileImporter().importClass(SomeClass.class).getField("field"); + + assertThatTypes(field.getAllInvolvedRawTypes()).matchInAnyOrder(List.class, Map.class, Serializable.class, Set.class, Number.class); + } +} \ No newline at end of file