You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@camel.apache.org by "Christian Schubert-Huff (Jira)" <ji...@apache.org> on 2023/01/06 09:43:00 UTC

[jira] [Created] (CAMEL-18865) camel-main - Setters not invoked on bean that implements Map

Christian Schubert-Huff created CAMEL-18865:
-----------------------------------------------

             Summary: camel-main - Setters not invoked on bean that implements Map
                 Key: CAMEL-18865
                 URL: https://issues.apache.org/jira/browse/CAMEL-18865
             Project: Camel
          Issue Type: Bug
          Components: camel-main
    Affects Versions: 3.20.0
         Environment: jdk11, camel-main, camel-jms, IBM-MQ 9.2 (https://mvnrepository.com/artifact/com.ibm.mq/com.ibm.mq.allclient)
            Reporter: Christian Schubert-Huff


We are having trouble configuring camel-jms with IBM-MQ as runtime implementation, using camel-main.

Doing so requires the declaration of a connection factory, which, in our case, is [com.ibm.mq.jms.MQConnectionFactory|https://www.ibm.com/docs/api/v1/content/SSFKSJ_9.2.0/com.ibm.mq.javadoc.doc/WMQJMSClasses/com/ibm/mq/jms/MQConnectionFactory.html]. Unfortunately, this class implements both {{javax.jms.ConnectionFactory}} and {{{}java.util.Map<java.lang.String,java.lang.Object>{}}}. Also, the setters of that class have side effects, that are non-trivial to reproduce.

What was really troubling us was that, contrary to intuition, defining a bean like this:
{code:java}
camel.beans.mqConnectionFactory = #class:com.ibm.mq.jms.MQConnectionFactory
camel.beans.mqConnectionFactory.hostName = mqhost
{code}
does not actually invoke the setHostName method on the factory. Instead, value "mqhost" is put under key "hostName" into the map.

Reproduction can be achieved with a quick custom class, like this:
{code:java}
package org.apache.camel.main;

import java.util.HashMap;

public class MyFooFactory extends HashMap<String, Object> {
    private String hostName;

    public String getHostName() {
        return hostName;
    }

    public void setHostName(String hostName) {
        this.hostName = hostName;
    }
}
{code}
and a unit test, which checks for the hostName:
{code:java}
    @Test
    public void testBindBeansDottedHybridMap() {
        Main main = new Main();
        main.configure().addRoutesBuilder(new MyRouteBuilder());

        // defining a factory bean
        main.addProperty("camel.beans.myfactory", "#class:org.apache.camel.main.MyFooFactory");
        main.addProperty("camel.beans.myfactory.hostName", "localhost");
        main.start();

        CamelContext camelContext = main.getCamelContext();
        assertNotNull(camelContext);

        Object bean = camelContext.getRegistry().lookupByName("myfactory");
        assertNotNull(bean);
        assertInstanceOf(MyFooFactory.class, bean);

        MyFooFactory factory = (MyFooFactory) bean;
        assertEquals("localhost", factory.getHostName());

        main.stop();
    }
{code}
For a custom bean that is under our own control, I would consider implementing java.util.Map and having additional custom getters and setters with side-effects to be invalid, but the IBM-MQ JMS client is out of our control - and required for our use case.

If the dotted annotation is used, it may be preferable to check for a suitable setter first, and only if that is missing, to check if the bean implements java.util.Map.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)