Use less confusing MergedAnnotation method names
Rename some `MergedAnnotation` methods to prevent using parent/child terminology, specifically: `getDepth()` has been renamed `getDistance()` `getParent()` has been renamed `getMetaSource()` `getTypeHierarchy()` has been renamed `getMetaTypes()` The parent child naming was particularly confusing given that the parent/child relationships were inverted from the way that a lot of users think about meta-annotations. For example, a `@RequestMapping` having a parent of `@GetMapping` feels odd given that `@GetMapping` is the thing declaring the meta-annotation relationship. The new method names are designed to align more closely with existing terms. For example, `getMetaSource` hints at the relationship with `isMetaAnnotated` and `getSource`. Closes gh-22946
This commit is contained in:
@@ -41,12 +41,12 @@ abstract class AbstractMergedAnnotation<A extends Annotation> implements MergedA
|
||||
|
||||
@Override
|
||||
public boolean isDirectlyPresent() {
|
||||
return isPresent() && getDepth() == 0;
|
||||
return isPresent() && getDistance() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMetaPresent() {
|
||||
return isPresent() && getDepth() > 0;
|
||||
return isPresent() && getDistance() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -502,7 +502,7 @@ public abstract class AnnotatedElementUtils {
|
||||
|
||||
Adapt[] adaptations = Adapt.values(classValuesAsString, nestedAnnotationsAsMap);
|
||||
return getAnnotations(element).stream(annotationName)
|
||||
.filter(MergedAnnotationPredicates.unique(MergedAnnotation::getTypeHierarchy))
|
||||
.filter(MergedAnnotationPredicates.unique(MergedAnnotation::getMetaTypes))
|
||||
.map(MergedAnnotation::withNonMergedAttributes)
|
||||
.collect(MergedAnnotationCollectors.toMultiValueMap(AnnotatedElementUtils::nullIfEmpty, adaptations));
|
||||
}
|
||||
|
||||
@@ -49,15 +49,15 @@ import org.springframework.util.StringUtils;
|
||||
final class AnnotationTypeMapping {
|
||||
|
||||
@Nullable
|
||||
private final AnnotationTypeMapping parent;
|
||||
private final AnnotationTypeMapping source;
|
||||
|
||||
private final AnnotationTypeMapping root;
|
||||
|
||||
private final int depth;
|
||||
private final int distance;
|
||||
|
||||
private final Class<? extends Annotation> annotationType;
|
||||
|
||||
private final List<Class<? extends Annotation>> annotationTypeHierarchy;
|
||||
private final List<Class<? extends Annotation>> metaTypes;
|
||||
|
||||
@Nullable
|
||||
private final Annotation annotation;
|
||||
@@ -79,15 +79,15 @@ final class AnnotationTypeMapping {
|
||||
private final Set<Method> claimedAliases = new HashSet<>();
|
||||
|
||||
|
||||
AnnotationTypeMapping(@Nullable AnnotationTypeMapping parent,
|
||||
AnnotationTypeMapping(@Nullable AnnotationTypeMapping source,
|
||||
Class<? extends Annotation> annotationType, @Nullable Annotation annotation) {
|
||||
|
||||
this.parent = parent;
|
||||
this.root = (parent != null ? parent.getRoot() : this);
|
||||
this.depth = (parent == null ? 0 : parent.getDepth() + 1);
|
||||
this.source = source;
|
||||
this.root = (source != null ? source.getRoot() : this);
|
||||
this.distance = (source == null ? 0 : source.getDistance() + 1);
|
||||
this.annotationType = annotationType;
|
||||
this.annotationTypeHierarchy = merge(
|
||||
parent != null ? parent.getAnnotationTypeHierarchy() : null,
|
||||
this.metaTypes = merge(
|
||||
source != null ? source.getMetaTypes() : null,
|
||||
annotationType);
|
||||
this.annotation = annotation;
|
||||
this.attributes = AttributeMethods.forAnnotationType(annotationType);
|
||||
@@ -223,7 +223,7 @@ final class AnnotationTypeMapping {
|
||||
aliases.addAll(additional);
|
||||
}
|
||||
}
|
||||
mapping = mapping.parent;
|
||||
mapping = mapping.source;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,7 +250,7 @@ final class AnnotationTypeMapping {
|
||||
}
|
||||
}
|
||||
}
|
||||
mapping = mapping.parent;
|
||||
mapping = mapping.source;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,7 +265,7 @@ final class AnnotationTypeMapping {
|
||||
}
|
||||
|
||||
private void addConventionMappings() {
|
||||
if (this.depth == 0) {
|
||||
if (this.distance == 0) {
|
||||
return;
|
||||
}
|
||||
AttributeMethods rootAttributes = this.root.getAttributes();
|
||||
@@ -290,13 +290,13 @@ final class AnnotationTypeMapping {
|
||||
Method attribute = this.attributes.get(i);
|
||||
boolean isValueAttribute = MergedAnnotation.VALUE.equals(attribute.getName());
|
||||
AnnotationTypeMapping mapping = this;
|
||||
while (mapping != null && mapping.depth > 0) {
|
||||
while (mapping != null && mapping.distance > 0) {
|
||||
int mapped = mapping.getAttributes().indexOf(attribute.getName());
|
||||
if (mapped != -1 && isBetterConventionAnnotationValue(i, isValueAttribute, mapping)) {
|
||||
this.annotationValueMappings[i] = mapped;
|
||||
this.annotationValueSource[i] = mapping;
|
||||
}
|
||||
mapping = mapping.parent;
|
||||
mapping = mapping.source;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -306,8 +306,8 @@ final class AnnotationTypeMapping {
|
||||
if (this.annotationValueMappings[index] == -1) {
|
||||
return true;
|
||||
}
|
||||
int existingDepth = this.annotationValueSource[index].depth;
|
||||
return !isValueAttribute && existingDepth > mapping.depth;
|
||||
int existingDistance = this.annotationValueSource[index].distance;
|
||||
return !isValueAttribute && existingDistance > mapping.distance;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -363,20 +363,20 @@ final class AnnotationTypeMapping {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parent mapping or {@code null}.
|
||||
* @return the parent mapping
|
||||
* Get the source of the mapping or {@code null}.
|
||||
* @return the source of the mapping
|
||||
*/
|
||||
@Nullable
|
||||
AnnotationTypeMapping getParent() {
|
||||
return this.parent;
|
||||
AnnotationTypeMapping getSource() {
|
||||
return this.source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the depth of this mapping.
|
||||
* @return the depth of the mapping
|
||||
* Get the distance of this mapping.
|
||||
* @return the distance of the mapping
|
||||
*/
|
||||
int getDepth() {
|
||||
return this.depth;
|
||||
int getDistance() {
|
||||
return this.distance;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -387,8 +387,8 @@ final class AnnotationTypeMapping {
|
||||
return this.annotationType;
|
||||
}
|
||||
|
||||
List<Class<? extends Annotation>> getAnnotationTypeHierarchy() {
|
||||
return this.annotationTypeHierarchy;
|
||||
List<Class<? extends Annotation>> getMetaTypes() {
|
||||
return this.metaTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -73,38 +73,40 @@ final class AnnotationTypeMappings {
|
||||
}
|
||||
}
|
||||
|
||||
private void addMetaAnnotationsToQueue(Deque<AnnotationTypeMapping> queue, AnnotationTypeMapping parent) {
|
||||
private void addMetaAnnotationsToQueue(Deque<AnnotationTypeMapping> queue, AnnotationTypeMapping source) {
|
||||
Annotation[] metaAnnotations =
|
||||
AnnotationsScanner.getDeclaredAnnotations(parent.getAnnotationType(), false);
|
||||
AnnotationsScanner.getDeclaredAnnotations(source.getAnnotationType(), false);
|
||||
for (Annotation metaAnnotation : metaAnnotations) {
|
||||
if (!isMappable(parent, metaAnnotation)) {
|
||||
if (!isMappable(source, metaAnnotation)) {
|
||||
continue;
|
||||
}
|
||||
Annotation[] repeatedAnnotations = RepeatableContainers.standardRepeatables()
|
||||
.findRepeatedAnnotations(metaAnnotation);
|
||||
if (repeatedAnnotations != null) {
|
||||
for (Annotation repeatedAnnotation : repeatedAnnotations) {
|
||||
if (!isMappable(parent, metaAnnotation)) {
|
||||
if (!isMappable(source, metaAnnotation)) {
|
||||
continue;
|
||||
}
|
||||
addIfPossible(queue, parent, repeatedAnnotation);
|
||||
addIfPossible(queue, source, repeatedAnnotation);
|
||||
}
|
||||
}
|
||||
else {
|
||||
addIfPossible(queue, parent, metaAnnotation);
|
||||
addIfPossible(queue, source, metaAnnotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addIfPossible(Deque<AnnotationTypeMapping> queue, AnnotationTypeMapping parent, Annotation ann) {
|
||||
addIfPossible(queue, parent, ann.annotationType(), ann);
|
||||
private void addIfPossible(Deque<AnnotationTypeMapping> queue,
|
||||
AnnotationTypeMapping source, Annotation ann) {
|
||||
|
||||
addIfPossible(queue, source, ann.annotationType(), ann);
|
||||
}
|
||||
|
||||
private void addIfPossible(Deque<AnnotationTypeMapping> queue, @Nullable AnnotationTypeMapping parent,
|
||||
private void addIfPossible(Deque<AnnotationTypeMapping> queue, @Nullable AnnotationTypeMapping source,
|
||||
Class<? extends Annotation> annotationType, @Nullable Annotation ann) {
|
||||
|
||||
try {
|
||||
queue.addLast(new AnnotationTypeMapping(parent, annotationType, ann));
|
||||
queue.addLast(new AnnotationTypeMapping(source, annotationType, ann));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (ex instanceof AnnotationConfigurationException) {
|
||||
@@ -112,25 +114,25 @@ final class AnnotationTypeMappings {
|
||||
}
|
||||
if (failureLogger.isEnabled()) {
|
||||
failureLogger.log("Failed to introspect meta-annotation " + annotationType.getName(),
|
||||
(parent != null ? parent.getAnnotationType() : null), ex);
|
||||
(source != null ? source.getAnnotationType() : null), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isMappable(AnnotationTypeMapping parent, @Nullable Annotation metaAnnotation) {
|
||||
private boolean isMappable(AnnotationTypeMapping source, @Nullable Annotation metaAnnotation) {
|
||||
return (metaAnnotation != null && !this.filter.matches(metaAnnotation) &&
|
||||
!AnnotationFilter.PLAIN.matches(parent.getAnnotationType()) &&
|
||||
!isAlreadyMapped(parent, metaAnnotation));
|
||||
!AnnotationFilter.PLAIN.matches(source.getAnnotationType()) &&
|
||||
!isAlreadyMapped(source, metaAnnotation));
|
||||
}
|
||||
|
||||
private boolean isAlreadyMapped(AnnotationTypeMapping parent, Annotation metaAnnotation) {
|
||||
private boolean isAlreadyMapped(AnnotationTypeMapping source, Annotation metaAnnotation) {
|
||||
Class<? extends Annotation> annotationType = metaAnnotation.annotationType();
|
||||
AnnotationTypeMapping mapping = parent;
|
||||
AnnotationTypeMapping mapping = source;
|
||||
while (mapping != null) {
|
||||
if (mapping.getAnnotationType() == annotationType) {
|
||||
return true;
|
||||
}
|
||||
mapping = mapping.getParent();
|
||||
mapping = mapping.getSource();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -229,8 +229,8 @@ public abstract class AnnotationUtils {
|
||||
}
|
||||
|
||||
private static <A extends Annotation> boolean isSingleLevelPresent(MergedAnnotation<A> mergedAnnotation) {
|
||||
int depth = mergedAnnotation.getDepth();
|
||||
return (depth == 0 || depth == 1);
|
||||
int distance = mergedAnnotation.getDistance();
|
||||
return (distance == 0 || distance == 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -73,15 +73,6 @@ public interface MergedAnnotation<A extends Annotation> {
|
||||
*/
|
||||
Class<A> getType();
|
||||
|
||||
/**
|
||||
* Return a complete type hierarchy from this annotation to the
|
||||
* {@link #getRoot() root}. Provides a useful way to uniquely identify a
|
||||
* merged annotation instance.
|
||||
* @return the type hierarchy for the annotation
|
||||
* @see MergedAnnotationPredicates#unique(Function)
|
||||
*/
|
||||
List<Class<? extends Annotation>> getTypeHierarchy();
|
||||
|
||||
/**
|
||||
* Determine if the annotation is present on the source. Considers
|
||||
* {@linkplain #isDirectlyPresent() directly present} and
|
||||
@@ -109,14 +100,14 @@ public interface MergedAnnotation<A extends Annotation> {
|
||||
boolean isMetaPresent();
|
||||
|
||||
/**
|
||||
* Get the depth of this annotation related to its use as a
|
||||
* meta-annotation. A directly declared annotation has a depth of {@code 0},
|
||||
* a meta-annotation has a depth of {@code 1}, a meta-annotation on a
|
||||
* meta-annotation has a depth of {@code 2}, etc. A {@linkplain #missing()
|
||||
* missing} annotation will always return a depth of {@code -1}.
|
||||
* @return the annotation depth or {@code -1} if the annotation is missing
|
||||
* Get the distance of this annotation related to its use as a
|
||||
* meta-annotation. A directly declared annotation has a distance of {@code 0},
|
||||
* a meta-annotation has a distance of {@code 1}, a meta-annotation on a
|
||||
* meta-annotation has a distance of {@code 2}, etc. A {@linkplain #missing()
|
||||
* missing} annotation will always return a distance of {@code -1}.
|
||||
* @return the annotation distance or {@code -1} if the annotation is missing
|
||||
*/
|
||||
int getDepth();
|
||||
int getDistance();
|
||||
|
||||
/**
|
||||
* Get the index of the aggregate collection containing this annotation.
|
||||
@@ -130,33 +121,50 @@ public interface MergedAnnotation<A extends Annotation> {
|
||||
int getAggregateIndex();
|
||||
|
||||
/**
|
||||
* Get the source that ultimately declared the annotation, or
|
||||
* Get the source that ultimately declared the root annotation, or
|
||||
* {@code null} if the source is not known. If this merged annotation was
|
||||
* created {@link MergedAnnotations#from(java.lang.reflect.AnnotatedElement)
|
||||
* from} an {@link AnnotatedElement} then this source will be an element of
|
||||
* the same type. If the annotation was loaded without using reflection, the
|
||||
* source can be of any type, but should have a sensible {@code toString()}.
|
||||
* Meta-annotations will return the same source as the {@link #getParent()}.
|
||||
* Meta-annotations will always return the same source as the
|
||||
* {@link #getRoot() root}.
|
||||
* @return the source, or {@code null}
|
||||
*/
|
||||
@Nullable
|
||||
Object getSource();
|
||||
|
||||
/**
|
||||
* Get the parent of the meta-annotation, or {@code null} if the
|
||||
* annotation is not {@linkplain #isMetaPresent() meta-present}.
|
||||
* @return the parent annotation or {@code null}
|
||||
* Get the source of the meta-annotation, or {@code null} if the
|
||||
* annotation is not {@linkplain #isMetaPresent() meta-present}. The
|
||||
* meta-source is the annotation that was meta-annotated with this
|
||||
* annotation.
|
||||
* @return the meta-annotation source or {@code null}
|
||||
* @see #getRoot()
|
||||
*/
|
||||
@Nullable
|
||||
MergedAnnotation<?> getParent();
|
||||
MergedAnnotation<?> getMetaSource();
|
||||
|
||||
/**
|
||||
* Get the root annotation, i.e. the {@link #getDepth() depth} {@code 0}
|
||||
* Get the root annotation, i.e. the {@link #getDistance() distance} {@code 0}
|
||||
* annotation as directly declared on the source.
|
||||
* @return the root annotation
|
||||
* @see #getMetaSource()
|
||||
*/
|
||||
MergedAnnotation<?> getRoot();
|
||||
|
||||
/**
|
||||
* Return the complete list of annotation types from this annotation to the
|
||||
* {@link #getRoot() root}. Provides a useful way to uniquely identify a
|
||||
* merged annotation instance.
|
||||
* @return the meta types for the annotation
|
||||
* @see MergedAnnotationPredicates#unique(Function)
|
||||
* @see #getRoot()
|
||||
* @see #getMetaSource()
|
||||
*/
|
||||
List<Class<? extends Annotation>> getMetaTypes();
|
||||
|
||||
|
||||
/**
|
||||
* Determine if the specified attribute name has a non-default value when
|
||||
* compared to the annotation declaration.
|
||||
@@ -433,7 +441,8 @@ public interface MergedAnnotation<A extends Annotation> {
|
||||
/**
|
||||
* Create a new view of the annotation that exposes non-merged attribute values.
|
||||
* <p>Methods from this view will return attribute values with only alias mirroring
|
||||
* rules applied. Aliases to parent attributes will not be applied.
|
||||
* rules applied. Aliases to {@link #getMetaSource() meta-source} attributes will
|
||||
* not be applied.
|
||||
* @return a non-merged view of the annotation
|
||||
*/
|
||||
MergedAnnotation<A> withNonMergedAttributes();
|
||||
|
||||
@@ -81,8 +81,8 @@ public abstract class MergedAnnotationPredicates {
|
||||
/**
|
||||
* Create a new stateful, single use {@link Predicate} that matches only
|
||||
* the first run of an extracted value. For example,
|
||||
* {@code MergedAnnotationPredicates.firstRunOf(MergedAnnotation::depth)}
|
||||
* will return the first annotation and a subsequent run of the same depth.
|
||||
* {@code MergedAnnotationPredicates.firstRunOf(MergedAnnotation::distance)}
|
||||
* will return the first annotation and a subsequent run of the same distance.
|
||||
* <p>NOTE: This predicate only matches the first first run. Once the extracted
|
||||
* value changes, the predicate always returns {@code false}.
|
||||
* @param valueExtractor function used to extract the value to check
|
||||
|
||||
@@ -40,8 +40,8 @@ public abstract class MergedAnnotationSelectors {
|
||||
|
||||
|
||||
/**
|
||||
* Select the nearest annotation, i.e. the one with the lowest depth.
|
||||
* @return a selector that picks the annotation with the lowest depth
|
||||
* Select the nearest annotation, i.e. the one with the lowest distance.
|
||||
* @return a selector that picks the annotation with the lowest distance
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <A extends Annotation> MergedAnnotationSelector<A> nearest() {
|
||||
@@ -50,7 +50,7 @@ public abstract class MergedAnnotationSelectors {
|
||||
|
||||
/**
|
||||
* Select the first directly declared annotation when possible. If no direct
|
||||
* annotations are declared then the earliest annotation is selected.
|
||||
* annotations are declared then the nearest annotation is selected.
|
||||
* @return a selector that picks the first directly declared annotation whenever possible
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -66,14 +66,14 @@ public abstract class MergedAnnotationSelectors {
|
||||
|
||||
@Override
|
||||
public boolean isBestCandidate(MergedAnnotation<Annotation> annotation) {
|
||||
return annotation.getDepth() == 0;
|
||||
return annotation.getDistance() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MergedAnnotation<Annotation> select(
|
||||
MergedAnnotation<Annotation> existing, MergedAnnotation<Annotation> candidate) {
|
||||
|
||||
if (candidate.getDepth() < existing.getDepth()) {
|
||||
if (candidate.getDistance() < existing.getDistance()) {
|
||||
return candidate;
|
||||
}
|
||||
return existing;
|
||||
@@ -90,14 +90,14 @@ public abstract class MergedAnnotationSelectors {
|
||||
|
||||
@Override
|
||||
public boolean isBestCandidate(MergedAnnotation<Annotation> annotation) {
|
||||
return annotation.getDepth() == 0;
|
||||
return annotation.getDistance() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MergedAnnotation<Annotation> select(
|
||||
MergedAnnotation<Annotation> existing, MergedAnnotation<Annotation> candidate) {
|
||||
|
||||
if (existing.getDepth() > 0 && candidate.getDepth() == 0) {
|
||||
if (existing.getDistance() > 0 && candidate.getDistance() == 0) {
|
||||
return candidate;
|
||||
}
|
||||
return existing;
|
||||
|
||||
@@ -269,7 +269,7 @@ public interface MergedAnnotations extends Iterable<MergedAnnotation<Annotation>
|
||||
* Stream all annotations and meta-annotations contained in this collection.
|
||||
* The resulting stream is ordered first by the
|
||||
* {@linkplain MergedAnnotation#getAggregateIndex() aggregate index} and then
|
||||
* by the annotation depth (with the closest annotations first). This ordering
|
||||
* by the annotation distance (with the closest annotations first). This ordering
|
||||
* means that, for most use-cases, the most suitable annotations appear
|
||||
* earliest in the stream.
|
||||
* @return a stream of annotations
|
||||
|
||||
@@ -233,15 +233,15 @@ final class MergedAnnotationsCollection implements MergedAnnotations {
|
||||
|
||||
@Override
|
||||
public boolean tryAdvance(Consumer<? super MergedAnnotation<A>> action) {
|
||||
int lowestDepth = Integer.MAX_VALUE;
|
||||
int lowestDistance = Integer.MAX_VALUE;
|
||||
int annotationResult = -1;
|
||||
for (int annotationIndex = 0; annotationIndex < annotations.length; annotationIndex++) {
|
||||
AnnotationTypeMapping mapping = getNextSuitableMapping(annotationIndex);
|
||||
if (mapping != null && mapping.getDepth() < lowestDepth) {
|
||||
if (mapping != null && mapping.getDistance() < lowestDistance) {
|
||||
annotationResult = annotationIndex;
|
||||
lowestDepth = mapping.getDepth();
|
||||
lowestDistance = mapping.getDistance();
|
||||
}
|
||||
if (lowestDepth == 0) {
|
||||
if (lowestDistance == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,11 +50,6 @@ final class MissingMergedAnnotation<A extends Annotation> extends AbstractMerged
|
||||
throw new NoSuchElementException("Unable to get type for missing annotation");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Class<? extends Annotation>> getTypeHierarchy() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPresent() {
|
||||
return false;
|
||||
@@ -68,7 +63,7 @@ final class MissingMergedAnnotation<A extends Annotation> extends AbstractMerged
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public MergedAnnotation<?> getParent() {
|
||||
public MergedAnnotation<?> getMetaSource() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -78,7 +73,12 @@ final class MissingMergedAnnotation<A extends Annotation> extends AbstractMerged
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDepth() {
|
||||
public List<Class<? extends Annotation>> getMetaTypes() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDistance() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
|
||||
this.attributeFilter = null;
|
||||
this.resolvedRootMirrors = (resolvedRootMirrors != null ? resolvedRootMirrors :
|
||||
mapping.getRoot().getMirrorSets().resolve(source, rootAttributes, this.valueExtractor));
|
||||
this.resolvedMirrors = (getDepth() == 0 ? this.resolvedRootMirrors :
|
||||
this.resolvedMirrors = (getDistance() == 0 ? this.resolvedRootMirrors :
|
||||
mapping.getMirrorSets().resolve(source, this, this::getValueForMirrorResolution));
|
||||
}
|
||||
|
||||
@@ -165,8 +165,8 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Class<? extends Annotation>> getTypeHierarchy() {
|
||||
return this.mapping.getAnnotationTypeHierarchy();
|
||||
public List<Class<? extends Annotation>> getMetaTypes() {
|
||||
return this.mapping.getMetaTypes();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -175,8 +175,8 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDepth() {
|
||||
return this.mapping.getDepth();
|
||||
public int getDistance() {
|
||||
return this.mapping.getDistance();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -192,23 +192,23 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public MergedAnnotation<?> getParent() {
|
||||
AnnotationTypeMapping parentMapping = this.mapping.getParent();
|
||||
if (parentMapping == null) {
|
||||
public MergedAnnotation<?> getMetaSource() {
|
||||
AnnotationTypeMapping metaSourceMapping = this.mapping.getSource();
|
||||
if (metaSourceMapping == null) {
|
||||
return null;
|
||||
}
|
||||
return new TypeMappedAnnotation<>(parentMapping, this.classLoader, this.source, this.rootAttributes,
|
||||
this.valueExtractor, this.aggregateIndex, this.resolvedRootMirrors);
|
||||
return new TypeMappedAnnotation<>(metaSourceMapping, this.classLoader, this.source,
|
||||
this.rootAttributes, this.valueExtractor, this.aggregateIndex, this.resolvedRootMirrors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MergedAnnotation<?> getRoot() {
|
||||
if (getDepth() == 0) {
|
||||
if (getDistance() == 0) {
|
||||
return this;
|
||||
}
|
||||
AnnotationTypeMapping rootMapping = this.mapping.getRoot();
|
||||
return new TypeMappedAnnotation<>(rootMapping, this.classLoader, this.source, this.rootAttributes,
|
||||
this.valueExtractor, this.aggregateIndex, this.resolvedRootMirrors);
|
||||
return new TypeMappedAnnotation<>(rootMapping, this.classLoader, this.source,
|
||||
this.rootAttributes, this.valueExtractor, this.aggregateIndex, this.resolvedRootMirrors);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -416,14 +416,14 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
|
||||
}
|
||||
}
|
||||
if (!forMirrorResolution) {
|
||||
attributeIndex = (mapping.getDepth() != 0 ?
|
||||
attributeIndex = (mapping.getDistance() != 0 ?
|
||||
this.resolvedMirrors :
|
||||
this.resolvedRootMirrors)[attributeIndex];
|
||||
}
|
||||
if (attributeIndex == -1) {
|
||||
return null;
|
||||
}
|
||||
if (mapping.getDepth() == 0) {
|
||||
if (mapping.getDistance() == 0) {
|
||||
Method attribute = mapping.getAttributes().get(attributeIndex);
|
||||
Object result = this.valueExtractor.apply(attribute, this.rootAttributes);
|
||||
return (result != null) ? result : attribute.getDefaultValue();
|
||||
@@ -672,7 +672,7 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
|
||||
}
|
||||
if (logger.isEnabled()) {
|
||||
String type = mapping.getAnnotationType().getName();
|
||||
String item = (mapping.getDepth() == 0 ? "annotation " + type :
|
||||
String item = (mapping.getDistance() == 0 ? "annotation " + type :
|
||||
"meta-annotation " + type + " from " + mapping.getRoot().getAnnotationType().getName());
|
||||
logger.log("Failed to introspect " + item, source, ex);
|
||||
}
|
||||
|
||||
@@ -542,7 +542,7 @@ final class TypeMappedAnnotations implements MergedAnnotations {
|
||||
|
||||
/**
|
||||
* {@link Spliterator} used to consume merged annotations from the
|
||||
* aggregates in depth fist order.
|
||||
* aggregates in distance fist order.
|
||||
*/
|
||||
private class AggregatesSpliterator<A extends Annotation> implements Spliterator<MergedAnnotation<A>> {
|
||||
|
||||
@@ -578,15 +578,15 @@ final class TypeMappedAnnotations implements MergedAnnotations {
|
||||
if (this.mappingCursors == null) {
|
||||
this.mappingCursors = new int[aggregate.size()];
|
||||
}
|
||||
int lowestDepth = Integer.MAX_VALUE;
|
||||
int lowestDistance = Integer.MAX_VALUE;
|
||||
int annotationResult = -1;
|
||||
for (int annotationIndex = 0; annotationIndex < aggregate.size(); annotationIndex++) {
|
||||
AnnotationTypeMapping mapping = getNextSuitableMapping(aggregate, annotationIndex);
|
||||
if (mapping != null && mapping.getDepth() < lowestDepth) {
|
||||
if (mapping != null && mapping.getDistance() < lowestDistance) {
|
||||
annotationResult = annotationIndex;
|
||||
lowestDepth = mapping.getDepth();
|
||||
lowestDistance = mapping.getDistance();
|
||||
}
|
||||
if (lowestDepth == 0) {
|
||||
if (lowestDistance == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ public interface AnnotatedTypeMetadata {
|
||||
|
||||
Adapt[] adaptations = Adapt.values(classValuesAsString, true);
|
||||
return getAnnotations().stream(annotationName)
|
||||
.filter(MergedAnnotationPredicates.unique(MergedAnnotation::getTypeHierarchy))
|
||||
.filter(MergedAnnotationPredicates.unique(MergedAnnotation::getMetaTypes))
|
||||
.map(MergedAnnotation::withNonMergedAttributes)
|
||||
.collect(MergedAnnotationCollectors.toMultiValueMap(map ->
|
||||
map.isEmpty() ? null : map, adaptations));
|
||||
|
||||
@@ -220,11 +220,11 @@ public class AnnotationTypeMappingsTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDepthReturnsDepth() {
|
||||
public void getDistanceReturnsDistance() {
|
||||
AnnotationTypeMappings mappings = AnnotationTypeMappings.forAnnotationType(
|
||||
Mapped.class);
|
||||
assertThat(mappings.get(0).getDepth()).isEqualTo(0);
|
||||
assertThat(mappings.get(1).getDepth()).isEqualTo(1);
|
||||
assertThat(mappings.get(0).getDistance()).isEqualTo(0);
|
||||
assertThat(mappings.get(1).getDistance()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -236,11 +236,11 @@ public class AnnotationTypeMappingsTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAnnotationTypeHierarchyReturnsTypeHierarchy() {
|
||||
public void getMetaTypeReturnsTypes() {
|
||||
AnnotationTypeMappings mappings = AnnotationTypeMappings.forAnnotationType(
|
||||
ThreeDeepA.class);
|
||||
AnnotationTypeMapping mappingC = mappings.get(2);
|
||||
assertThat(mappingC.getAnnotationTypeHierarchy()).containsExactly(
|
||||
assertThat(mappingC.getMetaTypes()).containsExactly(
|
||||
ThreeDeepA.class, ThreeDeepB.class, ThreeDeepC.class);
|
||||
}
|
||||
|
||||
|
||||
@@ -163,7 +163,7 @@ public class MergedAnnotationsCollectionTests {
|
||||
public void getWithPredicateReturnsOnlyMatching() {
|
||||
MergedAnnotations annotations = getMutiRoute1();
|
||||
assertThat(annotations.get(MutiRouteTarget.class,
|
||||
annotation -> annotation.getDepth() >= 3).getString(
|
||||
annotation -> annotation.getDistance() >= 3).getString(
|
||||
MergedAnnotation.VALUE)).isEqualTo("111");
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ public class MergedAnnotationsCollectionTests {
|
||||
public void getWithSelectorReturnsSelected() {
|
||||
MergedAnnotations annotations = getMutiRoute1();
|
||||
MergedAnnotationSelector<MutiRouteTarget> deepest = (existing,
|
||||
candidate) -> candidate.getDepth() > existing.getDepth() ? candidate
|
||||
candidate) -> candidate.getDistance() > existing.getDistance() ? candidate
|
||||
: existing;
|
||||
assertThat(annotations.get(MutiRouteTarget.class, null, deepest).getString(
|
||||
MergedAnnotation.VALUE)).isEqualTo("111");
|
||||
|
||||
@@ -153,7 +153,7 @@ public class MergedAnnotationsTests {
|
||||
@Test
|
||||
public void getParent() {
|
||||
MergedAnnotations annotations = MergedAnnotations.from(ComposedTransactionalComponentClass.class);
|
||||
assertThat(annotations.get(TransactionalComponent.class).getParent().getType())
|
||||
assertThat(annotations.get(TransactionalComponent.class).getMetaSource().getType())
|
||||
.isEqualTo(ComposedTransactionalComponent.class);
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ public class MergedAnnotationsTests {
|
||||
public void getRootWhenNotDirect() {
|
||||
MergedAnnotations annotations = MergedAnnotations.from(ComposedTransactionalComponentClass.class);
|
||||
MergedAnnotation<?> annotation = annotations.get(TransactionalComponent.class);
|
||||
assertThat(annotation.getDepth()).isGreaterThan(0);
|
||||
assertThat(annotation.getDistance()).isGreaterThan(0);
|
||||
assertThat(annotation.getRoot().getType()).isEqualTo(ComposedTransactionalComponent.class);
|
||||
}
|
||||
|
||||
@@ -169,16 +169,16 @@ public class MergedAnnotationsTests {
|
||||
public void getRootWhenDirect() {
|
||||
MergedAnnotations annotations = MergedAnnotations.from(ComposedTransactionalComponentClass.class);
|
||||
MergedAnnotation<?> annotation = annotations.get(ComposedTransactionalComponent.class);
|
||||
assertThat(annotation.getDepth()).isEqualTo(0);
|
||||
assertThat(annotation.getDistance()).isEqualTo(0);
|
||||
assertThat(annotation.getRoot()).isSameAs(annotation);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTypeHierarchy() {
|
||||
public void getMetaTypes() {
|
||||
MergedAnnotation<?> annotation = MergedAnnotations.from(
|
||||
ComposedTransactionalComponentClass.class).get(
|
||||
TransactionalComponent.class);
|
||||
assertThat(annotation.getTypeHierarchy()).containsExactly(
|
||||
assertThat(annotation.getMetaTypes()).containsExactly(
|
||||
ComposedTransactionalComponent.class, TransactionalComponent.class);
|
||||
}
|
||||
|
||||
@@ -696,30 +696,30 @@ public class MergedAnnotationsTests {
|
||||
public void getFromMethodWithMethodAnnotationOnLeaf() throws Exception {
|
||||
Method method = Leaf.class.getMethod("annotatedOnLeaf");
|
||||
assertThat(method.getAnnotation(Order.class)).isNotNull();
|
||||
assertThat(MergedAnnotations.from(method).get(Order.class).getDepth()).isEqualTo(
|
||||
assertThat(MergedAnnotations.from(method).get(Order.class).getDistance()).isEqualTo(
|
||||
0);
|
||||
assertThat(MergedAnnotations.from(method, SearchStrategy.EXHAUSTIVE).get(
|
||||
Order.class).getDepth()).isEqualTo(0);
|
||||
Order.class).getDistance()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFromMethodWithAnnotationOnMethodInInterface() throws Exception {
|
||||
Method method = Leaf.class.getMethod("fromInterfaceImplementedByRoot");
|
||||
assertThat(method.getAnnotation(Order.class)).isNull();
|
||||
assertThat(MergedAnnotations.from(method).get(Order.class).getDepth()).isEqualTo(
|
||||
assertThat(MergedAnnotations.from(method).get(Order.class).getDistance()).isEqualTo(
|
||||
-1);
|
||||
assertThat(MergedAnnotations.from(method, SearchStrategy.EXHAUSTIVE).get(
|
||||
Order.class).getDepth()).isEqualTo(0);
|
||||
Order.class).getDistance()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFromMethodWithMetaAnnotationOnLeaf() throws Exception {
|
||||
Method method = Leaf.class.getMethod("metaAnnotatedOnLeaf");
|
||||
assertThat(method.getAnnotation(Order.class)).isNull();
|
||||
assertThat(MergedAnnotations.from(method).get(Order.class).getDepth()).isEqualTo(
|
||||
assertThat(MergedAnnotations.from(method).get(Order.class).getDistance()).isEqualTo(
|
||||
1);
|
||||
assertThat(MergedAnnotations.from(method, SearchStrategy.EXHAUSTIVE).get(
|
||||
Order.class).getDepth()).isEqualTo(1);
|
||||
Order.class).getDistance()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -727,50 +727,50 @@ public class MergedAnnotationsTests {
|
||||
Method method = Leaf.class.getMethod("metaMetaAnnotatedOnLeaf");
|
||||
assertThat(method.getAnnotation(Component.class)).isNull();
|
||||
assertThat(
|
||||
MergedAnnotations.from(method).get(Component.class).getDepth()).isEqualTo(
|
||||
MergedAnnotations.from(method).get(Component.class).getDistance()).isEqualTo(
|
||||
2);
|
||||
assertThat(MergedAnnotations.from(method, SearchStrategy.EXHAUSTIVE).get(
|
||||
Component.class).getDepth()).isEqualTo(2);
|
||||
Component.class).getDistance()).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getWithAnnotationOnRoot() throws Exception {
|
||||
Method method = Leaf.class.getMethod("annotatedOnRoot");
|
||||
assertThat(method.getAnnotation(Order.class)).isNotNull();
|
||||
assertThat(MergedAnnotations.from(method).get(Order.class).getDepth()).isEqualTo(
|
||||
assertThat(MergedAnnotations.from(method).get(Order.class).getDistance()).isEqualTo(
|
||||
0);
|
||||
assertThat(MergedAnnotations.from(method, SearchStrategy.EXHAUSTIVE).get(
|
||||
Order.class).getDepth()).isEqualTo(0);
|
||||
Order.class).getDistance()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFromMethodWithMetaAnnotationOnRoot() throws Exception {
|
||||
Method method = Leaf.class.getMethod("metaAnnotatedOnRoot");
|
||||
assertThat(method.getAnnotation(Order.class)).isNull();
|
||||
assertThat(MergedAnnotations.from(method).get(Order.class).getDepth()).isEqualTo(
|
||||
assertThat(MergedAnnotations.from(method).get(Order.class).getDistance()).isEqualTo(
|
||||
1);
|
||||
assertThat(MergedAnnotations.from(method, SearchStrategy.EXHAUSTIVE).get(
|
||||
Order.class).getDepth()).isEqualTo(1);
|
||||
Order.class).getDistance()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFromMethodWithOnRootButOverridden() throws Exception {
|
||||
Method method = Leaf.class.getMethod("overrideWithoutNewAnnotation");
|
||||
assertThat(method.getAnnotation(Order.class)).isNull();
|
||||
assertThat(MergedAnnotations.from(method).get(Order.class).getDepth()).isEqualTo(
|
||||
assertThat(MergedAnnotations.from(method).get(Order.class).getDistance()).isEqualTo(
|
||||
-1);
|
||||
assertThat(MergedAnnotations.from(method, SearchStrategy.EXHAUSTIVE).get(
|
||||
Order.class).getDepth()).isEqualTo(0);
|
||||
Order.class).getDistance()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFromMethodWithNotAnnotated() throws Exception {
|
||||
Method method = Leaf.class.getMethod("notAnnotated");
|
||||
assertThat(method.getAnnotation(Order.class)).isNull();
|
||||
assertThat(MergedAnnotations.from(method).get(Order.class).getDepth()).isEqualTo(
|
||||
assertThat(MergedAnnotations.from(method).get(Order.class).getDistance()).isEqualTo(
|
||||
-1);
|
||||
assertThat(MergedAnnotations.from(method, SearchStrategy.EXHAUSTIVE).get(
|
||||
Order.class).getDepth()).isEqualTo(-1);
|
||||
Order.class).getDistance()).isEqualTo(-1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -779,10 +779,10 @@ public class MergedAnnotationsTests {
|
||||
Object.class);
|
||||
assertThat(method.isBridge()).isTrue();
|
||||
assertThat(method.getAnnotation(Order.class)).isNull();
|
||||
assertThat(MergedAnnotations.from(method).get(Order.class).getDepth()).isEqualTo(
|
||||
assertThat(MergedAnnotations.from(method).get(Order.class).getDistance()).isEqualTo(
|
||||
-1);
|
||||
assertThat(MergedAnnotations.from(method, SearchStrategy.EXHAUSTIVE).get(
|
||||
Order.class).getDepth()).isEqualTo(0);
|
||||
Order.class).getDistance()).isEqualTo(0);
|
||||
boolean runningInEclipse = Arrays.stream(
|
||||
new Exception().getStackTrace()).anyMatch(
|
||||
element -> element.getClassName().startsWith("org.eclipse.jdt"));
|
||||
@@ -799,9 +799,9 @@ public class MergedAnnotationsTests {
|
||||
assertThat(method.getAnnotation(Transactional.class)).isNotNull();
|
||||
}
|
||||
assertThat(MergedAnnotations.from(method).get(
|
||||
Transactional.class).getDepth()).isEqualTo(0);
|
||||
Transactional.class).getDistance()).isEqualTo(0);
|
||||
assertThat(MergedAnnotations.from(method, SearchStrategy.EXHAUSTIVE).get(
|
||||
Transactional.class).getDepth()).isEqualTo(0);
|
||||
Transactional.class).getDistance()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -810,22 +810,22 @@ public class MergedAnnotationsTests {
|
||||
String.class);
|
||||
assertThat(method.isBridge()).isFalse();
|
||||
assertThat(method.getAnnotation(Order.class)).isNull();
|
||||
assertThat(MergedAnnotations.from(method).get(Order.class).getDepth()).isEqualTo(
|
||||
assertThat(MergedAnnotations.from(method).get(Order.class).getDistance()).isEqualTo(
|
||||
-1);
|
||||
assertThat(MergedAnnotations.from(method, SearchStrategy.EXHAUSTIVE).get(
|
||||
Order.class).getDepth()).isEqualTo(0);
|
||||
Order.class).getDistance()).isEqualTo(0);
|
||||
assertThat(method.getAnnotation(Transactional.class)).isNotNull();
|
||||
assertThat(MergedAnnotations.from(method).get(
|
||||
Transactional.class).getDepth()).isEqualTo(0);
|
||||
Transactional.class).getDistance()).isEqualTo(0);
|
||||
assertThat(MergedAnnotations.from(method, SearchStrategy.EXHAUSTIVE).get(
|
||||
Transactional.class).getDepth()).isEqualTo(0);
|
||||
Transactional.class).getDistance()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFromMethodWithInterface() throws Exception {
|
||||
Method method = ImplementsInterfaceWithAnnotatedMethod.class.getMethod("foo");
|
||||
assertThat(MergedAnnotations.from(method, SearchStrategy.EXHAUSTIVE).get(
|
||||
Order.class).getDepth()).isEqualTo(0);
|
||||
Order.class).getDistance()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test // SPR-16060
|
||||
@@ -833,7 +833,7 @@ public class MergedAnnotationsTests {
|
||||
Method method = ImplementsInterfaceWithGenericAnnotatedMethod.class.getMethod(
|
||||
"foo", String.class);
|
||||
assertThat(MergedAnnotations.from(method, SearchStrategy.EXHAUSTIVE).get(
|
||||
Order.class).getDepth()).isEqualTo(0);
|
||||
Order.class).getDistance()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test // SPR-17146
|
||||
@@ -841,7 +841,7 @@ public class MergedAnnotationsTests {
|
||||
Method method = ExtendsBaseClassWithGenericAnnotatedMethod.class.getMethod("foo",
|
||||
String.class);
|
||||
assertThat(MergedAnnotations.from(method, SearchStrategy.EXHAUSTIVE).get(
|
||||
Order.class).getDepth()).isEqualTo(0);
|
||||
Order.class).getDistance()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -849,7 +849,7 @@ public class MergedAnnotationsTests {
|
||||
Method method = SubOfImplementsInterfaceWithAnnotatedMethod.class.getMethod(
|
||||
"foo");
|
||||
assertThat(MergedAnnotations.from(method, SearchStrategy.EXHAUSTIVE).get(
|
||||
Order.class).getDepth()).isEqualTo(0);
|
||||
Order.class).getDistance()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -858,7 +858,7 @@ public class MergedAnnotationsTests {
|
||||
Method method = SubOfAbstractImplementsInterfaceWithAnnotatedMethod.class.getMethod(
|
||||
"foo");
|
||||
assertThat(MergedAnnotations.from(method, SearchStrategy.EXHAUSTIVE).get(
|
||||
Order.class).getDepth()).isEqualTo(0);
|
||||
Order.class).getDistance()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -46,8 +46,8 @@ public class MissingMergedAnnotationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTypeHierarchyReturnsEmptyList() {
|
||||
assertThat(this.missing.getTypeHierarchy()).isEmpty();
|
||||
public void MetaTypesReturnsEmptyList() {
|
||||
assertThat(this.missing.getMetaTypes()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -66,8 +66,8 @@ public class MissingMergedAnnotationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDepthReturnsMinusOne() {
|
||||
assertThat(this.missing.getDepth()).isEqualTo(-1);
|
||||
public void getDistanceReturnsMinusOne() {
|
||||
assertThat(this.missing.getDistance()).isEqualTo(-1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -81,8 +81,8 @@ public class MissingMergedAnnotationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getParentReturnsNull() {
|
||||
assertThat(this.missing.getParent()).isNull();
|
||||
public void getMetaSourceReturnsNull() {
|
||||
assertThat(this.missing.getMetaSource()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user