blob: 28b9401bf1e76b466d3922c4dea1517daeb90b99 [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.*;
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));
}
}