blob: 0d45bc6a7ee84f6c9aa16c6a38d8af6c729f2ea6 [file] [log] [blame]
/*
* 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.CURLY;
import static org.apache.commons.lang3.AnnotationUtilsTest.Stooge.LARRY;
import static org.apache.commons.lang3.AnnotationUtilsTest.Stooge.MOE;
import static org.apache.commons.lang3.AnnotationUtilsTest.Stooge.SHEMP;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
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 java.util.Collection;
import java.util.Map;
import javax.enterprise.util.Nonbinding;
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 }
)
@Blah(foo = 6, bar = "x")
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 }
)
@Blah(foo = 6, bar = "y")
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 }
)
@Blah(foo = 7, bar = "x")
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;
}
@Retention(RUNTIME)
@Target(FIELD)
public @interface Blah {
int foo();
@Nonbinding
String bar();
}
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)));
assertTrue(AnnotationUtils.equals(field2.getAnnotation(TestAnnotation.class), field1.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)));
assertFalse(AnnotationUtils.equals(field3.getAnnotation(TestAnnotation.class), field1.getAnnotation(TestAnnotation.class)));
}
@Test
public void testAnnotationsOfDifferingTypes() {
assertFalse(AnnotationUtils.equals(field1.getAnnotation(TestAnnotation.class), field4.getAnnotation(NestAnnotation.class)));
assertFalse(AnnotationUtils.equals(field4.getAnnotation(NestAnnotation.class), field1.getAnnotation(TestAnnotation.class)));
}
@Test
public void testOneArgNull() {
assertFalse(AnnotationUtils.equals(field1.getAnnotation(TestAnnotation.class), null));
assertFalse(AnnotationUtils.equals(null, field1.getAnnotation(TestAnnotation.class)));
}
@Test
public void testBothArgsNull() {
assertTrue(AnnotationUtils.equals(null, 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()));
}
for (Class<?> type : new Class[] { Object.class, Map.class, Collection.class }) {
assertFalse(AnnotationUtils.isValidAnnotationMemberType(type));
assertFalse(AnnotationUtils.isValidAnnotationMemberType(Array.newInstance(type, 0)
.getClass()));
}
}
@Test(timeout = 666000)
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));
}
@Test(timeout = 666000)
public void testHashCode() throws Exception {
final Test test = getClass().getDeclaredMethod("testHashCode").getAnnotation(Test.class);
assertEquals(test.hashCode(), AnnotationUtils.hashCode(test));
final TestAnnotation testAnnotation1 = field1.getAnnotation(TestAnnotation.class);
assertEquals(testAnnotation1.hashCode(), AnnotationUtils.hashCode(testAnnotation1));
final TestAnnotation testAnnotation3 = field3.getAnnotation(TestAnnotation.class);
assertEquals(testAnnotation3.hashCode(), AnnotationUtils.hashCode(testAnnotation3));
}
@Test(timeout = 666000)
public void testToString() throws Exception {
final Test testAnno = getClass().getDeclaredMethod("testToString")
.getAnnotation(Test.class);
String toString = AnnotationUtils.toString(testAnno);
assertTrue(toString.startsWith("@org.junit.Test("));
assertTrue(toString.endsWith(")"));
assertTrue(toString.contains("expected=class org.junit.Test$None"));
assertTrue(toString.contains("timeout=666000"));
assertTrue(toString.contains(", "));
}
@Test
public void testNonbinding() throws Exception {
Blah blah1 = field1.getAnnotation(Blah.class);
Blah blah2 = field2.getAnnotation(Blah.class);
Blah blah3 = field3.getAnnotation(Blah.class);
assertTrue(AnnotationUtils.equals(blah1, blah2));
assertFalse(AnnotationUtils.equals(blah1, blah3));
}
}