Browse Source

Optimize toString() for synthesized annotations

This commit moves the toString() implementation for synthesized
annotations from TypeMappedAnnotation to
SynthesizedMergedAnnotationInvocationHandler in order to take advantage
of the synthesized annotation attribute value cache introduced in
72b1abd226.

Closes gh-24970
pull/24977/head
Sam Brannen 5 years ago
parent
commit
59ecd4997c
  1. 45
      spring-core/src/main/java/org/springframework/core/annotation/SynthesizedMergedAnnotationInvocationHandler.java
  2. 45
      spring-core/src/main/java/org/springframework/core/annotation/TypeMappedAnnotation.java

45
spring-core/src/main/java/org/springframework/core/annotation/SynthesizedMergedAnnotationInvocationHandler.java

@ -58,6 +58,9 @@ final class SynthesizedMergedAnnotationInvocationHandler<A extends Annotation> i @@ -58,6 +58,9 @@ final class SynthesizedMergedAnnotationInvocationHandler<A extends Annotation> i
@Nullable
private volatile Integer hashCode;
@Nullable
private volatile String string;
private SynthesizedMergedAnnotationInvocationHandler(MergedAnnotation<A> annotation, Class<A> type) {
Assert.notNull(annotation, "MergedAnnotation must not be null");
@ -78,7 +81,7 @@ final class SynthesizedMergedAnnotationInvocationHandler<A extends Annotation> i @@ -78,7 +81,7 @@ final class SynthesizedMergedAnnotationInvocationHandler<A extends Annotation> i
return annotationHashCode();
}
if (ReflectionUtils.isToStringMethod(method)) {
return this.annotation.toString();
return annotationToString();
}
if (isAnnotationTypeMethod(method)) {
return this.type;
@ -171,6 +174,44 @@ final class SynthesizedMergedAnnotationInvocationHandler<A extends Annotation> i @@ -171,6 +174,44 @@ final class SynthesizedMergedAnnotationInvocationHandler<A extends Annotation> i
return value.hashCode();
}
private String annotationToString() {
String string = this.string;
if (string == null) {
StringBuilder builder = new StringBuilder("@").append(this.type.getName()).append("(");
for (int i = 0; i < this.attributes.size(); i++) {
Method attribute = this.attributes.get(i);
if (i > 0) {
builder.append(", ");
}
builder.append(attribute.getName());
builder.append("=");
builder.append(toString(getAttributeValue(attribute)));
}
builder.append(")");
string = builder.toString();
this.string = string;
}
return string;
}
private String toString(Object value) {
if (value instanceof Class) {
return ((Class<?>) value).getName();
}
if (value.getClass().isArray()) {
StringBuilder builder = new StringBuilder("[");
for (int i = 0; i < Array.getLength(value); i++) {
if (i > 0) {
builder.append(", ");
}
builder.append(toString(Array.get(value, i)));
}
builder.append("]");
return builder.toString();
}
return String.valueOf(value);
}
private Object getAttributeValue(Method method) {
Object value = this.valueCache.computeIfAbsent(method.getName(), attributeName -> {
Class<?> type = ClassUtils.resolvePrimitiveIfNecessary(method.getReturnType());
@ -188,7 +229,7 @@ final class SynthesizedMergedAnnotationInvocationHandler<A extends Annotation> i @@ -188,7 +229,7 @@ final class SynthesizedMergedAnnotationInvocationHandler<A extends Annotation> i
}
/**
* Clone the provided array, ensuring that original component type is retained.
* Clone the provided array, ensuring that the original component type is retained.
* @param array the array to clone
*/
private Object cloneArray(Object array) {

45
spring-core/src/main/java/org/springframework/core/annotation/TypeMappedAnnotation.java

@ -110,9 +110,6 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn @@ -110,9 +110,6 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
private final int[] resolvedMirrors;
@Nullable
private String string;
private TypeMappedAnnotation(AnnotationTypeMapping mapping, @Nullable ClassLoader classLoader,
@Nullable Object source, @Nullable Object rootAttributes, ValueExtractor valueExtractor,
@ -346,48 +343,6 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn @@ -346,48 +343,6 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
return this.mapping.isSynthesizable();
}
@Override
public String toString() {
String string = this.string;
if (string == null) {
StringBuilder builder = new StringBuilder();
builder.append("@");
builder.append(getType().getName());
builder.append("(");
for (int i = 0; i < this.mapping.getAttributes().size(); i++) {
Method attribute = this.mapping.getAttributes().get(i);
builder.append(i == 0 ? "" : ", ");
builder.append(attribute.getName());
builder.append("=");
builder.append(toString(getValue(i, Object.class)));
}
builder.append(")");
string = builder.toString();
this.string = string;
}
return string;
}
private Object toString(@Nullable Object value) {
if (value == null) {
return "";
}
if (value instanceof Class) {
return ((Class<?>) value).getName();
}
if (value.getClass().isArray()) {
StringBuilder builder = new StringBuilder();
builder.append("[");
for (int i = 0; i < Array.getLength(value); i++) {
builder.append(i == 0 ? "" : ", ");
builder.append(toString(Array.get(value, i)));
}
builder.append("]");
return builder.toString();
}
return String.valueOf(value);
}
@Override
@Nullable
protected <T> T getAttributeValue(String attributeName, Class<T> type) {

Loading…
Cancel
Save