You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by kr...@apache.org on 2011/06/02 17:06:42 UTC
svn commit: r1130595 - in /camel/trunk/camel-core/src:
main/java/org/apache/camel/component/bean/BeanInfo.java
test/java/org/apache/camel/component/bean/BeanWithAnnotationInheritedTest.java
Author: krasserm
Date: Thu Jun 2 15:06:41 2011
New Revision: 1130595
URL: http://svn.apache.org/viewvc?rev=1130595&view=rev
Log:
Inherit parameter binding annotations from superclasses and interfaces. Closes CAMEL-4040
Added:
camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithAnnotationInheritedTest.java
Modified:
camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanInfo.java
Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanInfo.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanInfo.java?rev=1130595&r1=1130594&r2=1130595&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanInfo.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/BeanInfo.java Thu Jun 2 15:06:41 2011
@@ -289,7 +289,7 @@ public class BeanInfo {
@SuppressWarnings("unchecked")
protected MethodInfo createMethodInfo(Class clazz, Method method) {
Class[] parameterTypes = method.getParameterTypes();
- Annotation[][] parametersAnnotations = method.getParameterAnnotations();
+ List<Annotation>[] parametersAnnotations = collectParameterAnnotations(clazz, method);
List<ParameterInfo> parameters = new ArrayList<ParameterInfo>();
List<ParameterInfo> bodyParameters = new ArrayList<ParameterInfo>();
@@ -302,7 +302,7 @@ public class BeanInfo {
for (int i = 0; i < size; i++) {
Class parameterType = parameterTypes[i];
- Annotation[] parameterAnnotations = parametersAnnotations[i];
+ Annotation[] parameterAnnotations = parametersAnnotations[i].toArray(new Annotation[parametersAnnotations[i].size()]);
Expression expression = createParameterUnmarshalExpression(clazz, method, parameterType, parameterAnnotations);
hasCustomAnnotation |= expression != null;
@@ -338,6 +338,33 @@ public class BeanInfo {
return new MethodInfo(camelContext, clazz, method, parameters, bodyParameters, hasCustomAnnotation, hasHandlerAnnotation);
}
+ protected List<Annotation>[] collectParameterAnnotations(Class<?> c, Method m) {
+ List<Annotation>[] annotations = new List[m.getParameterTypes().length];
+ for (int i = 0; i < annotations.length; i++) {
+ annotations[i] = new ArrayList<Annotation>();
+ }
+ collectParameterAnnotations(c, m, annotations);
+ return annotations;
+ }
+
+ protected void collectParameterAnnotations(Class<?> c, Method m, List<Annotation>[] a) {
+ try {
+ Annotation[][] pa = c.getDeclaredMethod(m.getName(), m.getParameterTypes()).getParameterAnnotations();
+ for (int i = 0; i < pa.length; i++) {
+ a[i].addAll(Arrays.asList(pa[i]));
+ }
+ } catch (NoSuchMethodException e) {
+ // no method with signature of m declared on c
+ }
+ for (Class<?> i : c.getInterfaces()) {
+ collectParameterAnnotations(i, m, a);
+ }
+ if (!c.isInterface() && c.getSuperclass() != Object.class) {
+ collectParameterAnnotations(c.getSuperclass(), m, a);
+ }
+
+ }
+
/**
* Lets try choose one of the available methods to invoke if we can match
* the message body to the body parameter
Added: camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithAnnotationInheritedTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithAnnotationInheritedTest.java?rev=1130595&view=auto
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithAnnotationInheritedTest.java (added)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithAnnotationInheritedTest.java Thu Jun 2 15:06:41 2011
@@ -0,0 +1,148 @@
+/**
+ * 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.component.bean;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+import javax.naming.Context;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Header;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.util.jndi.JndiContext;
+
+/**
+ * Test inheritance of parameter binding annotations from superclasses and
+ * interfaces.
+ */
+public class BeanWithAnnotationInheritedTest extends ContextTestSupport {
+
+ public void testWithAnnotationsFromOneInterface() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:result");
+ mock.expectedBodiesReceived("x1y1");
+ template.requestBody("direct:in1", "whatever");
+ mock.assertIsSatisfied();
+ }
+
+ public void testWithAnnotationsFromTwoInterfaces() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:result");
+ mock.expectedBodiesReceived("x2y2");
+ template.requestBody("direct:in2", "whatever");
+ mock.assertIsSatisfied();
+ }
+
+ public void testWithAnnotationsFromSuperclassAndInterface() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:result");
+ mock.expectedBodiesReceived("x3y3");
+ template.requestBody("direct:in3", "whatever");
+ mock.assertIsSatisfied();
+ }
+
+ public void testWithAnnotationsFromImplementationClassAndInterface() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:result");
+ mock.expectedBodiesReceived("x4y4");
+ template.requestBody("direct:in4", "whatever");
+ mock.assertIsSatisfied();
+ }
+
+ public void testWithAnnotationsFromOneInterfaceInheritedByProxy() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:result");
+ mock.expectedBodiesReceived("x5y5");
+ template.requestBody("direct:in5", "whatever");
+ mock.assertIsSatisfied();
+ }
+
+ protected Context createJndiContext() throws Exception {
+ JndiContext answer = new JndiContext();
+ answer.bind("b", new B());
+ answer.bind("p", Proxy.newProxyInstance(I1.class.getClassLoader(), new Class[]{I1.class}, new InvocationHandler() {
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ if (method.getName().equals("m1")) {
+ return args[0].toString() + args[1].toString();
+ } else {
+ return null;
+ }
+ }
+ }));
+ return answer;
+ }
+
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ public void configure() throws Exception {
+ from("direct:in1")
+ .setHeader("foo", constant("x1"))
+ .setHeader("bar", constant("y1"))
+ .to("bean:b?method=m1")
+ .to("mock:result");
+ from("direct:in2")
+ .setHeader("foo", constant("x2"))
+ .setHeader("bar", constant("y2"))
+ .to("bean:b?method=m2")
+ .to("mock:result");
+ from("direct:in3")
+ .setHeader("foo", constant("x3"))
+ .setHeader("bar", constant("y3"))
+ .to("bean:b?method=m3")
+ .to("mock:result");
+ from("direct:in4")
+ .setHeader("foo", constant("x4"))
+ .setHeader("bar", constant("y4"))
+ .to("bean:b?method=m4")
+ .to("mock:result");
+ from("direct:in5")
+ .setHeader("foo", constant("x5"))
+ .setHeader("bar", constant("y5"))
+ .to("bean:p?method=m1")
+ .to("mock:result");
+ }
+ };
+ }
+
+ private static interface I1 {
+ String m1(@Header("foo")String h1, @Header("bar")String h2);
+ String m2(@Header("foo")String h1, String h2);
+ }
+
+ private static interface I2 {
+ String m2(String h1, @Header("bar")String h2);
+ String m3(@Header("foo")String h1, String h2);
+ String m4(@Header("foo")String h1, String h2);
+ }
+
+ private abstract static class A implements I2 {
+ public String m3(String h1, @Header("bar")String h2) {
+ return h1 + h2;
+ }
+ }
+
+ private static class B extends A implements I1 {
+ public String m1(String h1, String h2) {
+ return h1 + h2;
+ }
+ public String m2(String h1, String h2) {
+ return h1 + h2;
+ }
+ public String m4(String h1, @Header("bar")String h2) {
+ return h1 + h2;
+ }
+ }
+}