Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to retrieve involved raw types of JavaType and JavaMember #1116

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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