提交 def7663e 编写于 作者: S Sam Brannen

Implement hashCode() for synthesized annotations

Issue: SPR-13066
上级 ae5c8285
...@@ -20,6 +20,7 @@ import java.lang.annotation.Annotation; ...@@ -20,6 +20,7 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement; import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
...@@ -70,6 +71,9 @@ class SynthesizedAnnotationInvocationHandler implements InvocationHandler { ...@@ -70,6 +71,9 @@ class SynthesizedAnnotationInvocationHandler implements InvocationHandler {
if (isEqualsMethod(method)) { if (isEqualsMethod(method)) {
return equals(proxy, args[0]); return equals(proxy, args[0]);
} }
if (isHashCodeMethod(method)) {
return hashCode(proxy);
}
if (isToStringMethod(method)) { if (isToStringMethod(method)) {
return toString(proxy); return toString(proxy);
} }
...@@ -137,6 +141,12 @@ class SynthesizedAnnotationInvocationHandler implements InvocationHandler { ...@@ -137,6 +141,12 @@ class SynthesizedAnnotationInvocationHandler implements InvocationHandler {
return value; return value;
} }
/**
* See {@link Annotation#equals(Object)} for a definition of the required algorithm.
*
* @param proxy the synthesized annotation
* @param other the other object to compare against
*/
private boolean equals(Object proxy, Object other) { private boolean equals(Object proxy, Object other) {
if (this == other) { if (this == other) {
return true; return true;
...@@ -156,6 +166,72 @@ class SynthesizedAnnotationInvocationHandler implements InvocationHandler { ...@@ -156,6 +166,72 @@ class SynthesizedAnnotationInvocationHandler implements InvocationHandler {
return true; return true;
} }
/**
* See {@link Annotation#hashCode()} for a definition of the required algorithm.
*
* @param proxy the synthesized annotation
*/
private int hashCode(Object proxy) {
int result = 0;
for (Method attributeMethod : getAttributeMethods(this.annotationType)) {
Object value = invokeMethod(attributeMethod, proxy);
int hashCode;
if (value.getClass().isArray()) {
hashCode = hashCodeForArray(value);
}
else {
hashCode = value.hashCode();
}
result += (127 * attributeMethod.getName().hashCode()) ^ hashCode;
}
return result;
}
/**
* WARNING: we can NOT use any of the {@code nullSafeHashCode()} methods
* in Spring's {@link ObjectUtils} because those hash code generation
* algorithms do not comply with the requirements specified in
* {@link Annotation#hashCode()}.
*
* @param array the array to compute the hash code for
*/
private int hashCodeForArray(Object array) {
if (array instanceof boolean[]) {
return Arrays.hashCode((boolean[]) array);
}
if (array instanceof byte[]) {
return Arrays.hashCode((byte[]) array);
}
if (array instanceof char[]) {
return Arrays.hashCode((char[]) array);
}
if (array instanceof double[]) {
return Arrays.hashCode((double[]) array);
}
if (array instanceof float[]) {
return Arrays.hashCode((float[]) array);
}
if (array instanceof int[]) {
return Arrays.hashCode((int[]) array);
}
if (array instanceof long[]) {
return Arrays.hashCode((long[]) array);
}
if (array instanceof short[]) {
return Arrays.hashCode((short[]) array);
}
// else
return Arrays.hashCode((Object[]) array);
}
/**
* See {@link Annotation#toString()} for guidelines on the recommended format.
*
* @param proxy the synthesized annotation
*/
private String toString(Object proxy) { private String toString(Object proxy) {
StringBuilder sb = new StringBuilder("@").append(annotationType.getName()).append("("); StringBuilder sb = new StringBuilder("@").append(annotationType.getName()).append("(");
......
...@@ -694,6 +694,44 @@ public class AnnotationUtilsTests { ...@@ -694,6 +694,44 @@ public class AnnotationUtilsTests {
assertThat(webMappingWithAliases, is(not(synthesizedWebMapping1))); assertThat(webMappingWithAliases, is(not(synthesizedWebMapping1)));
} }
@Test
public void hashCodeForSynthesizedAnnotations() throws Exception {
Method methodWithPath = WebController.class.getMethod("handleMappedWithPathAttribute");
WebMapping webMappingWithAliases = methodWithPath.getAnnotation(WebMapping.class);
assertNotNull(webMappingWithAliases);
Method methodWithPathAndValue = WebController.class.getMethod("handleMappedWithSamePathAndValueAttributes");
WebMapping webMappingWithPathAndValue = methodWithPathAndValue.getAnnotation(WebMapping.class);
assertNotNull(webMappingWithPathAndValue);
WebMapping synthesizedWebMapping1 = synthesizeAnnotation(webMappingWithAliases);
assertNotNull(synthesizedWebMapping1);
WebMapping synthesizedWebMapping2 = synthesizeAnnotation(webMappingWithAliases);
assertNotNull(synthesizedWebMapping2);
// Equality amongst standard annotations
assertThat(webMappingWithAliases.hashCode(), is(webMappingWithAliases.hashCode()));
assertThat(webMappingWithPathAndValue.hashCode(), is(webMappingWithPathAndValue.hashCode()));
// Inequality amongst standard annotations
assertThat(webMappingWithAliases.hashCode(), is(not(webMappingWithPathAndValue.hashCode())));
assertThat(webMappingWithPathAndValue.hashCode(), is(not(webMappingWithAliases.hashCode())));
// Equality amongst synthesized annotations
assertThat(synthesizedWebMapping1.hashCode(), is(synthesizedWebMapping1.hashCode()));
assertThat(synthesizedWebMapping2.hashCode(), is(synthesizedWebMapping2.hashCode()));
assertThat(synthesizedWebMapping1.hashCode(), is(synthesizedWebMapping2.hashCode()));
assertThat(synthesizedWebMapping2.hashCode(), is(synthesizedWebMapping1.hashCode()));
// Equality between standard and synthesized annotations
assertThat(synthesizedWebMapping1.hashCode(), is(webMappingWithPathAndValue.hashCode()));
assertThat(webMappingWithPathAndValue.hashCode(), is(synthesizedWebMapping1.hashCode()));
// Inequality between standard and synthesized annotations
assertThat(synthesizedWebMapping1.hashCode(), is(not(webMappingWithAliases.hashCode())));
assertThat(webMappingWithAliases.hashCode(), is(not(synthesizedWebMapping1.hashCode())));
}
/** /**
* Fully reflection-based test that verifies support for * Fully reflection-based test that verifies support for
* {@linkplain AnnotationUtils#synthesizeAnnotation synthesizing annotations} * {@linkplain AnnotationUtils#synthesizeAnnotation synthesizing annotations}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册