Skip to content

Commit

Permalink
Add component type of arrays to JavaClass dependencies #257 #428
Browse files Browse the repository at this point in the history
This PR partly resolves #257 by adding the component type of arrays to the dependencies *from self* in `JavaClass`.
  • Loading branch information
codecholeric authored Dec 6, 2020
2 parents 077db87 + 956475b commit efd325a
Show file tree
Hide file tree
Showing 7 changed files with 346 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Field <com.tngtech.archunit.example.layers.controller.SomeController.otherServic
Field <com.tngtech.archunit.example.layers.controller.SomeController.service> has type <com.tngtech.archunit.example.layers.service.ServiceViolatingDaoRules> in (SomeController.java:0)
Field <com.tngtech.archunit.example.layers.persistence.layerviolation.DaoCallingService.service> has type <com.tngtech.archunit.example.layers.service.ServiceViolatingLayerRules> in (DaoCallingService.java:0)
Field <com.tngtech.archunit.example.layers.service.ServiceType.$VALUES> has type <[Lcom.tngtech.archunit.example.layers.service.ServiceType;> in (ServiceType.java:0)
Field <com.tngtech.archunit.example.layers.service.ServiceType.$VALUES> depends on component type <com.tngtech.archunit.example.layers.service.ServiceType> in (ServiceType.java:0)
Field <com.tngtech.archunit.example.layers.service.ServiceViolatingDaoRules.myEntityManager> has type <com.tngtech.archunit.example.layers.service.ServiceViolatingDaoRules$MyEntityManager> in (ServiceViolatingDaoRules.java:0)
Method <com.tngtech.archunit.example.layers.SomeMediator.violateLayerRulesIndirectly()> calls method <com.tngtech.archunit.example.layers.service.ServiceViolatingLayerRules.doSomething()> in (SomeMediator.java:15)
Method <com.tngtech.archunit.example.layers.controller.SomeGuiController.callServiceLayer()> calls constructor <com.tngtech.archunit.example.layers.service.ServiceHelper.<init>()> in (SomeGuiController.java:7)
Expand All @@ -20,4 +21,6 @@ Method <com.tngtech.archunit.example.layers.service.ComplexServiceAnnotation.ser
Method <com.tngtech.archunit.example.layers.service.ComplexServiceAnnotation.simpleServiceAnnotation()> has return type <com.tngtech.archunit.example.layers.service.SimpleServiceAnnotation> in (ComplexServiceAnnotation.java:0)
Method <com.tngtech.archunit.example.layers.service.ServiceType.values()> calls method <[Lcom.tngtech.archunit.example.layers.service.ServiceType;.clone()> in (ServiceType.java:3)
Method <com.tngtech.archunit.example.layers.service.ServiceType.values()> has return type <[Lcom.tngtech.archunit.example.layers.service.ServiceType;> in (ServiceType.java:0)
Method <com.tngtech.archunit.example.layers.service.ServiceType.values()> depends on component type <com.tngtech.archunit.example.layers.service.ServiceType> in (ServiceType.java:0)
Method <com.tngtech.archunit.example.layers.service.ServiceType.values()> depends on component type <com.tngtech.archunit.example.layers.service.ServiceType> in (ServiceType.java:3)
Method <com.tngtech.archunit.example.layers.service.ServiceViolatingDaoRules.illegallyUseEntityManager()> calls method <com.tngtech.archunit.example.layers.service.ServiceViolatingDaoRules$MyEntityManager.persist(java.lang.Object)> in (ServiceViolatingDaoRules.java:27)
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,18 @@
*/
package com.tngtech.archunit.core.domain;

import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

import com.google.common.base.MoreObjects;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.ImmutableSet;
import com.tngtech.archunit.PublicAPI;
import com.tngtech.archunit.base.ChainableFunction;
import com.tngtech.archunit.base.DescribedPredicate;
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.HasSourceCodeLocation;

Expand Down Expand Up @@ -62,11 +63,17 @@ private Dependency(JavaClass originClass, JavaClass targetClass, int lineNumber,
this.sourceCodeLocation = SourceCodeLocation.of(originClass, lineNumber);
}

static Optional<Dependency> tryCreateFromAccess(JavaAccess<?> access) {
if (access.getOriginOwner().equals(access.getTargetOwner()) || access.getTargetOwner().isPrimitive()) {
return Optional.absent();
static Set<Dependency> tryCreateFromAccess(JavaAccess<?> access) {
JavaClass originOwner = access.getOriginOwner();
JavaClass targetOwner = access.getTargetOwner();
if (originOwner.equals(targetOwner) || targetOwner.isPrimitive()) {
return Collections.emptySet();
}
return Optional.of(new Dependency(access.getOriginOwner(), access.getTargetOwner(), access.getLineNumber(), access.getDescription()));

ImmutableSet.Builder<Dependency> dependencies = ImmutableSet.<Dependency>builder()
.addAll(createComponentTypeDependencies(originOwner, access.getOrigin().getDescription(), targetOwner, access.getSourceCodeLocation()));
dependencies.add(new Dependency(originOwner, targetOwner, access.getLineNumber(), access.getDescription()));
return dependencies.build();
}

static Dependency fromInheritance(JavaClass origin, JavaClass targetSuperType) {
Expand All @@ -87,32 +94,32 @@ static Dependency fromInheritance(JavaClass origin, JavaClass targetSuperType) {
return new Dependency(origin, targetSuperType, 0, description);
}

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

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

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

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

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

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

static Optional<Dependency> tryCreateFromAnnotationMember(JavaAnnotation<?> annotation, JavaClass memberType) {
static Set<Dependency> tryCreateFromAnnotationMember(JavaAnnotation<?> annotation, JavaClass memberType) {
Origin origin = findSuitableOrigin(annotation);
return tryCreateDependency(origin.originClass, origin.originDescription, "has annotation member of type", memberType);
}
Expand All @@ -130,32 +137,47 @@ private static Origin findSuitableOrigin(JavaAnnotation<?> annotation) {
throw new IllegalStateException("Could not find suitable dependency origin for " + annotation);
}

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

private static Optional<Dependency> tryCreateDependencyFromJavaMemberWithLocation(JavaMember origin, String dependencyType, JavaClass target, int lineNumber) {
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 Optional<Dependency> tryCreateDependency(
private static Set<Dependency> tryCreateDependency(
JavaClass originClass, String originDescription, String dependencyType, JavaClass targetClass) {

return tryCreateDependency(originClass, originDescription, dependencyType, targetClass, originClass.getSourceCodeLocation());
}

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

if (originClass.equals(targetClass) || targetClass.isPrimitive()) {
return Optional.absent();
return Collections.emptySet();
}

ImmutableSet.Builder<Dependency> dependencies = ImmutableSet.<Dependency>builder()
.addAll(createComponentTypeDependencies(originClass, originDescription, targetClass, sourceCodeLocation));
String targetDescription = bracketFormat(targetClass.getName());
String dependencyDescription = originDescription + " " + dependencyType + " " + targetDescription;
String description = dependencyDescription + " in " + sourceCodeLocation;
int lineNumber = sourceCodeLocation.getLineNumber();
return Optional.of(new Dependency(originClass, targetClass, lineNumber, description));
dependencies.add(new Dependency(originClass, targetClass, sourceCodeLocation.getLineNumber(), description));
return dependencies.build();
}

private static Set<Dependency> createComponentTypeDependencies(JavaClass originClass, String originDescription, JavaClass targetClass, SourceCodeLocation sourceCodeLocation) {
ImmutableSet.Builder<Dependency> result = ImmutableSet.builder();
JavaClass componentType = targetClass;
while (componentType.isArray()) {
componentType = componentType.getComponentType();
String componentTypeTargetDescription = bracketFormat(componentType.getName());
String componentTypeDependencyDescription = originDescription + " depends on component type " + componentTypeTargetDescription;
String componentTypeDescription = componentTypeDependencyDescription + " in " + sourceCodeLocation;
result.add(new Dependency(originClass, componentType, sourceCodeLocation.getLineNumber(), componentTypeDescription));
}
return result.build();
}

private static String bracketFormat(String name) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ Set<InstanceofCheck> getInstanceofChecksWithTypeOfClass() {
private Set<Dependency> dependenciesFromAccesses(Set<JavaAccess<?>> accesses) {
ImmutableSet.Builder<Dependency> result = ImmutableSet.builder();
for (JavaAccess<?> access : accesses) {
result.addAll(Dependency.tryCreateFromAccess(access).asSet());
result.addAll(Dependency.tryCreateFromAccess(access));
}
return result.build();
}
Expand All @@ -158,15 +158,15 @@ private Set<Dependency> inheritanceDependenciesFromSelf() {
private Set<Dependency> fieldDependenciesFromSelf() {
ImmutableSet.Builder<Dependency> result = ImmutableSet.builder();
for (JavaField field : javaClass.getFields()) {
result.addAll(Dependency.tryCreateFromField(field).asSet());
result.addAll(Dependency.tryCreateFromField(field));
}
return result.build();
}

private Set<Dependency> returnTypeDependenciesFromSelf() {
ImmutableSet.Builder<Dependency> result = ImmutableSet.builder();
for (JavaMethod method : javaClass.getMethods()) {
result.addAll(Dependency.tryCreateFromReturnType(method).asSet());
result.addAll(Dependency.tryCreateFromReturnType(method));
}
return result.build();
}
Expand All @@ -175,7 +175,7 @@ private Set<Dependency> methodParameterDependenciesFromSelf() {
ImmutableSet.Builder<Dependency> result = ImmutableSet.builder();
for (JavaMethod method : javaClass.getMethods()) {
for (JavaClass parameter : method.getRawParameterTypes()) {
result.addAll(Dependency.tryCreateFromParameter(method, parameter).asSet());
result.addAll(Dependency.tryCreateFromParameter(method, parameter));
}
}
return result.build();
Expand All @@ -185,7 +185,7 @@ private Set<Dependency> throwsDeclarationDependenciesFromSelf() {
ImmutableSet.Builder<Dependency> result = ImmutableSet.builder();
for (JavaCodeUnit codeUnit : javaClass.getCodeUnits()) {
for (ThrowsDeclaration<? extends JavaCodeUnit> throwsDeclaration : codeUnit.getThrowsClause()) {
result.addAll(Dependency.tryCreateFromThrowsDeclaration(throwsDeclaration).asSet());
result.addAll(Dependency.tryCreateFromThrowsDeclaration(throwsDeclaration));
}
}
return result.build();
Expand All @@ -195,7 +195,7 @@ private Set<Dependency> constructorParameterDependenciesFromSelf() {
ImmutableSet.Builder<Dependency> result = ImmutableSet.builder();
for (JavaConstructor constructor : javaClass.getConstructors()) {
for (JavaClass parameter : constructor.getRawParameterTypes()) {
result.addAll(Dependency.tryCreateFromParameter(constructor, parameter).asSet());
result.addAll(Dependency.tryCreateFromParameter(constructor, parameter));
}
}
return result.build();
Expand All @@ -214,7 +214,7 @@ private Set<Dependency> instanceofCheckDependenciesFromSelf() {
ImmutableSet.Builder<Dependency> result = ImmutableSet.builder();
for (JavaCodeUnit codeUnit : javaClass.getCodeUnits()) {
for (InstanceofCheck instanceofCheck : codeUnit.getInstanceofChecks()) {
result.addAll(Dependency.tryCreateFromInstanceofCheck(instanceofCheck).asSet());
result.addAll(Dependency.tryCreateFromInstanceofCheck(instanceofCheck));
}
}
return result.build();
Expand All @@ -231,21 +231,21 @@ private <T extends HasDescription & HasAnnotations<?>> Set<Dependency> annotatio
private <T extends HasDescription & HasAnnotations<?>> Set<Dependency> annotationDependencies(T annotated) {
final ImmutableSet.Builder<Dependency> result = ImmutableSet.builder();
for (final JavaAnnotation<?> annotation : annotated.getAnnotations()) {
result.addAll(Dependency.tryCreateFromAnnotation(annotation).asSet());
result.addAll(Dependency.tryCreateFromAnnotation(annotation));
annotation.accept(new DefaultParameterVisitor() {
@Override
public void visitClass(String propertyName, JavaClass javaClass) {
result.addAll(Dependency.tryCreateFromAnnotationMember(annotation, javaClass).asSet());
result.addAll(Dependency.tryCreateFromAnnotationMember(annotation, javaClass));
}

@Override
public void visitEnumConstant(String propertyName, JavaEnumConstant enumConstant) {
result.addAll(Dependency.tryCreateFromAnnotationMember(annotation, enumConstant.getDeclaringClass()).asSet());
result.addAll(Dependency.tryCreateFromAnnotationMember(annotation, enumConstant.getDeclaringClass()));
}

@Override
public void visitAnnotation(String propertyName, JavaAnnotation<?> memberAnnotation) {
result.addAll(Dependency.tryCreateFromAnnotationMember(annotation, memberAnnotation.getRawType()).asSet());
result.addAll(Dependency.tryCreateFromAnnotationMember(annotation, memberAnnotation.getRawType()));
memberAnnotation.accept(this);
}
});
Expand All @@ -264,58 +264,58 @@ private Set<Dependency> inheritanceDependenciesToSelf() {
private Set<Dependency> fieldDependenciesToSelf() {
Set<Dependency> result = new HashSet<>();
for (JavaField field : javaClass.getFieldsWithTypeOfSelf()) {
result.addAll(Dependency.tryCreateFromField(field).asSet());
result.addAll(Dependency.tryCreateFromField(field));
}
return result;
}

private Set<Dependency> returnTypeDependenciesToSelf() {
Set<Dependency> result = new HashSet<>();
for (JavaMethod method : javaClass.getMethodsWithReturnTypeOfSelf()) {
result.addAll(Dependency.tryCreateFromReturnType(method).asSet());
result.addAll(Dependency.tryCreateFromReturnType(method));
}
return result;
}

private Set<Dependency> methodParameterDependenciesToSelf() {
Set<Dependency> result = new HashSet<>();
for (JavaMethod method : javaClass.getMethodsWithParameterTypeOfSelf()) {
result.addAll(Dependency.tryCreateFromParameter(method, javaClass).asSet());
result.addAll(Dependency.tryCreateFromParameter(method, javaClass));
}
return result;
}

private Set<Dependency> throwsDeclarationDependenciesToSelf() {
Set<Dependency> result = new HashSet<>();
for (ThrowsDeclaration<? extends JavaCodeUnit> throwsDeclaration : getThrowsDeclarationsWithTypeOfClass()) {
result.addAll(Dependency.tryCreateFromThrowsDeclaration(throwsDeclaration).asSet());
result.addAll(Dependency.tryCreateFromThrowsDeclaration(throwsDeclaration));
}
return result;
}

private Set<Dependency> constructorParameterDependenciesToSelf() {
Set<Dependency> result = new HashSet<>();
for (JavaConstructor constructor : javaClass.getConstructorsWithParameterTypeOfSelf()) {
result.addAll(Dependency.tryCreateFromParameter(constructor, javaClass).asSet());
result.addAll(Dependency.tryCreateFromParameter(constructor, javaClass));
}
return result;
}

private Iterable<? extends Dependency> annotationDependenciesToSelf() {
Set<Dependency> result = new HashSet<>();
for (JavaAnnotation<?> annotation : annotationsWithTypeOfClass) {
result.addAll(Dependency.tryCreateFromAnnotation(annotation).asSet());
result.addAll(Dependency.tryCreateFromAnnotation(annotation));
}
for (JavaAnnotation<?> annotation : annotationsWithParameterTypeOfClass) {
result.addAll(Dependency.tryCreateFromAnnotationMember(annotation, javaClass).asSet());
result.addAll(Dependency.tryCreateFromAnnotationMember(annotation, javaClass));
}
return result;
}

private Set<Dependency> instanceofCheckDependenciesToSelf() {
Set<Dependency> result = new HashSet<>();
for (InstanceofCheck instanceofCheck : getInstanceofChecksWithTypeOfClass()) {
result.addAll(Dependency.tryCreateFromInstanceofCheck(instanceofCheck).asSet());
result.addAll(Dependency.tryCreateFromInstanceofCheck(instanceofCheck));
}
return result;
}
Expand Down
Loading

0 comments on commit efd325a

Please sign in to comment.