From da9ebdf72af4a2527255a7f06a65d4ce672af6de Mon Sep 17 00:00:00 2001 From: Matthew Jason Benson Date: Mon, 13 Sep 2010 22:03:12 +0000 Subject: [PATCH] verify that a user-generated annotation which does not directly implement equals() nevertheless compares equivalently to a 'real' annotation git-svn-id: https://svn.apache.org/repos/asf/commons/proper/lang/trunk@996701 13f79535-47bb-0310-9956-ffa450edef68 --- .../commons/lang3/AnnotationUtilsTest.java | 387 +++++------------- 1 file changed, 111 insertions(+), 276 deletions(-) diff --git a/src/test/java/org/apache/commons/lang3/AnnotationUtilsTest.java b/src/test/java/org/apache/commons/lang3/AnnotationUtilsTest.java index d634e1392..ef4f10f73 100644 --- a/src/test/java/org/apache/commons/lang3/AnnotationUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/AnnotationUtilsTest.java @@ -26,6 +26,9 @@ import java.lang.annotation.Target; import java.lang.reflect.Array; import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.Arrays; @@ -36,337 +39,127 @@ * @version $Id$ */ public class AnnotationUtilsTest { - @TestAnnotation( - booleanValue = false, - booleanValues = { false }, - byteValue = 0, - byteValues = { 0 }, - charValue = 0, - charValues = { 0 }, - doubleValue = 0, - doubleValues = { 0 }, - floatValue = 0, - floatValues = { 0 }, - intValue = 0, - intValues = { 0 }, - longValue = 0, - longValues = { 0 }, - nest = @NestAnnotation( - booleanValue = false, - booleanValues = { false }, - byteValue = 0, - byteValues = { 0 }, - charValue = 0, - charValues = { 0 }, - doubleValue = 0, - doubleValues = { 0 }, - floatValue = 0, - floatValues = { 0 }, - intValue = 0, - intValues = { 0 }, - longValue = 0, - longValues = { 0 }, - shortValue = 0, - shortValues = { 0 }, - stooge = CURLY, - stooges = { MOE, LARRY, SHEMP }, - string = "", - strings = { "" }, - type = Object.class, - types = { Object.class } - ), - nests = { - @NestAnnotation( - booleanValue = false, - booleanValues = { false }, - byteValue = 0, - byteValues = { 0 }, - charValue = 0, - charValues = { 0 }, - doubleValue = 0, - doubleValues = { 0 }, - floatValue = 0, - floatValues = { 0 }, - intValue = 0, - intValues = { 0 }, - longValue = 0, - longValues = { 0 }, - shortValue = 0, - shortValues = { 0 }, - stooge = CURLY, - stooges = { MOE, LARRY, SHEMP }, - string = "", - strings = { "" }, - type = Object[].class, - types = { Object[].class } - ) - }, - shortValue = 0, - shortValues = { 0 }, - stooge = SHEMP, - stooges = { MOE, LARRY, CURLY }, - string = "", - strings = { "" }, - type = Object.class, - types = { Object.class } - ) + @TestAnnotation(booleanValue = false, booleanValues = { false }, byteValue = 0, byteValues = { 0 }, charValue = 0, charValues = { 0 }, doubleValue = 0, doubleValues = { 0 }, floatValue = 0, floatValues = { 0 }, intValue = 0, intValues = { 0 }, longValue = 0, longValues = { 0 }, nest = @NestAnnotation(booleanValue = false, booleanValues = { false }, byteValue = 0, byteValues = { 0 }, charValue = 0, charValues = { 0 }, doubleValue = 0, doubleValues = { 0 }, floatValue = 0, floatValues = { 0 }, intValue = 0, intValues = { 0 }, longValue = 0, longValues = { 0 }, shortValue = 0, shortValues = { 0 }, stooge = CURLY, stooges = { + MOE, LARRY, SHEMP }, string = "", strings = { "" }, type = Object.class, types = { Object.class }), nests = { @NestAnnotation(booleanValue = false, booleanValues = { false }, byteValue = 0, byteValues = { 0 }, charValue = 0, charValues = { 0 }, doubleValue = 0, doubleValues = { 0 }, floatValue = 0, floatValues = { 0 }, intValue = 0, intValues = { 0 }, longValue = 0, longValues = { 0 }, shortValue = 0, shortValues = { 0 }, stooge = CURLY, stooges = { + MOE, LARRY, SHEMP }, string = "", strings = { "" }, type = Object[].class, types = { Object[].class }) }, shortValue = 0, shortValues = { 0 }, stooge = SHEMP, stooges = { + MOE, LARRY, CURLY }, string = "", strings = { "" }, type = Object.class, types = { Object.class }) public Object dummy1; - @TestAnnotation( - booleanValue = false, - booleanValues = { false }, - byteValue = 0, - byteValues = { 0 }, - charValue = 0, - charValues = { 0 }, - doubleValue = 0, - doubleValues = { 0 }, - floatValue = 0, - floatValues = { 0 }, - intValue = 0, - intValues = { 0 }, - longValue = 0, - longValues = { 0 }, - nest = @NestAnnotation( - booleanValue = false, - booleanValues = { false }, - byteValue = 0, - byteValues = { 0 }, - charValue = 0, - charValues = { 0 }, - doubleValue = 0, - doubleValues = { 0 }, - floatValue = 0, - floatValues = { 0 }, - intValue = 0, - intValues = { 0 }, - longValue = 0, - longValues = { 0 }, - shortValue = 0, - shortValues = { 0 }, - stooge = CURLY, - stooges = { MOE, LARRY, SHEMP }, - string = "", - strings = { "" }, - type = Object.class, - types = { Object.class } - ), - nests = { - @NestAnnotation( - booleanValue = false, - booleanValues = { false }, - byteValue = 0, - byteValues = { 0 }, - charValue = 0, - charValues = { 0 }, - doubleValue = 0, - doubleValues = { 0 }, - floatValue = 0, - floatValues = { 0 }, - intValue = 0, - intValues = { 0 }, - longValue = 0, - longValues = { 0 }, - shortValue = 0, - shortValues = { 0 }, - stooge = CURLY, - stooges = { MOE, LARRY, SHEMP }, - string = "", - strings = { "" }, - type = Object[].class, - types = { Object[].class } - ) - }, - shortValue = 0, - shortValues = { 0 }, - stooge = SHEMP, - stooges = { MOE, LARRY, CURLY }, - string = "", - strings = { "" }, - type = Object.class, - types = { Object.class } - ) + @TestAnnotation(booleanValue = false, booleanValues = { false }, byteValue = 0, byteValues = { 0 }, charValue = 0, charValues = { 0 }, doubleValue = 0, doubleValues = { 0 }, floatValue = 0, floatValues = { 0 }, intValue = 0, intValues = { 0 }, longValue = 0, longValues = { 0 }, nest = @NestAnnotation(booleanValue = false, booleanValues = { false }, byteValue = 0, byteValues = { 0 }, charValue = 0, charValues = { 0 }, doubleValue = 0, doubleValues = { 0 }, floatValue = 0, floatValues = { 0 }, intValue = 0, intValues = { 0 }, longValue = 0, longValues = { 0 }, shortValue = 0, shortValues = { 0 }, stooge = CURLY, stooges = { + MOE, LARRY, SHEMP }, string = "", strings = { "" }, type = Object.class, types = { Object.class }), nests = { @NestAnnotation(booleanValue = false, booleanValues = { false }, byteValue = 0, byteValues = { 0 }, charValue = 0, charValues = { 0 }, doubleValue = 0, doubleValues = { 0 }, floatValue = 0, floatValues = { 0 }, intValue = 0, intValues = { 0 }, longValue = 0, longValues = { 0 }, shortValue = 0, shortValues = { 0 }, stooge = CURLY, stooges = { + MOE, LARRY, SHEMP }, string = "", strings = { "" }, type = Object[].class, types = { Object[].class }) }, shortValue = 0, shortValues = { 0 }, stooge = SHEMP, stooges = { + MOE, LARRY, CURLY }, string = "", strings = { "" }, type = Object.class, types = { Object.class }) public Object dummy2; - @TestAnnotation( - booleanValue = false, - booleanValues = { false }, - byteValue = 0, - byteValues = { 0 }, - charValue = 0, - charValues = { 0 }, - doubleValue = 0, - doubleValues = { 0 }, - floatValue = 0, - floatValues = { 0 }, - intValue = 0, - intValues = { 0 }, - longValue = 0, - longValues = { 0 }, - nest = @NestAnnotation( - booleanValue = false, - booleanValues = { false }, - byteValue = 0, - byteValues = { 0 }, - charValue = 0, - charValues = { 0 }, - doubleValue = 0, - doubleValues = { 0 }, - floatValue = 0, - floatValues = { 0 }, - intValue = 0, - intValues = { 0 }, - longValue = 0, - longValues = { 0 }, - shortValue = 0, - shortValues = { 0 }, - stooge = CURLY, - stooges = { MOE, LARRY, SHEMP }, - string = "", - strings = { "" }, - type = Object.class, - types = { Object.class } - ), - nests = { - @NestAnnotation( - booleanValue = false, - booleanValues = { false }, - byteValue = 0, - byteValues = { 0 }, - charValue = 0, - charValues = { 0 }, - doubleValue = 0, - doubleValues = { 0 }, - floatValue = 0, - floatValues = { 0 }, - intValue = 0, - intValues = { 0 }, - longValue = 0, - longValues = { 0 }, - shortValue = 0, - shortValues = { 0 }, - stooge = CURLY, - stooges = { MOE, LARRY, SHEMP }, - string = "", - strings = { "" }, - type = Object[].class, - types = { Object[].class } - ), - //add a second NestAnnotation to break equality: - @NestAnnotation( - booleanValue = false, - booleanValues = { false }, - byteValue = 0, - byteValues = { 0 }, - charValue = 0, - charValues = { 0 }, - doubleValue = 0, - doubleValues = { 0 }, - floatValue = 0, - floatValues = { 0 }, - intValue = 0, - intValues = { 0 }, - longValue = 0, - longValues = { 0 }, - shortValue = 0, - shortValues = { 0 }, - stooge = CURLY, - stooges = { MOE, LARRY, SHEMP }, - string = "", - strings = { "" }, - type = Object[].class, - types = { Object[].class } - ) - }, - shortValue = 0, - shortValues = { 0 }, - stooge = SHEMP, - stooges = { MOE, LARRY, CURLY }, - string = "", - strings = { "" }, - type = Object.class, - types = { Object.class } - ) + @TestAnnotation(booleanValue = false, booleanValues = { false }, byteValue = 0, byteValues = { 0 }, charValue = 0, charValues = { 0 }, doubleValue = 0, doubleValues = { 0 }, floatValue = 0, floatValues = { 0 }, intValue = 0, intValues = { 0 }, longValue = 0, longValues = { 0 }, nest = @NestAnnotation(booleanValue = false, booleanValues = { false }, byteValue = 0, byteValues = { 0 }, charValue = 0, charValues = { 0 }, doubleValue = 0, doubleValues = { 0 }, floatValue = 0, floatValues = { 0 }, intValue = 0, intValues = { 0 }, longValue = 0, longValues = { 0 }, shortValue = 0, shortValues = { 0 }, stooge = CURLY, stooges = { + MOE, LARRY, SHEMP }, string = "", strings = { "" }, type = Object.class, types = { Object.class }), nests = { + @NestAnnotation(booleanValue = false, booleanValues = { false }, byteValue = 0, byteValues = { 0 }, charValue = 0, charValues = { 0 }, doubleValue = 0, doubleValues = { 0 }, floatValue = 0, floatValues = { 0 }, intValue = 0, intValues = { 0 }, longValue = 0, longValues = { 0 }, shortValue = 0, shortValues = { 0 }, stooge = CURLY, stooges = { + MOE, LARRY, SHEMP }, string = "", strings = { "" }, type = Object[].class, types = { Object[].class }), + //add a second NestAnnotation to break equality: + @NestAnnotation(booleanValue = false, booleanValues = { false }, byteValue = 0, byteValues = { 0 }, charValue = 0, charValues = { 0 }, doubleValue = 0, doubleValues = { 0 }, floatValue = 0, floatValues = { 0 }, intValue = 0, intValues = { 0 }, longValue = 0, longValues = { 0 }, shortValue = 0, shortValues = { 0 }, stooge = CURLY, stooges = { + MOE, LARRY, SHEMP }, string = "", strings = { "" }, type = Object[].class, types = { Object[].class }) }, shortValue = 0, shortValues = { 0 }, stooge = SHEMP, stooges = { + MOE, LARRY, CURLY }, string = "", strings = { "" }, type = Object.class, types = { Object.class }) public Object dummy3; - @NestAnnotation( - booleanValue = false, - booleanValues = { false }, - byteValue = 0, - byteValues = { 0 }, - charValue = 0, - charValues = { 0 }, - doubleValue = 0, - doubleValues = { 0 }, - floatValue = 0, - floatValues = { 0 }, - intValue = 0, - intValues = { 0 }, - longValue = 0, - longValues = { 0 }, - shortValue = 0, - shortValues = { 0 }, - stooge = CURLY, - stooges = { MOE, LARRY, SHEMP }, - string = "", - strings = { "" }, - type = Object[].class, - types = { Object[].class } - ) - + @NestAnnotation(booleanValue = false, booleanValues = { false }, byteValue = 0, byteValues = { 0 }, charValue = 0, charValues = { 0 }, doubleValue = 0, doubleValues = { 0 }, floatValue = 0, floatValues = { 0 }, intValue = 0, intValues = { 0 }, longValue = 0, longValues = { 0 }, shortValue = 0, shortValues = { 0 }, stooge = CURLY, stooges = { + MOE, LARRY, SHEMP }, string = "", strings = { "" }, type = Object[].class, types = { Object[].class }) public Object dummy4; @Target(FIELD) @Retention(RUNTIME) public @interface TestAnnotation { String string(); + String[] strings(); + Class type(); + Class[] types(); + byte byteValue(); + byte[] byteValues(); + short shortValue(); + short[] shortValues(); + int intValue(); + int[] intValues(); + char charValue(); + char[] charValues(); + long longValue(); + long[] longValues(); + float floatValue(); + float[] floatValues(); + double doubleValue(); + double[] doubleValues(); + boolean booleanValue(); + boolean[] booleanValues(); + Stooge stooge(); + Stooge[] stooges(); + NestAnnotation nest(); + NestAnnotation[] nests(); } public @interface NestAnnotation { String string(); + String[] strings(); + Class type(); + Class[] types(); + byte byteValue(); + byte[] byteValues(); + short shortValue(); + short[] shortValues(); + int intValue(); + int[] intValues(); + char charValue(); + char[] charValues(); + long longValue(); + long[] longValues(); + float floatValue(); + float[] floatValues(); + double doubleValue(); + double[] doubleValues(); + boolean booleanValue(); + boolean[] booleanValues(); + Stooge stooge(); + Stooge[] stooges(); } @@ -389,22 +182,26 @@ public void setup() throws Exception { @Test public void testEquivalence() { - assertTrue(AnnotationUtils.equals(field1.getAnnotation(TestAnnotation.class), field2.getAnnotation(TestAnnotation.class))); + assertTrue(AnnotationUtils.equals(field1.getAnnotation(TestAnnotation.class), field2 + .getAnnotation(TestAnnotation.class))); } @Test public void testSameInstance() { - assertTrue(AnnotationUtils.equals(field1.getAnnotation(TestAnnotation.class), field1.getAnnotation(TestAnnotation.class))); + assertTrue(AnnotationUtils.equals(field1.getAnnotation(TestAnnotation.class), field1 + .getAnnotation(TestAnnotation.class))); } @Test public void testNonEquivalentAnnotationsOfSameType() { - assertFalse(AnnotationUtils.equals(field1.getAnnotation(TestAnnotation.class), field3.getAnnotation(TestAnnotation.class))); + assertFalse(AnnotationUtils.equals(field1.getAnnotation(TestAnnotation.class), field3 + .getAnnotation(TestAnnotation.class))); } @Test public void testAnnotationsOfDifferingTypes() { - assertFalse(AnnotationUtils.equals(field1.getAnnotation(TestAnnotation.class), field4.getAnnotation(NestAnnotation.class))); + assertFalse(AnnotationUtils.equals(field1.getAnnotation(TestAnnotation.class), field4 + .getAnnotation(NestAnnotation.class))); } @Test @@ -427,4 +224,42 @@ public void testIsValidAnnotationMemberType() { .getClass())); } } + + @Test(timeout = 666) + public void testGeneratedAnnotationEquivalentToRealAnnotation() throws Exception { + final Test real = getClass().getDeclaredMethod( + "testGeneratedAnnotationEquivalentToRealAnnotation").getAnnotation(Test.class); + + InvocationHandler generatedTestInvocationHandler = new InvocationHandler() { + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if ("equals".equals(method.getName()) && method.getParameterTypes().length == 1) { + return proxy == args[0]; + } + if ("hashCode".equals(method.getName()) && method.getParameterTypes().length == 0) { + return System.identityHashCode(proxy); + } + if ("toString".equals(method.getName()) && method.getParameterTypes().length == 0) { + return "Test proxy"; + } + return method.invoke(real, args); + } + }; + + Test generated = (Test) Proxy.newProxyInstance(Thread.currentThread() + .getContextClassLoader(), new Class[] { Test.class }, + generatedTestInvocationHandler); + assertTrue(real.equals(generated)); + assertFalse(generated.equals(real)); + assertTrue(AnnotationUtils.equals(generated, real)); + assertTrue(AnnotationUtils.equals(real, generated)); + + Test generated2 = (Test) Proxy.newProxyInstance(Thread.currentThread() + .getContextClassLoader(), new Class[] { Test.class }, + generatedTestInvocationHandler); + assertFalse(generated.equals(generated2)); + assertFalse(generated2.equals(generated)); + assertTrue(AnnotationUtils.equals(generated, generated2)); + assertTrue(AnnotationUtils.equals(generated2, generated)); + } }