Add support for alternatives in Camel CDI test
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/1b89ecd9 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/1b89ecd9 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/1b89ecd9 Branch: refs/heads/master Commit: 1b89ecd902cfce8b8a074580cfec084de8df582d Parents: f547565 Author: Antonin Stefanutti <anto...@stefanutti.fr> Authored: Wed Mar 9 12:19:36 2016 +0100 Committer: Antonin Stefanutti <anto...@stefanutti.fr> Committed: Wed Mar 9 12:40:03 2016 +0100 ---------------------------------------------------------------------- .../camel/test/cdi/AnnotatedDecorator.java | 78 ++++++++++++++++++++ .../test/cdi/AnnotatedMethodDecorator.java | 70 ++++++++++++++++++ .../camel/test/cdi/AnnotatedTypeDecorator.java | 77 +++++++++++++++++++ .../java/org/apache/camel/test/cdi/Beans.java | 73 ++++++++++++++++++ .../camel/test/cdi/CamelCdiDeployment.java | 10 +++ .../camel/test/cdi/CamelCdiTestExtension.java | 71 ++++++++++++++++++ .../apache/camel/test/cdi/PriorityLiteral.java | 38 ++++++++++ 7 files changed, 417 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/1b89ecd9/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/AnnotatedDecorator.java ---------------------------------------------------------------------- diff --git a/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/AnnotatedDecorator.java b/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/AnnotatedDecorator.java new file mode 100644 index 0000000..176f0ae --- /dev/null +++ b/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/AnnotatedDecorator.java @@ -0,0 +1,78 @@ +/** + * 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.camel.test.cdi; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import javax.enterprise.inject.spi.Annotated; + +class AnnotatedDecorator implements Annotated { + + private final Annotated decorated; + + private final Set<Annotation> annotations; + + AnnotatedDecorator(Annotated decorated, Set<Annotation> annotations) { + this.decorated = decorated; + this.annotations = annotations; + } + + @Override + public Type getBaseType() { + return decorated.getBaseType(); + } + + @Override + public Set<Type> getTypeClosure() { + return decorated.getTypeClosure(); + } + + @Override + public <T extends Annotation> T getAnnotation(Class<T> annotationType) { + T annotation = getDecoratingAnnotation(annotationType); + if (annotation != null) { + return annotation; + } else { + return decorated.getAnnotation(annotationType); + } + } + + @Override + public Set<Annotation> getAnnotations() { + Set<Annotation> annotations = new HashSet<>(this.annotations); + annotations.addAll(decorated.getAnnotations()); + return Collections.unmodifiableSet(annotations); + } + + @Override + public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) { + return getDecoratingAnnotation(annotationType) != null || decorated.isAnnotationPresent(annotationType); + } + + @SuppressWarnings("unchecked") + private <T extends Annotation> T getDecoratingAnnotation(Class<T> annotationType) { + for (Annotation annotation : annotations) { + if (annotationType.isAssignableFrom(annotation.annotationType())) { + return (T) annotation; + } + } + return null; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/1b89ecd9/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/AnnotatedMethodDecorator.java ---------------------------------------------------------------------- diff --git a/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/AnnotatedMethodDecorator.java b/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/AnnotatedMethodDecorator.java new file mode 100644 index 0000000..7ca7171 --- /dev/null +++ b/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/AnnotatedMethodDecorator.java @@ -0,0 +1,70 @@ +/** + * 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.camel.test.cdi; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.List; +import javax.enterprise.inject.spi.AnnotatedMethod; +import javax.enterprise.inject.spi.AnnotatedParameter; +import javax.enterprise.inject.spi.AnnotatedType; + +final class AnnotatedMethodDecorator<X> extends AnnotatedDecorator implements AnnotatedMethod<X> { + + private final AnnotatedMethod<X> decoratedMethod; + + AnnotatedMethodDecorator(AnnotatedMethod<X> decoratedMethod, Annotation decoratingAnnotation) { + super(decoratedMethod, Collections.singleton(decoratingAnnotation)); + this.decoratedMethod = decoratedMethod; + } + + @Override + public Method getJavaMember() { + return decoratedMethod.getJavaMember(); + } + + @Override + public boolean isStatic() { + return decoratedMethod.isStatic(); + } + + @Override + public AnnotatedType<X> getDeclaringType() { + return decoratedMethod.getDeclaringType(); + } + + @Override + public List<AnnotatedParameter<X>> getParameters() { + return decoratedMethod.getParameters(); + } + + @Override + public String toString() { + return decoratedMethod.toString(); + } + + @Override + public int hashCode() { + return decoratedMethod.hashCode(); + } + + @Override + public boolean equals(Object object) { + return decoratedMethod.equals(object); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/1b89ecd9/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/AnnotatedTypeDecorator.java ---------------------------------------------------------------------- diff --git a/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/AnnotatedTypeDecorator.java b/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/AnnotatedTypeDecorator.java new file mode 100644 index 0000000..73af50b --- /dev/null +++ b/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/AnnotatedTypeDecorator.java @@ -0,0 +1,77 @@ +/** + * 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.camel.test.cdi; + +import java.lang.annotation.Annotation; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import javax.enterprise.inject.spi.AnnotatedConstructor; +import javax.enterprise.inject.spi.AnnotatedField; +import javax.enterprise.inject.spi.AnnotatedMethod; +import javax.enterprise.inject.spi.AnnotatedType; + +final class AnnotatedTypeDecorator<X> extends AnnotatedDecorator implements AnnotatedType<X> { + + private final AnnotatedType<X> decoratedType; + + private final Set<AnnotatedMethod<? super X>> decoratedMethods; + + AnnotatedTypeDecorator(AnnotatedType<X> decoratedType, Annotation decoratingAnnotation) { + this(decoratedType, decoratingAnnotation, Collections.<AnnotatedMethod<? super X>>emptySet()); + } + + AnnotatedTypeDecorator(AnnotatedType<X> decoratedType, Annotation decoratingAnnotation, Set<AnnotatedMethod<? super X>> decoratedMethods) { + this(decoratedType, Collections.singleton(decoratingAnnotation), decoratedMethods); + } + + AnnotatedTypeDecorator(AnnotatedType<X> decoratedType, Set<AnnotatedMethod<? super X>> decoratedMethods) { + this(decoratedType, Collections.<Annotation>emptySet(), decoratedMethods); + } + + AnnotatedTypeDecorator(AnnotatedType<X> decoratedType, Set<Annotation> decoratingAnnotations, Set<AnnotatedMethod<? super X>> decoratedMethods) { + super(decoratedType, decoratingAnnotations); + this.decoratedType = decoratedType; + this.decoratedMethods = decoratedMethods; + } + + @Override + public Class<X> getJavaClass() { + return decoratedType.getJavaClass(); + } + + @Override + public Set<AnnotatedConstructor<X>> getConstructors() { + return decoratedType.getConstructors(); + } + + @Override + public Set<AnnotatedMethod<? super X>> getMethods() { + Set<AnnotatedMethod<? super X>> methods = new HashSet<>(decoratedType.getMethods()); + for (AnnotatedMethod<? super X> method : decoratedMethods) { + methods.remove(method); + methods.add(method); + } + + return Collections.unmodifiableSet(methods); + } + + @Override + public Set<AnnotatedField<? super X>> getFields() { + return decoratedType.getFields(); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/1b89ecd9/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/Beans.java ---------------------------------------------------------------------- diff --git a/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/Beans.java b/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/Beans.java new file mode 100644 index 0000000..611964a --- /dev/null +++ b/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/Beans.java @@ -0,0 +1,73 @@ +/** + * 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.camel.test.cdi; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation to be used to customise the deployment configured by the {@code CamelCdiRunner}. + * + * @see CamelCdiRunner + */ +@Documented +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface Beans { + + /** + * Returns the list of <a href="http://docs.jboss.org/cdi/spec/1.2/cdi-spec.html#alternatives">alternatives</a> + * to be selected in the application. + * <p/> + * Note that the declared alternatives are globally selected for the entire + * application. For example, if you have the following named bean in your + * application: + * <pre><code> + * {@literal @}Named("foo") + * public class FooBean { + * + * } + * </code></pre> + * + * It can be replaced in your test by declaring the following alternative + * bean: + * <pre><code> + * {@literal @}Alternative + * {@literal @}Named("foo") + * public class AlternativeBean { + * + * } + * </code></pre> + * + * And adding the {@code @Beans} annotation to you test class to activate it: + * <pre><code> + * {@literal @}RunWith(CamelCdiRunner.class) + * {@literal @}Beans(alternatives = AlternativeBean.class) + * public class TestWithAlternative { + * + * } + * </code></pre> + * + * @see javax.enterprise.inject.Alternative + */ + Class<?>[] alternatives() default {}; +} http://git-wip-us.apache.org/repos/asf/camel/blob/1b89ecd9/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/CamelCdiDeployment.java ---------------------------------------------------------------------- diff --git a/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/CamelCdiDeployment.java b/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/CamelCdiDeployment.java index 245c7c7..4142583 100644 --- a/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/CamelCdiDeployment.java +++ b/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/CamelCdiDeployment.java @@ -33,6 +33,7 @@ final class CamelCdiDeployment implements TestRule { CamelCdiDeployment(TestClass test, CamelCdiContext context) { this.context = context; + weld = new Weld() // TODO: check parallel execution .containerId("camel-context-cdi") @@ -41,6 +42,15 @@ final class CamelCdiDeployment implements TestRule { .beanClasses(test.getJavaClass().getDeclaredClasses()) .addBeanClass(test.getJavaClass()) .addExtension(new CdiCamelExtension()); + + if (test.getJavaClass().isAnnotationPresent(Beans.class)) { + Beans beans = test.getJavaClass().getAnnotation(Beans.class); + weld.addExtension(new CamelCdiTestExtension(beans)); + for (Class<?> alternative : beans.alternatives()) { + weld.addBeanClass(alternative) + .addAlternative(alternative); + } + } } @Override http://git-wip-us.apache.org/repos/asf/camel/blob/1b89ecd9/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/CamelCdiTestExtension.java ---------------------------------------------------------------------- diff --git a/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/CamelCdiTestExtension.java b/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/CamelCdiTestExtension.java new file mode 100644 index 0000000..7b7e151 --- /dev/null +++ b/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/CamelCdiTestExtension.java @@ -0,0 +1,71 @@ +/** + * 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.camel.test.cdi; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import javax.enterprise.event.Observes; +import javax.enterprise.inject.Alternative; +import javax.enterprise.inject.spi.AnnotatedMethod; +import javax.enterprise.inject.spi.Extension; +import javax.enterprise.inject.spi.ProcessAnnotatedType; +import javax.enterprise.inject.spi.WithAnnotations; +import javax.interceptor.Interceptor.Priority; + +final class CamelCdiTestExtension implements Extension { + + private final Beans beans; + + CamelCdiTestExtension(Beans beans) { + this.beans = beans; + } + + /** + * Activates the alternatives declared with {@code @Beans} globally for the + * application. + * <p/> + * For every types and every methods of every types declared with + * {@link Beans#alternatives()}, the {@code Priority} annotation is added + * so that the corresponding alternatives are selected globally for the + * entire application. + * + * @see Beans + */ + private <T> void alternatives(@Observes @WithAnnotations(Alternative.class) ProcessAnnotatedType<T> pat) { + if (!Arrays.asList(beans.alternatives()).contains(pat.getAnnotatedType().getJavaClass())) { + // Only select globally the alternatives that are declared with @Beans + return; + } + + Set<AnnotatedMethod<? super T>> methods = new HashSet<>(); + for (AnnotatedMethod<? super T> am : pat.getAnnotatedType().getMethods()) { + if (am.isAnnotationPresent(Alternative.class)) { + methods.add(new AnnotatedMethodDecorator<>(am, PriorityLiteral.of(Priority.APPLICATION))); + } + } + + if (pat.getAnnotatedType().isAnnotationPresent(Alternative.class)) { + pat.setAnnotatedType(new AnnotatedTypeDecorator<>(pat.getAnnotatedType(), + PriorityLiteral.of(Priority.APPLICATION), + methods)); + } else if (!methods.isEmpty()) { + pat.setAnnotatedType(new AnnotatedTypeDecorator<>(pat.getAnnotatedType(), + methods)); + } + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/1b89ecd9/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/PriorityLiteral.java ---------------------------------------------------------------------- diff --git a/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/PriorityLiteral.java b/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/PriorityLiteral.java new file mode 100644 index 0000000..e24ca7b --- /dev/null +++ b/components/camel-test-cdi/src/main/java/org/apache/camel/test/cdi/PriorityLiteral.java @@ -0,0 +1,38 @@ +/** + * 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.camel.test.cdi; + +import javax.annotation.Priority; +import javax.enterprise.util.AnnotationLiteral; + +final class PriorityLiteral extends AnnotationLiteral<Priority> implements Priority { + + private final int priority; + + private PriorityLiteral(int priority) { + this.priority = priority; + } + + static PriorityLiteral of(int priority) { + return new PriorityLiteral(priority); + } + + @Override + public int value() { + return priority; + } +} \ No newline at end of file