Skip to content

Commit

Permalink
move JavaCodeUnit.Parameter to toplevel JavaParameter
Browse files Browse the repository at this point in the history
Originally I decided for `JavaCodeUnit.Parameter` because
* the concept is very closely related to `JavaCodeUnit`
* as a nested class it would enable to import as `Parameter` in a clear narrow scope or as `JavaCodeUnit.Parameter` in a wider scope
* I considered "parameter" alone to be too generic as a name

However, I have now decided to name it `JavaParameter` after all. The reason is simply, that it is consistent with the Reflection API. And since we followed this philosophy with most other classes (`Class` -> `JavaClass`, `Method` -> `JavaMethod`, ...) I consider this to be the way of least surprise. Which in the end is one of the most important guiding principles we should follow.

Signed-off-by: Peter Gafert <peter.gafert@tngtech.com>
  • Loading branch information
codecholeric committed Oct 28, 2021
1 parent c995b95 commit 83355ae
Show file tree
Hide file tree
Showing 7 changed files with 195 additions and 184 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,8 @@ private static Origin findSuitableOrigin(Object dependencyCause, Object originCa
JavaClass clazz = (JavaClass) originCandidate;
return new Origin(clazz, clazz.getDescription());
}
if (originCandidate instanceof JavaCodeUnit.Parameter) {
JavaCodeUnit.Parameter parameter = (JavaCodeUnit.Parameter) originCandidate;
if (originCandidate instanceof JavaParameter) {
JavaParameter parameter = (JavaParameter) originCandidate;
return new Origin(parameter.getOwner().getOwner(), parameter.getDescription());
}
throw new IllegalStateException("Could not find suitable dependency origin for " + dependencyCause);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,46 +15,30 @@
*/
package com.tngtech.archunit.core.domain;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.tngtech.archunit.PublicAPI;
import com.tngtech.archunit.base.ChainableFunction;
import com.tngtech.archunit.base.DescribedPredicate;
import com.tngtech.archunit.base.ForwardingList;
import com.tngtech.archunit.base.Optional;
import com.tngtech.archunit.core.MayResolveTypesViaReflection;
import com.tngtech.archunit.core.ResolvesTypesViaReflection;
import com.tngtech.archunit.core.domain.properties.CanBeAnnotated;
import com.tngtech.archunit.core.domain.properties.HasAnnotations;
import com.tngtech.archunit.core.domain.properties.HasOwner;
import com.tngtech.archunit.core.domain.properties.HasParameterTypes;
import com.tngtech.archunit.core.domain.properties.HasReturnType;
import com.tngtech.archunit.core.domain.properties.HasThrowsClause;
import com.tngtech.archunit.core.domain.properties.HasType;
import com.tngtech.archunit.core.domain.properties.HasTypeParameters;
import com.tngtech.archunit.core.importer.DomainBuilders.JavaCodeUnitBuilder;
import com.tngtech.archunit.core.importer.DomainBuilders.JavaCodeUnitBuilder.ParameterAnnotationsBuilder;

import static com.tngtech.archunit.PublicAPI.Usage.ACCESS;
import static com.tngtech.archunit.base.DescribedPredicate.anyElementThat;
import static com.tngtech.archunit.base.DescribedPredicate.equalTo;
import static com.tngtech.archunit.base.Guava.toGuava;
import static com.tngtech.archunit.core.domain.Formatters.formatMethod;
import static com.tngtech.archunit.core.domain.JavaClass.Predicates.equivalentTo;
import static com.tngtech.archunit.core.domain.properties.CanBeAnnotated.Utils.toAnnotationOfType;
import static com.tngtech.archunit.core.domain.properties.HasName.Functions.GET_NAME;
import static com.tngtech.archunit.core.domain.properties.HasName.Utils.namesOf;
import static com.tngtech.archunit.core.domain.properties.HasType.Functions.GET_RAW_TYPE;

/**
* Represents a unit of code containing accesses to other units of code. A unit of code can be
Expand Down Expand Up @@ -139,7 +123,7 @@ public List<JavaType> getParameterTypes() {
}

/**
* @return the {@link Parameter parameters} of this {@link JavaCodeUnit}. On the contrary to the Reflection API this will only contain
* @return the {@link JavaParameter parameters} of this {@link JavaCodeUnit}. On the contrary to the Reflection API this will only contain
* the parameters from the signature and not synthetic parameters, if the signature is generic. In these cases
* {@link #getParameters()}{@code .size()} will always be equal to {@link #getParameterTypes()}{@code .size()},
* but not necessarily to {@link #getRawParameterTypes()}{@code .size()} in case the compiler adds synthetic parameters.<br>
Expand All @@ -151,7 +135,7 @@ public List<JavaType> getParameterTypes() {
* @see #getParameterTypes()
*/
@PublicAPI(usage = ACCESS)
public List<Parameter> getParameters() {
public List<JavaParameter> getParameters() {
return parameters;
}

Expand Down Expand Up @@ -249,7 +233,7 @@ public List<? extends JavaTypeVariable<? extends JavaCodeUnit>> getTypeParameter
}

@PublicAPI(usage = ACCESS)
public List<Set<JavaAnnotation<Parameter>>> getParameterAnnotations() {
public List<Set<JavaAnnotation<JavaParameter>>> getParameterAnnotations() {
return parameters.getAnnotations();
}

Expand All @@ -269,137 +253,11 @@ static Class<?>[] reflect(List<JavaClass> parameters) {
return result.toArray(new Class<?>[0]);
}

/**
* A parameter of a {@link JavaCodeUnit}, i.e. encapsulates the raw parameter type, the (possibly) generic
* parameter type and any annotations this parameter has.
*/
@PublicAPI(usage = ACCESS)
public static final class Parameter implements HasType, HasOwner<JavaCodeUnit>, HasAnnotations<Parameter> {
private static final ChainableFunction<HasType, String> GET_ANNOTATION_TYPE_NAME = GET_RAW_TYPE.then(GET_NAME);
private static final Function<HasType, String> GUAVA_GET_ANNOTATION_TYPE_NAME = toGuava(GET_ANNOTATION_TYPE_NAME);

private final JavaCodeUnit owner;
private final int index;
private final JavaType type;
private final JavaClass rawType;
private final Map<String, JavaAnnotation<Parameter>> annotations;

private Parameter(JavaCodeUnit owner, ParameterAnnotationsBuilder builder, int index, JavaType type) {
this.owner = owner;
this.index = index;
this.type = type;
this.rawType = type.toErasure();
this.annotations = buildIndexedByTypeName(builder);
}

private Map<String, JavaAnnotation<Parameter>> buildIndexedByTypeName(ParameterAnnotationsBuilder builder) {
Set<JavaAnnotation<Parameter>> annotations = builder.build(this);
return Maps.uniqueIndex(annotations, GUAVA_GET_ANNOTATION_TYPE_NAME);
}

@Override
@PublicAPI(usage = ACCESS)
public JavaCodeUnit getOwner() {
return owner;
}

@PublicAPI(usage = ACCESS)
public int getIndex() {
return index;
}

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

@Override
@PublicAPI(usage = ACCESS)
public JavaClass getRawType() {
return rawType;
}

@Override
public boolean isAnnotatedWith(Class<? extends Annotation> annotationType) {
return annotations.containsKey(annotationType.getName());
}

@Override
public boolean isAnnotatedWith(String annotationTypeName) {
return annotations.containsKey(annotationTypeName);
}

@Override
public boolean isAnnotatedWith(DescribedPredicate<? super JavaAnnotation<?>> predicate) {
return anyElementThat(predicate).apply(annotations.values());
}

@Override
public boolean isMetaAnnotatedWith(Class<? extends Annotation> annotationType) {
return isMetaAnnotatedWith(GET_RAW_TYPE.is(equivalentTo(annotationType)));
}

@Override
public boolean isMetaAnnotatedWith(String annotationTypeName) {
return isMetaAnnotatedWith(GET_ANNOTATION_TYPE_NAME.is(equalTo(annotationTypeName)));
}

@Override
public boolean isMetaAnnotatedWith(DescribedPredicate<? super JavaAnnotation<?>> predicate) {
return CanBeAnnotated.Utils.isMetaAnnotatedWith(annotations.values(), predicate);
}

@Override
public Set<JavaAnnotation<Parameter>> getAnnotations() {
return ImmutableSet.copyOf(annotations.values());
}

@Override
public <A extends Annotation> A getAnnotationOfType(Class<A> type) {
return getAnnotationOfType(type.getName()).as(type);
}

@Override
public JavaAnnotation<Parameter> getAnnotationOfType(String typeName) {
Optional<JavaAnnotation<Parameter>> annotation = tryGetAnnotationOfType(typeName);
if (!annotation.isPresent()) {
throw new IllegalArgumentException(String.format("%s is not annotated with @%s", getDescription(), typeName));
}
return annotation.get();
}

@Override
public <A extends Annotation> Optional<A> tryGetAnnotationOfType(Class<A> type) {
return tryGetAnnotationOfType(type.getName()).map(toAnnotationOfType(type));
}

@Override
public Optional<JavaAnnotation<Parameter>> tryGetAnnotationOfType(String typeName) {
return Optional.ofNullable(annotations.get(typeName));
}

@Override
@PublicAPI(usage = ACCESS)
public String getDescription() {
return "Parameter <" + type.getName() + "> of " + startWithLowercase(owner.getDescription());
}

@Override
public String toString() {
return "JavaParameter{owner='" + owner.getFullName() + "', index='" + index + "', type='" + type.getName() + "'}";
}

static String startWithLowercase(String string) {
return Character.toLowerCase(string.charAt(0)) + string.substring(1);
}
}

private static class Parameters extends ForwardingList<Parameter> {
private static class Parameters extends ForwardingList<JavaParameter> {
private final List<JavaClass> rawParameterTypes;
private final List<JavaType> parameterTypes;
private final List<Set<JavaAnnotation<Parameter>>> parameterAnnotations;
private final List<Parameter> parameters;
private final List<Set<JavaAnnotation<JavaParameter>>> parameterAnnotations;
private final List<JavaParameter> parameters;

Parameters(JavaCodeUnit owner, JavaCodeUnitBuilder<?, ?> builder) {
rawParameterTypes = builder.getRawParameterTypes();
Expand All @@ -408,18 +266,18 @@ private static class Parameters extends ForwardingList<Parameter> {
parameterAnnotations = annotationsOf(parameters);
}

private List<Set<JavaAnnotation<Parameter>>> annotationsOf(List<Parameter> parameters) {
ImmutableList.Builder<Set<JavaAnnotation<Parameter>>> result = ImmutableList.builder();
for (Parameter parameter : parameters) {
private List<Set<JavaAnnotation<JavaParameter>>> annotationsOf(List<JavaParameter> parameters) {
ImmutableList.Builder<Set<JavaAnnotation<JavaParameter>>> result = ImmutableList.builder();
for (JavaParameter parameter : parameters) {
result.add(parameter.getAnnotations());
}
return result.build();
}

private static List<Parameter> createParameters(JavaCodeUnit owner, JavaCodeUnitBuilder<?, ?> builder, List<JavaType> parameterTypes) {
ImmutableList.Builder<Parameter> result = ImmutableList.builder();
private static List<JavaParameter> createParameters(JavaCodeUnit owner, JavaCodeUnitBuilder<?, ?> builder, List<JavaType> parameterTypes) {
ImmutableList.Builder<JavaParameter> result = ImmutableList.builder();
for (int i = 0; i < parameterTypes.size(); i++) {
result.add(new Parameter(owner, builder.getParameterAnnotationsBuilder(i), i, parameterTypes.get(i)));
result.add(new JavaParameter(owner, builder.getParameterAnnotationsBuilder(i), i, parameterTypes.get(i)));
}
return result.build();
}
Expand All @@ -437,12 +295,12 @@ List<JavaType> getParameterTypes() {
return parameterTypes;
}

List<Set<JavaAnnotation<Parameter>>> getAnnotations() {
List<Set<JavaAnnotation<JavaParameter>>> getAnnotations() {
return parameterAnnotations;
}

@Override
protected List<Parameter> delegate() {
protected List<JavaParameter> delegate() {
return parameters;
}
}
Expand Down
Loading

0 comments on commit 83355ae

Please sign in to comment.