Skip to content

Commit

Permalink
Allow to retrieve involved raw types of JavaType and JavaMember (#…
Browse files Browse the repository at this point in the history
…1116)

add `{JavaType/JavaMember}.getAllInvolvedRawTypes()`

Resolves: #723
  • Loading branch information
codecholeric authored Nov 5, 2023
2 parents e68956d + ea320d8 commit d6030be
Show file tree
Hide file tree
Showing 15 changed files with 245 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,11 @@ public JavaClass toErasure() {
return this;
}

@Override
public Set<JavaClass> getAllInvolvedRawTypes() {
return ImmutableSet.of(getBaseComponentType());
}

@PublicAPI(usage = ACCESS)
public Optional<JavaClass> getRawSuperclass() {
return superclass.getRaw();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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<JavaClass> 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<JavaFieldAccess> getFieldAccesses() {
return fieldAccesses;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<JavaClass> getAllInvolvedRawTypes() {
return getType().getAllInvolvedRawTypes();
}

@Override
@PublicAPI(usage = ACCESS)
public Set<JavaFieldAccess> getAccessesToSelf() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*/
package com.tngtech.archunit.core.domain;

import java.util.Set;

import com.tngtech.archunit.PublicAPI;

import static com.google.common.base.Preconditions.checkNotNull;
Expand Down Expand Up @@ -67,6 +69,11 @@ public JavaClass toErasure() {
return erasure;
}

@Override
public Set<JavaClass> getAllInvolvedRawTypes() {
return this.componentType.getAllInvolvedRawTypes();
}

@Override
public String toString() {
return getClass().getSimpleName() + '{' + getName() + '}';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<JavaClass> getAllInvolvedRawTypes();

@Override
@PublicAPI(usage = ACCESS)
public Set<? extends JavaAnnotation<? extends JavaMember>> getAnnotations() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package com.tngtech.archunit.core.domain;

import java.lang.reflect.Type;
import java.util.Set;

import com.tngtech.archunit.PublicAPI;
import com.tngtech.archunit.base.ChainableFunction;
Expand Down Expand Up @@ -56,6 +57,33 @@ public interface JavaType extends HasName {
@PublicAPI(usage = ACCESS)
JavaClass toErasure();

/**
* Returns the set of all raw types that are involved in this type.
* If this type is a {@link JavaClass}, then this method trivially returns only the class itself.
* If this type is a {@link JavaParameterizedType}, {@link JavaTypeVariable}, {@link JavaWildcardType}, etc.,
* then this method returns all raw types involved in type arguments and upper and lower bounds recursively.
* If this type is an array type, then this method returns all raw types involved in the component type of the array type.
* <br><br>
* Examples:<br>
* For the parameterized type
* <pre><code>
* List&lt;String&gt;</code></pre>
* the result would be the {@link JavaClass classes} <code>[List, String]</code>.<br>
* For the parameterized type
* <pre><code>
* Map&lt;? extends Serializable, List&lt;? super Integer[]&gt;&gt;</code></pre>
* the result would be <code>[Map, Serializable, List, Integer]</code>.<br>
* And for the type variable
* <pre><code>
* T extends List&lt;? super Integer&gt;</code></pre>
* the result would be <code>[List, Integer]</code>.<br>
* Thus, this method offers a quick way to determine all types a (possibly complex) type depends on.
*
* @return All raw types involved in this {@link JavaType}
*/
@PublicAPI(usage = ACCESS)
Set<JavaClass> getAllInvolvedRawTypes();

/**
* Predefined {@link ChainableFunction functions} to transform {@link JavaType}.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import java.lang.reflect.TypeVariable;
import java.util.List;
import java.util.Set;

import com.tngtech.archunit.PublicAPI;
import com.tngtech.archunit.base.HasDescription;
Expand All @@ -28,6 +29,7 @@
import static com.tngtech.archunit.core.domain.properties.HasName.Functions.GET_NAME;
import static java.util.Collections.emptyList;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toSet;

/**
* Represents a type variable used by generic types and members.<br>
Expand Down Expand Up @@ -119,6 +121,14 @@ public JavaClass toErasure() {
return erasure;
}

@Override
public Set<JavaClass> getAllInvolvedRawTypes() {
return this.upperBounds.stream()
.map(JavaType::getAllInvolvedRawTypes)
.flatMap(Set::stream)
.collect(toSet());
}

@Override
public String toString() {
String bounds = printExtendsClause() ? " extends " + joinTypeNames(upperBounds) : "";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

import java.lang.reflect.WildcardType;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;

import com.tngtech.archunit.PublicAPI;
import com.tngtech.archunit.core.domain.properties.HasUpperBounds;
Expand All @@ -25,6 +27,7 @@
import static com.tngtech.archunit.PublicAPI.Usage.ACCESS;
import static com.tngtech.archunit.core.domain.Formatters.ensureCanonicalArrayTypeName;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toSet;

/**
* Represents a wildcard type in a type signature (compare the JLS).
Expand Down Expand Up @@ -95,6 +98,14 @@ public JavaClass toErasure() {
return erasure;
}

@Override
public Set<JavaClass> getAllInvolvedRawTypes() {
return Stream.concat(upperBounds.stream(), lowerBounds.stream())
.map(JavaType::getAllInvolvedRawTypes)
.flatMap(Set::stream)
.collect(toSet());
}

@Override
public String toString() {
return getClass().getSimpleName() + '{' + getName() + '}';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
import static com.tngtech.archunit.core.domain.properties.HasName.Utils.namesOf;
import static java.util.Collections.emptyList;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toSet;

@Internal
@SuppressWarnings("UnusedReturnValue")
Expand Down Expand Up @@ -1216,6 +1217,14 @@ public JavaClass toErasure() {
return type.toErasure();
}

@Override
public Set<JavaClass> getAllInvolvedRawTypes() {
return Stream.concat(
type.getAllInvolvedRawTypes().stream(),
typeArguments.stream().map(JavaType::getAllInvolvedRawTypes).flatMap(Set::stream)
).collect(toSet());
}

@Override
public List<JavaType> getActualTypeArguments() {
return typeArguments;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,28 @@ class SimpleClass {
assertThat(type.toErasure()).isEqualTo(type);
}

@Test
public void get_all_involved_raw_types_returns_only_self_for_non_array_type() {
class SimpleClass {
}

JavaClass clazz = new ClassFileImporter().importClass(SimpleClass.class);

assertThatTypes(clazz.getAllInvolvedRawTypes()).matchExactly(SimpleClass.class);
}

@Test
public void get_all_involved_raw_types_returns_component_type_for_array_type() {
class SimpleClass {
@SuppressWarnings("unused")
SimpleClass[][] field;
}

JavaType arrayType = new ClassFileImporter().importClass(SimpleClass.class).getField("field").getType();

assertThatTypes(arrayType.getAllInvolvedRawTypes()).matchExactly(SimpleClass.class);
}

@Test
public void finds_component_type_chain_of_otherwise_unreferenced_component_type() {
@SuppressWarnings("unused")
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<T extends Collection<? super File> & Serializable> {
@SuppressWarnings("unused")
T method(List<Map<? extends Number, Set<? super String[][]>>> 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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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<? super Map<? extends Serializable, ? super Set<Number[][]>>> field;
}

JavaField field = new ClassFileImporter().importClass(SomeClass.class).getField("field");

assertThatTypes(field.getAllInvolvedRawTypes()).matchInAnyOrder(List.class, Map.class, Serializable.class, Set.class, Number.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import static com.tngtech.archunit.testutil.Assertions.assertThat;
import static com.tngtech.archunit.testutil.Assertions.assertThatType;
import static com.tngtech.archunit.testutil.Assertions.assertThatTypeErasuresOf;
import static com.tngtech.archunit.testutil.Assertions.assertThatTypes;

public class JavaTypeVariableTest {

Expand Down Expand Up @@ -119,6 +120,30 @@ class ClassWithBoundTypeParameterWithGenericArrayBounds<A, B extends String, C e
assertThatType(getTypeArgumentOfFirstBound(typeParameters.get(5)).toErasure()).matches(List[][][].class);
}

@Test
public void all_involved_raw_types() {
class SampleClass<T extends String & List<Serializable[]>> {
@SuppressWarnings("unused")
private T field;
}

JavaTypeVariable<?> typeVariable = (JavaTypeVariable<?>) new ClassFileImporter().importClass(SampleClass.class).getField("field").getType();

assertThatTypes(typeVariable.getAllInvolvedRawTypes()).matchInAnyOrder(String.class, List.class, Serializable.class);
}

@Test
public void all_involved_raw_types_of_generic_array() {
class SampleClass<T extends String & List<Serializable>> {
@SuppressWarnings("unused")
private T[][] field;
}

JavaGenericArrayType typeVariable = (JavaGenericArrayType) new ClassFileImporter().importClass(SampleClass.class).getField("field").getType();

assertThatTypes(typeVariable.getAllInvolvedRawTypes()).matchInAnyOrder(String.class, List.class, Serializable.class);
}

@Test
public void toString_unbounded() {
@SuppressWarnings("unused")
Expand Down
Loading

0 comments on commit d6030be

Please sign in to comment.