camel-issues mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Alex Paransky (JIRA)" <j...@apache.org>
Subject [jira] [Created] (CAMEL-9243) Invocation of Bean fails when Bean extends and abstract which implements the actual method
Date Thu, 22 Oct 2015 17:16:27 GMT
Alex Paransky created CAMEL-9243:
------------------------------------

             Summary: Invocation of Bean fails when Bean extends and abstract which implements
the actual method
                 Key: CAMEL-9243
                 URL: https://issues.apache.org/jira/browse/CAMEL-9243
             Project: Camel
          Issue Type: Bug
          Components: camel-core
    Affects Versions: 2.15.3
            Reporter: Alex Paransky


With the following definition of a Bean:

{code}
    public interface MyBaseInterface {
        @Handler
        String hello(@Body String hi);
    }

    public abstract static class MyAbstractBean implements MyBaseInterface {
        public String hello(@Body String hi) {
            return "Hello " + hi;
        }
        public String doCompute(String input) {
            fail("Should not invoke me");
            return null;
        }
    }

    public static class MyConcreteBean extends MyAbstractBean {
    }

{code}

The following test case will fail to invoke the proper method:

{code}
public class BeanHandlerMethodTest extends ContextTestSupport {

    public void testInterfaceBeanMethod() throws Exception {
        BeanInfo info = new BeanInfo(context, MyConcreteBean.class);

        Exchange exchange = new DefaultExchange(context);
        MyNoDummyBean pojo = new MyNoDummyBean();
        MethodInvocation mi = info.createInvocation(pojo, exchange);
        assertNotNull(mi);
        assertEquals("hello", mi.getMethod().getName());
    }
{code}

The issue is how BeanInfo.introspect determines which methods are available to be invoked.

At line 344, if the class is public, the interface methods are added to the list:

{code}
        if (Modifier.isPublic(clazz.getModifiers())) {
            // add additional interface methods
            List<Method> extraMethods = getInterfaceMethods(clazz);
            for (Method target : extraMethods) {
                for (Method source : methods) {
                    if (ObjectHelper.isOverridingMethod(source, target, false)) {
                        overrides.add(target);
                    }
                }
            }
            // remove all the overrides methods
            extraMethods.removeAll(overrides);
            methods.addAll(extraMethods);
        }
{code}

However, all the methods from the interface are "abstract".  Later, when the real implementation
is encountered as the code crawls up the tree, the abstract method is not replaced:

Line 390:

{code}
        MethodInfo existingMethodInfo = overridesExistingMethod(methodInfo);
        if (existingMethodInfo != null) {
            LOG.trace("This method is already overridden in a subclass, so the method from
the sub class is preferred: {}", existingMethodInfo);
            return existingMethodInfo;
        }
{code}

Finally, during the invocation, the following was added as part of 2.15.3 release:

Line 561:

{code}
        removeAllAbstractMethods(localOperationsWithBody);
        removeAllAbstractMethods(localOperationsWithNoBody);
        removeAllAbstractMethods(localOperationsWithCustomAnnotation);
        removeAllAbstractMethods(localOperationsWithHandlerAnnotation);
{code}

As a result, the abstract method is removed and not invoked.

I think the fix should be to see if the existingMethodInfo references an "abstract' method
and if it does and methodInfo does not, replace the existingMethodInfo with methodInfo in
the collection.

This would preserve the preferences implied with the rest of the code while properly replacing
the abstract method with their proper implementations.




--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Mime
View raw message