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
This commit is contained in:
parent
db45b80b1f
commit
59ecd4997c
|
@ -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
|
|||
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
|
|||
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
|
|||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
|
|
|
@ -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
|
|||
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…
Reference in New Issue