blob: 97c0146b25184939b66b9c80c1c38a0fa05c789a [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.xbean.finder;
import junit.framework.TestCase;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* @version $Rev$ $Date$
*/
public class MetaAnnotatedMethodParametersTest extends TestCase {
public void test() throws Exception {
final Class<?>[] classes = new Class[]{Square.class, Circle.class, Triangle.class, Oval.class, Store.class, Farm.class, None.class};
final Map<String, Annotated<Method>> map = new HashMap<String, Annotated<Method>>();
for (Class<?> clazz : classes) {
final MetaAnnotatedClass<?> annotatedClass = new MetaAnnotatedClass(clazz);
for (MetaAnnotatedMethod method : annotatedClass.getMethods()) {
map.put(method.getName(), method);
}
}
// Check the positive scenarios
{
Annotation[] annotations = getAnnotations(map, "circle");
assertTrue(contains(Color.class, annotations));
assertTrue(contains(Red.class, annotations));
assertEquals("white", get(Color.class, annotations).value());
assertEquals(2, annotations.length);
}
{
Annotation[] annotations = getAnnotations(map, "square");
assertTrue(contains(Color.class, annotations));
assertTrue(contains(Red.class, annotations));
assertEquals("red", get(Color.class, annotations).value());
assertEquals(2, annotations.length);
}
{
Annotation[] annotations = getAnnotations(map, "triangle");
assertTrue(contains(Color.class, annotations));
assertTrue(contains(Red.class, annotations));
assertTrue(contains(Crimson.class, annotations));
assertEquals("red", get(Color.class, annotations).value());
assertEquals(3, annotations.length);
}
{ // Circular - Egg wins
Annotation[] annotations = getAnnotations(map, "store");
assertTrue(contains(Color.class, annotations));
assertTrue(contains(Egg.class, annotations));
assertTrue(contains(Chicken.class, annotations));
assertEquals("egg", get(Color.class, annotations).value());
assertEquals(3, annotations.length);
}
{ // Circular - Chicken wins
Annotation[] annotations = getAnnotations(map, "farm");
assertTrue(contains(Color.class, annotations));
assertTrue(contains(Egg.class, annotations));
assertTrue(contains(Chicken.class, annotations));
assertEquals("chicken", get(Color.class, annotations).value());
assertEquals(3, annotations.length);
}
}
private Annotation[] getAnnotations(Map<String, Annotated<Method>> map, String key) {
final MetaAnnotatedMethod method = (MetaAnnotatedMethod) map.get(key);
assertNotNull(method);
return method.getParameterAnnotations()[0];
}
public <T extends Annotation> T get(Class<T> type, Annotation[] annotations) {
for (Annotation annotation : annotations) {
if (annotation.annotationType() == type) return (T) annotation;
}
return null;
}
private boolean contains(Class<? extends Annotation> type, Annotation[] annotations) {
return get(type, annotations) != null;
}
// 100% your own annotations, even the @Metatype annotation
// Any annotation called @Metatype and annotated with itself works
@Metatype
@Retention(RetentionPolicy.RUNTIME)
@Target(ANNOTATION_TYPE)
public @interface Metatype {
}
@Target({PARAMETER})
@Retention(RUNTIME)
public static @interface Color {
String value() default "";
}
@Metatype
@Target({PARAMETER})
@Retention(RUNTIME)
public static @interface Red {
public interface $ {
// one level deep
public void method(
@Red
@Color("red")
Object object);
}
}
@Metatype
@Target({PARAMETER})
@Retention(RUNTIME)
public static @interface Crimson {
public interface $ {
// two levels deep
public void method(
@Crimson
@Red
Object object);
}
}
// Green is intentionally not used in the classes
// passed directly to the finder to ensure that
// the finder is capable of following the path to
// the root annotation even when some of the
// annotations in the path are not strictly part
// of the archive
@Metatype
@Target({PARAMETER})
@Retention(RUNTIME)
public static @interface Green {
public interface $ {
// two levels deep
public void method(
@Green
@Color("green")
Object object);
}
}
@Metatype
@Target({PARAMETER})
@Retention(RUNTIME)
public static @interface DarkGreen {
public interface $ {
public void method(
@DarkGreen
@Green
Object object);
}
}
@Metatype
@Target({PARAMETER})
@Retention(RUNTIME)
public static @interface Forrest {
public interface $ {
public void method(
@Forrest
@DarkGreen
Object object);
}
}
@Metatype
@Target({PARAMETER})
@Retention(RUNTIME)
public static @interface Chicken {
public interface $ {
public void method(
@Chicken
@Color("chicken")
@Egg
Object object);
}
}
@Metatype
@Target({PARAMETER})
@Retention(RUNTIME)
public static @interface Egg {
public interface $ {
public void method(
@Egg
@Color("egg")
@Chicken
Object object);
}
}
public static class Square {
public void square(@Red Object object) {
}
}
public static class Circle {
public void circle(@Red @Color("white") Object object) {
}
}
public static class Triangle {
public void triangle(@Crimson Object object) {
}
}
public static class Oval {
public void oval(@Forrest Object object) {
}
}
// always good to have a fake in there
public static class None {
public void none(Object object) {
}
}
public static class Store {
public void store(@Egg Object object) {
}
}
public static class Farm {
public void farm(@Chicken Object object) {
}
}
}