| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.commons.lang3; |
| |
| import static java.lang.annotation.ElementType.FIELD; |
| import static java.lang.annotation.RetentionPolicy.RUNTIME; |
| import static org.apache.commons.lang3.AnnotationUtilsTest.Stooge.*; |
| import static org.junit.Assert.*; |
| |
| import java.lang.annotation.ElementType; |
| import java.lang.annotation.Retention; |
| 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 org.junit.Before; |
| import org.junit.Test; |
| |
| /** |
| * @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 } |
| ) |
| 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 } |
| ) |
| 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 } |
| ) |
| 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 } |
| ) |
| |
| 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(); |
| } |
| |
| public static enum Stooge { |
| MOE, LARRY, CURLY, JOE, SHEMP; |
| } |
| |
| private Field field1; |
| private Field field2; |
| private Field field3; |
| private Field field4; |
| |
| @Before |
| public void setup() throws Exception { |
| field1 = getClass().getDeclaredField("dummy1"); |
| field2 = getClass().getDeclaredField("dummy2"); |
| field3 = getClass().getDeclaredField("dummy3"); |
| field4 = getClass().getDeclaredField("dummy4"); |
| } |
| |
| @Test |
| public void testEquivalence() { |
| 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))); |
| } |
| |
| @Test |
| public void testNonEquivalentAnnotationsOfSameType() { |
| 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))); |
| } |
| |
| @Test |
| public void testOneArgNull() { |
| assertFalse(AnnotationUtils.equals(field1.getAnnotation(TestAnnotation.class), null)); |
| } |
| |
| @Test |
| public void testBothArgsNull() { |
| assertFalse(AnnotationUtils.equals(field1.getAnnotation(TestAnnotation.class), null)); |
| } |
| |
| @Test |
| public void testIsValidAnnotationMemberType() { |
| for (Class<?> type : new Class[] { byte.class, short.class, int.class, char.class, |
| long.class, float.class, double.class, boolean.class, String.class, Class.class, |
| NestAnnotation.class, TestAnnotation.class, Stooge.class, ElementType.class }) { |
| assertTrue(AnnotationUtils.isValidAnnotationMemberType(type)); |
| assertTrue(AnnotationUtils.isValidAnnotationMemberType(Array.newInstance(type, 0) |
| .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)); |
| } |
| } |