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

Add referenced class objects to JavaClass #518

Merged
merged 5 commits into from
Jan 31, 2021
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 @@ -972,6 +972,9 @@ Stream<DynamicTest> OnionArchitectureTest() {
.by(field(ShoppingService.class, "productRepository").ofType(ProductRepository.class))
.by(field(ShoppingService.class, "shoppingCartRepository").ofType(ShoppingCartRepository.class))

.by(method(AdministrationCLI.class, "handle")
.referencingClassObject(ProductRepository.class)
.inLine(16))
.by(callFromMethod(AdministrationCLI.class, "handle", String[].class, AdministrationPort.class)
.toMethod(ProductRepository.class, "getTotalCount")
.inLine(17).asDependency())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,11 @@ public ExpectedDependency withAnnotationType(Class<?> annotationType) {
}

public AddsLineNumber checkingInstanceOf(Class<?> target) {
return new AddsLineNumber(owner, getOriginName(), target);
return new AddsLineNumber(owner, getOriginName(), "checks instanceof", target);
}

public AddsLineNumber referencingClassObject(Class<?> target) {
return new AddsLineNumber(owner, getOriginName(), "references class object", target);
}

private String getOriginName() {
Expand All @@ -201,15 +205,17 @@ public static class AddsLineNumber {
private final Class<?> owner;
private final String origin;
private final Class<?> target;
private final String dependencyType;

private AddsLineNumber(Class<?> owner, String origin, Class<?> target) {
private AddsLineNumber(Class<?> owner, String origin, String dependencyType, Class<?> target) {
this.owner = owner;
this.origin = origin;
this.target = target;
this.dependencyType = dependencyType;
}

public ExpectedDependency inLine(int lineNumber) {
String dependencyPattern = getDependencyPattern(origin, "checks instanceof", target.getName(), lineNumber);
String dependencyPattern = getDependencyPattern(origin, dependencyType, target.getName(), lineNumber);
return new ExpectedDependency(owner, target, dependencyPattern);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.tngtech.archunit.base.HasDescription;
import com.tngtech.archunit.base.Optional;
import com.tngtech.archunit.core.domain.properties.HasName;
import com.tngtech.archunit.core.domain.properties.HasOwner;
import com.tngtech.archunit.core.domain.properties.HasSourceCodeLocation;

import static com.google.common.base.Preconditions.checkArgument;
Expand Down Expand Up @@ -100,44 +101,52 @@ static Dependency fromInheritance(JavaClass origin, JavaClass targetSupertype) {
}

static Set<Dependency> tryCreateFromField(JavaField field) {
return tryCreateDependencyFromJavaMember(field, "has type", field.getRawType());
return tryCreateDependency(field, "has type", field.getRawType());
}

static Set<Dependency> tryCreateFromReturnType(JavaMethod method) {
return tryCreateDependencyFromJavaMember(method, "has return type", method.getRawReturnType());
return tryCreateDependency(method, "has return type", method.getRawReturnType());
}

static Set<Dependency> tryCreateFromParameter(JavaCodeUnit codeUnit, JavaClass parameter) {
return tryCreateDependencyFromJavaMember(codeUnit, "has parameter of type", parameter);
return tryCreateDependency(codeUnit, "has parameter of type", parameter);
}

static Set<Dependency> tryCreateFromThrowsDeclaration(ThrowsDeclaration<? extends JavaCodeUnit> declaration) {
return tryCreateDependencyFromJavaMember(declaration.getLocation(), "throws type", declaration.getRawType());
return tryCreateDependency(declaration.getLocation(), "throws type", declaration.getRawType());
}

static Set<Dependency> tryCreateFromInstanceofCheck(InstanceofCheck instanceofCheck) {
return tryCreateDependencyFromJavaMemberWithLocation(instanceofCheck.getOwner(), "checks instanceof", instanceofCheck.getRawType(), instanceofCheck.getLineNumber());
return tryCreateDependency(
instanceofCheck.getOwner(), "checks instanceof",
instanceofCheck.getRawType(), instanceofCheck.getSourceCodeLocation());
}

static Set<Dependency> tryCreateFromReferencedClassObject(ReferencedClassObject referencedClassObject) {
return tryCreateDependency(
referencedClassObject.getOwner(), "references class object",
referencedClassObject.getRawType(), referencedClassObject.getSourceCodeLocation());
}

static Set<Dependency> tryCreateFromAnnotation(JavaAnnotation<?> target) {
Origin origin = findSuitableOrigin(target, target.getAnnotatedElement());
return tryCreateDependency(origin.originClass, origin.originDescription, "is annotated with", target.getRawType());
return tryCreateDependency(origin, "is annotated with", target.getRawType());
}

static Set<Dependency> tryCreateFromAnnotationMember(JavaAnnotation<?> annotation, JavaClass memberType) {
Origin origin = findSuitableOrigin(annotation, annotation.getAnnotatedElement());
return tryCreateDependency(origin.originClass, origin.originDescription, "has annotation member of type", memberType);
return tryCreateDependency(origin, "has annotation member of type", memberType);
}

static Set<Dependency> tryCreateFromTypeParameter(JavaTypeVariable<?> typeParameter, JavaClass typeParameterDependency) {
String dependencyType = "has type parameter '" + typeParameter.getName() + "' depending on";
Origin origin = findSuitableOrigin(typeParameter, typeParameter.getOwner());
return tryCreateDependency(origin.originClass, origin.originDescription, dependencyType, typeParameterDependency);
return tryCreateDependency(origin, dependencyType, typeParameterDependency);
}

static Set<Dependency> tryCreateFromGenericSuperclassTypeArguments(JavaClass originClass, JavaType superclass, JavaClass typeArgumentDependency) {
String dependencyType = "has generic superclass " + bracketFormat(superclass.getName()) + " with type argument depending on";
return tryCreateDependency(originClass, originClass.getDescription(), dependencyType, typeArgumentDependency);
return tryCreateDependency(originClass, originClass.getDescription(), dependencyType, typeArgumentDependency, originClass.getSourceCodeLocation());
}

private static Origin findSuitableOrigin(Object dependencyCause, Object originCandidate) {
Expand All @@ -152,22 +161,20 @@ private static Origin findSuitableOrigin(Object dependencyCause, Object originCa
throw new IllegalStateException("Could not find suitable dependency origin for " + dependencyCause);
}

private static Set<Dependency> tryCreateDependencyFromJavaMember(JavaMember origin, String dependencyType, JavaClass target) {
return tryCreateDependency(origin.getOwner(), origin.getDescription(), dependencyType, target);
}

private static Set<Dependency> tryCreateDependencyFromJavaMemberWithLocation(JavaMember origin, String dependencyType, JavaClass target, int lineNumber) {
return tryCreateDependency(origin.getOwner(), origin.getDescription(), dependencyType, target, SourceCodeLocation.of(origin.getOwner(), lineNumber));
private static <T extends HasOwner<JavaClass> & HasDescription> Set<Dependency> tryCreateDependency(
T origin, String dependencyType, JavaClass targetClass) {
return tryCreateDependency(origin, dependencyType, targetClass, origin.getOwner().getSourceCodeLocation());
}

private static Set<Dependency> tryCreateDependency(
JavaClass originClass, String originDescription, String dependencyType, JavaClass targetClass) {
private static <T extends HasOwner<JavaClass> & HasDescription> Set<Dependency> tryCreateDependency(
T origin, String dependencyType, JavaClass targetClass, SourceCodeLocation sourceCodeLocation) {

return tryCreateDependency(originClass, originDescription, dependencyType, targetClass, originClass.getSourceCodeLocation());
return tryCreateDependency(origin.getOwner(), origin.getDescription(), dependencyType, targetClass, sourceCodeLocation);
}

private static Set<Dependency> tryCreateDependency(
JavaClass originClass, String originDescription, String dependencyType, JavaClass targetClass, SourceCodeLocation sourceCodeLocation) {

ImmutableSet.Builder<Dependency> dependencies = ImmutableSet.<Dependency>builder()
.addAll(createComponentTypeDependencies(originClass, originDescription, targetClass, sourceCodeLocation));
String targetDescription = bracketFormat(targetClass.getName());
Expand All @@ -177,7 +184,9 @@ private static Set<Dependency> tryCreateDependency(
return dependencies.build();
}

private static Set<Dependency> createComponentTypeDependencies(JavaClass originClass, String originDescription, JavaClass targetClass, SourceCodeLocation sourceCodeLocation) {
private static Set<Dependency> createComponentTypeDependencies(
JavaClass originClass, String originDescription, JavaClass targetClass, SourceCodeLocation sourceCodeLocation) {

ImmutableSet.Builder<Dependency> result = ImmutableSet.builder();
Optional<JavaClass> componentType = targetClass.tryGetComponentType();
while (componentType.isPresent()) {
Expand Down Expand Up @@ -271,14 +280,24 @@ public static JavaClasses toTargetClasses(Iterable<Dependency> dependencies) {
return JavaClasses.of(classes);
}

private static class Origin {
private static class Origin implements HasOwner<JavaClass>, HasDescription {
private final JavaClass originClass;
private final String originDescription;

private Origin(JavaClass originClass, String originDescription) {
this.originClass = originClass;
this.originDescription = originDescription;
}

@Override
public JavaClass getOwner() {
return originClass;
}

@Override
public String getDescription() {
return originDescription;
}
}

public static final class Predicates {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,10 @@ public static Source createSource(URI uri, Optional<String> sourceFileName, bool
return new Source(uri, sourceFileName, md5InClassSourcesEnabled);
}

public static ReferencedClassObject createReferencedClassObject(JavaCodeUnit codeUnit, JavaClass javaClass, int lineNumber) {
return ReferencedClassObject.from(codeUnit, javaClass, lineNumber);
}

public static <CODE_UNIT extends JavaCodeUnit> ThrowsClause<CODE_UNIT> createThrowsClause(CODE_UNIT codeUnit, List<JavaClass> types) {
return ThrowsClause.from(codeUnit, types);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,25 @@

import com.tngtech.archunit.PublicAPI;
import com.tngtech.archunit.core.domain.properties.HasOwner;
import com.tngtech.archunit.core.domain.properties.HasSourceCodeLocation;
import com.tngtech.archunit.core.domain.properties.HasType;

import static com.google.common.base.MoreObjects.toStringHelper;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.tngtech.archunit.PublicAPI.Usage.ACCESS;

public final class InstanceofCheck implements HasType, HasOwner<JavaCodeUnit> {
public final class InstanceofCheck implements HasType, HasOwner<JavaCodeUnit>, HasSourceCodeLocation {

private final JavaCodeUnit owner;
private final JavaClass target;
private final int lineNumber;
private final SourceCodeLocation sourceCodeLocation;

private InstanceofCheck(JavaCodeUnit owner, JavaClass target, int lineNumber) {
this.owner = checkNotNull(owner);
this.target = checkNotNull(target);
this.lineNumber = lineNumber;
sourceCodeLocation = SourceCodeLocation.of(owner.getOwner(), lineNumber);
}

@Override
Expand All @@ -57,6 +61,20 @@ public int getLineNumber() {
return lineNumber;
}

@Override
public SourceCodeLocation getSourceCodeLocation() {
return sourceCodeLocation;
}

@Override
public String toString() {
return toStringHelper(this)
.add("owner", owner)
.add("target", target)
.add("lineNumber", lineNumber)
.toString();
}

static InstanceofCheck from(JavaCodeUnit owner, JavaClass target, int lineNumber) {
return new InstanceofCheck(owner, target, lineNumber);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,15 @@ public List<JavaTypeVariable<JavaClass>> getTypeParameters() {
return typeParameters;
}

@PublicAPI(usage = ACCESS)
public Set<ReferencedClassObject> getReferencedClassObjects() {
ImmutableSet.Builder<ReferencedClassObject> result = ImmutableSet.builder();
for (JavaCodeUnit codeUnit : codeUnits) {
result.addAll(codeUnit.getReferencedClassObjects());
}
return result.build();
}

@Override
@PublicAPI(usage = ACCESS)
public JavaClass toErasure() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public Set<Dependency> get() {
result.addAll(constructorParameterDependenciesFromSelf());
result.addAll(annotationDependenciesFromSelf());
result.addAll(instanceofCheckDependenciesFromSelf());
result.addAll(referencedClassObjectDependenciesFromSelf());
result.addAll(typeParameterDependenciesFromSelf());
return result.build();
}
Expand Down Expand Up @@ -158,6 +159,14 @@ private Set<Dependency> instanceofCheckDependenciesFromSelf() {
return result.build();
}

private Set<Dependency> referencedClassObjectDependenciesFromSelf() {
ImmutableSet.Builder<Dependency> result = ImmutableSet.builder();
for (ReferencedClassObject referencedClassObject : javaClass.getReferencedClassObjects()) {
result.addAll(Dependency.tryCreateFromReferencedClassObject(referencedClassObject));
}
return result.build();
}

private Set<Dependency> typeParameterDependenciesFromSelf() {
ImmutableSet.Builder<Dependency> result = ImmutableSet.builder();
for (JavaTypeVariable<?> typeVariable : javaClass.getTypeParameters()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public abstract class JavaCodeUnit extends JavaMember implements HasParameterTyp
private final JavaClass returnType;
private final JavaClassList parameters;
private final String fullName;
private final Set<ReferencedClassObject> referencedClassObjects;
private final Set<InstanceofCheck> instanceofChecks;

private Set<JavaFieldAccess> fieldAccesses = Collections.emptySet();
Expand All @@ -61,7 +62,8 @@ public abstract class JavaCodeUnit extends JavaMember implements HasParameterTyp
this.returnType = builder.getReturnType();
this.parameters = builder.getParameters();
fullName = formatMethod(getOwner().getName(), getName(), getRawParameterTypes());
instanceofChecks = builder.getInstanceofChecks(this);
referencedClassObjects = ImmutableSet.copyOf(builder.getReferencedClassObjects(this));
instanceofChecks = ImmutableSet.copyOf(builder.getInstanceofChecks(this));
}

/**
Expand Down Expand Up @@ -112,6 +114,11 @@ public Set<JavaConstructorCall> getConstructorCallsFromSelf() {
return constructorCalls;
}

@PublicAPI(usage = ACCESS)
public Set<ReferencedClassObject> getReferencedClassObjects() {
return referencedClassObjects;
}

@PublicAPI(usage = ACCESS)
public Set<InstanceofCheck> getInstanceofChecks() {
return instanceofChecks;
Expand Down
Loading