Skip to content

Add generic type info to JavaClass #398

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

Merged
merged 15 commits into from
Sep 12, 2020
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 @@ -2,7 +2,7 @@

import com.tngtech.archunit.base.DescribedPredicate;
import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.core.domain.JavaType;
import com.tngtech.archunit.core.domain.JavaClassDescriptor;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import com.tngtech.archunit.core.importer.DomainBuilders;
import com.tngtech.archunit.junit.ArchTest;
Expand All @@ -21,15 +21,15 @@ public class ImporterRules {
.should().accessClassesThat(belong_to_the_import_context());

@ArchTest
public static final ArchRule ASM_type_is_only_accessed_within_JavaType_or_JavaTypeImporter =
public static final ArchRule ASM_type_is_only_accessed_within_JavaClassDescriptor_or_JavaClassDescriptorImporter =
noClasses()
.that().resideOutsideOfPackage(THIRDPARTY_PACKAGE_IDENTIFIER)
.and(not(belongToAnyOf(JavaType.class)))
.and().doNotHaveFullyQualifiedName("com.tngtech.archunit.core.importer.JavaTypeImporter")
.and(not(belongToAnyOf(JavaClassDescriptor.class)))
.and().doNotHaveFullyQualifiedName("com.tngtech.archunit.core.importer.JavaClassDescriptorImporter")
.should().dependOnClassesThat().haveNameMatching(".*\\.asm\\..*Type")
.as("org.objectweb.asm.Type should only be accessed within JavaType(Importer)")
.as("org.objectweb.asm.Type should only be accessed within JavaClassDescriptor(Importer)")
.because("org.objectweb.asm.Type handles array types inconsistently (uses the canonical name instead of the class name), "
+ "so the correct behavior is implemented only within JavaType");
+ "so the correct behavior is implemented only within JavaClassDescriptor");

private static DescribedPredicate<JavaClass> belong_to_the_import_context() {
return new DescribedPredicate<JavaClass>("belong to the import context") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import org.mockito.junit.MockitoRule;

import static com.tngtech.archunit.junit.CacheMode.PER_CLASS;
import static com.tngtech.archunit.testutil.Assertions.assertThatClasses;
import static com.tngtech.archunit.testutil.Assertions.assertThatTypes;
import static com.tngtech.java.junit.dataprovider.DataProviders.testForEach;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
Expand Down Expand Up @@ -114,13 +114,13 @@ public void get_all_classes_by_LocationProvider() {
.withPackagesRoots(ClassCacheTest.class)
.withLocationProviders(TestLocationProviderOfClass_String.class, TestLocationProviderOfClass_Rule.class));

assertThatClasses(classes).contain(String.class, Rule.class, getClass());
assertThatTypes(classes).contain(String.class, Rule.class, getClass());

classes = cache.getClassesToAnalyzeFor(TestClassWithLocationProviderUsingTestClass.class,
analyzeLocation(LocationOfClass.Provider.class));

assertThatClasses(classes).contain(String.class);
assertThatClasses(classes).doNotContain(getClass());
assertThatTypes(classes).contain(String.class);
assertThatTypes(classes).doNotContain(getClass());
}

@Test
Expand Down Expand Up @@ -275,4 +275,4 @@ public Set<Location> get(Class<?> testClass) {
return Collections.emptySet();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,12 @@ public static final class FieldAccessTarget extends AccessTarget implements HasT
this.field = Suppliers.memoize(builder.getField());
}

@Override
@PublicAPI(usage = ACCESS)
public JavaType getType() {
return type;
}

@Override
@PublicAPI(usage = ACCESS)
public JavaClass getRawType() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ public String apply(String input) {

/**
* Configures that the identifier is omitted if the annotation is a
* <a href="https://docs.oracle.com/javase/specs/jls/se14/html/jls-9.html#jls-9.7.3">single-element annotation</a>
* <a href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-9.html#jls-9.7.3">single-element annotation</a>
* and the identifier of the only element is "value".
*
* <ul><li>Example with this configuration: {@code @Copyright("2020 Acme Corporation")}</li>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ private JavaClassConversion(ClassLoader classLoader) {

@Override
public Class<?> convert(JavaClass input, Class<?> returnType) {
return JavaType.From.javaClass(input).resolveClass(classLoader);
return JavaClassDescriptor.From.javaClass(input).resolveClass(classLoader);
}

@Override
Expand Down Expand Up @@ -150,7 +150,7 @@ public boolean canHandle(Class<?> returnType) {
private static class JavaEnumConstantConversion implements Conversion<JavaEnumConstant> {
@Override
public Enum<?> convert(JavaEnumConstant input, Class<?> returnType) {
for (Object constant : JavaType.From.javaClass(input.getDeclaringClass()).resolveClass().getEnumConstants()) {
for (Object constant : JavaClassDescriptor.From.javaClass(input.getDeclaringClass()).resolveClass().getEnumConstants()) {
Enum<?> anEnum = (Enum<?>) constant;
if (anEnum.name().equals(input.name())) {
return anEnum;
Expand Down Expand Up @@ -196,7 +196,7 @@ public Annotation convert(JavaAnnotation<?> input, Class<?> returnType) {
// JavaAnnotation.getType() will return the type name of a Class<? extends Annotation>
@SuppressWarnings("unchecked")
Class<? extends Annotation> type = (Class<? extends Annotation>)
JavaType.From.javaClass(input.getRawType()).resolveClass(classLoader);
JavaClassDescriptor.From.javaClass(input.getRawType()).resolveClass(classLoader);
return AnnotationProxy.of(type, input);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,11 @@
import com.tngtech.archunit.core.importer.DomainBuilders.JavaMethodBuilder;
import com.tngtech.archunit.core.importer.DomainBuilders.JavaMethodCallBuilder;
import com.tngtech.archunit.core.importer.DomainBuilders.JavaStaticInitializerBuilder;
import com.tngtech.archunit.core.importer.DomainBuilders.JavaWildcardTypeBuilder;
import com.tngtech.archunit.core.importer.DomainBuilders.MethodCallTargetBuilder;

import static com.google.common.base.Preconditions.checkArgument;

/**
* Together with {@link DomainBuilders}, this class is the link to create domain objects from the import
* context. To make the API clear, we try to keep only those methods public, which are really meant to be used.
Expand All @@ -62,7 +65,7 @@
@Internal
public class DomainObjectCreationContext {
public static JavaClasses createJavaClasses(
Map<String, JavaClass> selectedClasses, Map<String, JavaClass> allClasses, ImportContext importContext) {
Map<String, JavaClass> selectedClasses, Collection<JavaClass> allClasses, ImportContext importContext) {

return JavaClasses.of(selectedClasses, allClasses, importContext);
}
Expand All @@ -75,6 +78,14 @@ public static void completeClassHierarchy(JavaClass javaClass, ImportContext imp
javaClass.completeClassHierarchyFrom(importContext);
}

public static void completeEnclosingClass(JavaClass javaClass, ImportContext importContext) {
javaClass.completeEnclosingClassFrom(importContext);
}

public static void completeTypeParameters(JavaClass javaClass, ImportContext importContext) {
javaClass.completeTypeParametersFrom(importContext);
}

public static void completeMembers(JavaClass javaClass, ImportContext importContext) {
javaClass.completeMembers(importContext);
}
Expand Down Expand Up @@ -143,6 +154,24 @@ public static <CODE_UNIT extends JavaCodeUnit> ThrowsClause<CODE_UNIT> createThr
return ThrowsClause.from(codeUnit, types);
}

public static JavaTypeVariable createTypeVariable(String name, JavaClass erasure) {
return new JavaTypeVariable(name, erasure);
}

public static void completeTypeVariable(JavaTypeVariable variable, List<JavaType> upperBounds) {
variable.setUpperBounds(upperBounds);
}

public static JavaGenericArrayType createGenericArrayType(JavaType componentType, JavaClass erasure) {
checkArgument(componentType instanceof JavaTypeVariable || componentType instanceof JavaGenericArrayType,
"Component type of a generic array type can only be a type variable or a generic array type. This is most likely a bug.");
return new JavaGenericArrayType(componentType.getName() + "[]", componentType, erasure);
}

public static JavaWildcardType createWildcardType(JavaWildcardTypeBuilder builder) {
return new JavaWildcardType(builder);
}

static class AccessContext {
final SetMultimap<JavaClass, JavaFieldAccess> fieldAccessesByTarget = HashMultimap.create();
final SetMultimap<JavaClass, JavaMethodCall> methodCallsByTarget = HashMultimap.create();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package com.tngtech.archunit.core.domain;

import java.util.List;
import java.util.Map;
import java.util.Set;

Expand All @@ -27,6 +28,8 @@ public interface ImportContext {

Set<JavaClass> createInterfaces(JavaClass owner);

List<JavaTypeVariable> createTypeParameters(JavaClass owner);

Set<JavaField> createFields(JavaClass owner);

Set<JavaMethod> createMethods(JavaClass owner);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ private String startWithLowerCase(HasDescription annotatedElement) {
return annotatedElement.getDescription().substring(0, 1).toLowerCase() + annotatedElement.getDescription().substring(1);
}

@Override
public JavaType getType() {
return type;
}

@Override
@PublicAPI(usage = ACCESS)
public JavaClass getRawType() {
Expand Down
Loading