-1

I have built an application base on Spring Integration (version 4.2.3.RELEASE) which consumes JMS message from ActiveMQ (5.14.0) topic. There are thousands of messages sent to this topic everyday but only a few (about 20) messages are moved to ActiveMQ.DLQ (Dead Letter Queue) due to NullPointerException. Since the exception is not thrown certainly, I need some suggestions.

The spring context configuration as following.

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:int="http://www.springframework.org/schema/integration"
       xmlns:jms="http://www.springframework.org/schema/jms"
       xmlns:int-jms="http://www.springframework.org/schema/integration/jms"
       xmlns:int-http="http://www.springframework.org/schema/integration/http"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/jms
                           http://www.springframework.org/schema/jms/spring-jms.xsd
                           http://www.springframework.org/schema/integration
                           http://www.springframework.org/schema/integration/spring-integration-4.2.xsd
                           http://www.springframework.org/schema/integration/http
                           http://www.springframework.org/schema/integration/http/spring-integration-http-4.2.xsd
                           http://www.springframework.org/schema/integration/jms
                           http://www.springframework.org/schema/integration/jms/spring-integration-jms-4.2.xsd">

  <context:property-placeholder location="classpath:data-share-healthcloud.properties"/>

  <bean id="connectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop">
    <property name="connectionFactory">
      <bean class="org.apache.activemq.ActiveMQConnectionFactory">
        <property name="brokerURL">
          <value>${jms.activemq.broker.url}</value>
        </property>
        <property name="trustedPackages">
          <list>
            <value>java.util</value>
            <value>java.sql</value>
            <value>com.wd.fw.health.platform.message</value>
            <value>com.wd.fw.health.platform.domain</value>
          </list>
        </property>
      </bean>
    </property>
  </bean>

  <bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
    <constructor-arg>
      <bean class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
        <constructor-arg>
          <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
            <property name="targetClass" value="org.apache.http.impl.client.HttpClients"/>
            <property name="targetMethod" value="createMinimal"/>
          </bean>
        </constructor-arg>
        <property name="connectTimeout" value="${health.cloud.request.timeout}" />
        <property name="readTimeout" value="${health.cloud.request.timeout}" />
      </bean>
    </constructor-arg>
    <property name="messageConverters">
      <list>
        <bean class="org.springframework.http.converter.StringHttpMessageConverter" />
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
        <bean class="org.springframework.http.converter.FormHttpMessageConverter">
        </bean>
      </list>
    </property>
  </bean>

  <bean id="objectMapper" class="org.springframework.integration.support.json.Jackson2JsonObjectMapper">
    <constructor-arg ref="jacksonObjectMapper" />
  </bean>
  <bean id="jacksonObjectMapper" class="com.fasterxml.jackson.databind.ObjectMapper" >
    <property name="dateFormat">
      <bean class="java.text.SimpleDateFormat">
        <constructor-arg index="0" type="java.lang.String" value="yyyy-MM-dd HH:mm:ss" />
      </bean>
    </property>
    <property name="serializationInclusion" value="#{ T(com.fasterxml.jackson.annotation.JsonInclude.Include).NON_NULL }" />
  </bean>
  <bean class="org.springframework.beans.factory.config.MethodInvokingBean">
    <property name="targetObject" ref="jacksonObjectMapper"/>
    <property name="targetMethod" value="disable"/>
    <property name="arguments" value="#{ T(com.fasterxml.jackson.databind.DeserializationFeature).FAIL_ON_UNKNOWN_PROPERTIES }"/>
  </bean>
  <bean class="org.springframework.beans.factory.config.MethodInvokingBean">
    <property name="targetObject" ref="jacksonObjectMapper"/>
    <property name="targetMethod" value="enable"/>
    <property name="arguments" value="#{ T(com.fasterxml.jackson.databind.DeserializationFeature).READ_UNKNOWN_ENUM_VALUES_AS_NULL }"/>
  </bean>

  <bean id="healthCloudTransformer" class="com.wd.fw.health.platform.share.transformer.healthcloud.HealthCloudDtoCheckDataTransformer" />

  <int:annotation-config />
  <int:message-history/>
  <int:logging-channel-adapter id="logger" expression="headers.history" />

  <bean id="headerEnricher" class="org.springframework.integration.transformer.HeaderEnricher" >
    <constructor-arg name="headersToAdd">
      <map>
        <entry key="token">
          <bean class="org.springframework.integration.transformer.support.ExpressionEvaluatingHeaderValueMessageProcessor">
            <constructor-arg name="expressionString" value="'${health.cloud.request.header.token}'" />
            <constructor-arg name="expectedType" value="java.lang.String" />
          </bean>
        </entry>
        <entry key="version">
          <bean class="org.springframework.integration.transformer.support.ExpressionEvaluatingHeaderValueMessageProcessor">
            <constructor-arg name="expressionString" value="${health.cloud.request.header.version}" />
            <constructor-arg name="expectedType" value="java.lang.String" />
          </bean>
        </entry>
        <entry key="Content-Type">
          <bean class="org.springframework.integration.transformer.support.ExpressionEvaluatingHeaderValueMessageProcessor">
            <constructor-arg name="expressionString" value="'application/json'" />
            <constructor-arg name="expectedType" value="java.lang.String" />
          </bean>
        </entry>
      </map>
    </constructor-arg>
  </bean>

  <bean id="headerMapper" class="org.springframework.integration.http.support.DefaultHttpHeaderMapper">
    <property name="outboundHeaderNames" value="HTTP_REQUEST_HEADERS, version, token" />
    <property name="userDefinedHeaderPrefix" value="" />
  </bean>

  <int:handler-retry-advice id="retrier" max-attempts="4" recovery-channel="nullChannel">
    <int:exponential-back-off initial="1000" multiplier="5.0" maximum="60000" />
  </int:handler-retry-advice>

  <!-- Blood Pressure dispatching to health cloud -->
  <int-jms:message-driven-channel-adapter destination-name="#{ T(com.wd.fw.health.platform.common.MessageQueueConstants).JMS_DESTINATION_TOPIC_DATA_BLOOD_PRESSURE }"
                                          pub-sub-domain="true"
                                          subscription-durable="true"
                                          client-id="${jms.topic.client.id}"
                                          subscription-name="#{ T(com.wd.fw.health.platform.common.MessageQueueConstants).JMS_TOPIC_SUBSCRIPTION_BLOOD_PRESSURE }"
                                          acknowledge="transacted"
                                          channel="bloodPressureMessageForwardChannel"
                                          error-channel="nullChannel"
                                          selector="NOT (messageSource = '${jms.topic.message.source}')"/>

  <int:channel id="bloodPressureMessageForwardChannel" />

  <int-jms:outbound-channel-adapter destination-name="#{ T(com.wd.fw.health.platform.share.common.healthcloud.MessageQueueConstants).JMS_DESTINATION_QUEUE_FORWARD_SHARE_HEALTHCLOUD_BLOOD_PRESSURE }"
                                    channel="bloodPressureMessageForwardChannel"
                                    extract-payload="true" />

  <int-jms:message-driven-channel-adapter destination-name="#{ T(com.wd.fw.health.platform.share.common.healthcloud.MessageQueueConstants).JMS_DESTINATION_QUEUE_FORWARD_SHARE_HEALTHCLOUD_BLOOD_PRESSURE }"
                                          acknowledge="transacted"
                                          concurrent-consumers="${jms.queue.concurrent.consumer.count}"
                                          channel="bloodPressureMessageInboundChannel"/>

  <int:channel id="bloodPressureMessageInboundChannel" />

  <int:chain input-channel="bloodPressureMessageInboundChannel">  
    <int:json-to-object-transformer type="com.wd.fw.health.platform.message.BloodPressureCheckDataMessage" object-mapper="objectMapper" />
    <int:transformer ref="healthCloudTransformer" method="transformBloodPressureMessage2Dto" />
    <int:transformer ref="headerEnricher" method="transform" />
    <int-http:outbound-channel-adapter url="http://${health.cloud.server.name}:${health.cloud.server.port}/${health.cloud.data.submit.path}/${health.cloud.data.bloodpressure.resource}"
                                       http-method="POST"
                                       header-mapper="headerMapper"
                                       rest-template="restTemplate"
                                       charset="UTF-8">
      <int-http:request-handler-advice-chain>
        <ref bean="retrier" />
      </int-http:request-handler-advice-chain>
    </int-http:outbound-channel-adapter>
  </int:chain>
</beans>

The NullPointerException as following.

2017-05-22 10:00:18,843 [WARN] [org.springframework.integration.jms.JmsMessageDrivenEndpoint#5.container-1] o.s.j.l.DefaultMessageListenerContainer:936 - Execution of JMS message listener failed, and no ErrorHandler has been set.
org.springframework.integration.transformer.MessageTransformationException: Failed to transform Message; nested exception is org.springframework.messaging.MessageHandlingException: nested exception is java.lang.NullPointerException
        at org.springframework.integration.transformer.MessageTransformingHandler.handleRequestMessage(MessageTransformingHandler.java:95) ~[spring-integration-core-4.2.3.RELEASE.jar:?]
        at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:99) ~[spring-integration-core-4.2.3.RELEASE.jar:?]
        at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127) ~[spring-integration-core-4.2.3.RELEASE.jar:?]
        at org.springframework.integration.handler.MessageHandlerChain$1.send(MessageHandlerChain.java:123) ~[spring-integration-core-4.2.3.RELEASE.jar:?]
        at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115) ~[spring-messaging-4.2.3.RELEASE.jar:4.2.3.RELEASE]
        at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:45) ~[spring-messaging-4.2.3.RELEASE.jar:4.2.3.RELEASE]
        at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:105) ~[spring-messaging-4.2.3.RELEASE.jar:4.2.3.RELEASE]
        at org.springframework.integration.handler.AbstractMessageProducingHandler.sendOutput(AbstractMessageProducingHandler.java:231) ~[spring-integration-core-4.2.3.RELEASE.jar:?]
        at org.springframework.integration.handler.AbstractMessageProducingHandler.produceOutput(AbstractMessageProducingHandler.java:154) ~[spring-integration-core-4.2.3.RELEASE.jar:?]
        at org.springframework.integration.handler.AbstractMessageProducingHandler.sendOutputs(AbstractMessageProducingHandler.java:102) ~[spring-integration-core-4.2.3.RELEASE.jar:?]
        at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:105) ~[spring-integration-core-4.2.3.RELEASE.jar:?]
        at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127) ~[spring-integration-core-4.2.3.RELEASE.jar:?]
        at org.springframework.integration.handler.MessageHandlerChain.handleMessageInternal(MessageHandlerChain.java:104) ~[spring-integration-core-4.2.3.RELEASE.jar:?]
        at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127) ~[spring-integration-core-4.2.3.RELEASE.jar:?]
        at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116) ~[spring-integration-core-4.2.3.RELEASE.jar:?]
        at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:147) ~[spring-integration-core-4.2.3.RELEASE.jar:?]
        at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:120) ~[spring-integration-core-4.2.3.RELEASE.jar:?]
        at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77) ~[spring-integration-core-4.2.3.RELEASE.jar:?]
        at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:442) ~[spring-integration-core-4.2.3.RELEASE.jar:?]
        at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115) ~[spring-messaging-4.2.3.RELEASE.jar:4.2.3.RELEASE]
        at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:45) ~[spring-messaging-4.2.3.RELEASE.jar:4.2.3.RELEASE]
        at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:105) ~[spring-messaging-4.2.3.RELEASE.jar:4.2.3.RELEASE]
        at org.springframework.messaging.core.AbstractMessageSendingTemplate.convertAndSend(AbstractMessageSendingTemplate.java:143) ~[spring-messaging-4.2.3.RELEASE.jar:4.2.3.RELEASE]
        at org.springframework.messaging.core.AbstractMessageSendingTemplate.convertAndSend(AbstractMessageSendingTemplate.java:135) ~[spring-messaging-4.2.3.RELEASE.jar:4.2.3.RELEASE]
        at org.springframework.integration.gateway.MessagingGatewaySupport.send(MessagingGatewaySupport.java:364) ~[spring-integration-core-4.2.3.RELEASE.jar:?]
        at org.springframework.integration.jms.ChannelPublishingJmsMessageListener$GatewayDelegate.send(ChannelPublishingJmsMessageListener.java:504) ~[spring-integration-jms-4.2.3.RELEASE.jar:?]
        at org.springframework.integration.jms.ChannelPublishingJmsMessageListener.onMessage(ChannelPublishingJmsMessageListener.java:338) ~[spring-integration-jms-4.2.3.RELEASE.jar:?]
        at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:721) ~[spring-jms-4.2.3.RELEASE.jar:4.2.3.RELEASE]
        at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:681) [spring-jms-4.2.3.RELEASE.jar:4.2.3.RELEASE]
        at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:651) [spring-jms-4.2.3.RELEASE.jar:4.2.3.RELEASE]
        at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:315) [spring-jms-4.2.3.RELEASE.jar:4.2.3.RELEASE]
        at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:253) [spring-jms-4.2.3.RELEASE.jar:4.2.3.RELEASE]
        at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1150) [spring-jms-4.2.3.RELEASE.jar:4.2.3.RELEASE]
        at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1142) [spring-jms-4.2.3.RELEASE.jar:4.2.3.RELEASE]
        at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:1039) [spring-jms-4.2.3.RELEASE.jar:4.2.3.RELEASE]
        at java.lang.Thread.run(Thread.java:745) [?:1.8.0_91]
Caused by: org.springframework.messaging.MessageHandlingException: nested exception is java.lang.NullPointerException
        at org.springframework.integration.handler.MethodInvokingMessageProcessor.processMessage(MethodInvokingMessageProcessor.java:96) ~[spring-integration-core-4.2.3.RELEASE.jar:?]
        at org.springframework.integration.transformer.AbstractMessageProcessingTransformer.transform(AbstractMessageProcessingTransformer.java:90) ~[spring-integration-core-4.2.3.RELEASE.jar:?]
        at org.springframework.integration.transformer.MessageTransformingHandler.handleRequestMessage(MessageTransformingHandler.java:89) ~[spring-integration-core-4.2.3.RELEASE.jar:?]
        ... 35 more
Caused by: java.lang.NullPointerException

The code block of MethodInvokingMessageProcessor around line 96 as following.

@Override
public T processMessage(Message<?> message) {
    try {
        return delegate.process(message);
    }
    catch (Exception e) {
        throw new MessageHandlingException(message, e);
    }
}

Base on the exception stacktrace, I believe the error occurs while trying to transform as per configuration <int:transformer ref="healthCloudTransformer" method="transformBloodPressureMessage2Dto" /> It seems the delegate is not properly wired for this transformer.

UPDATE: Adding log4j2.xml here but I don't think there is anything special in my configuration.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration name="JmsCentralizedLoggingSystem">
  <Appenders>
    <RollingFile name="RollingFile" fileName="${sys:catalina.base}/logs/${project.name}.log"
      filePattern="${sys:catalina.base}/logs/${project.name}-%i.log.gz" ignoreExceptions="false"
      immediateFlush="false">
      <PatternLayout>
        <Pattern>%d{yyyy-MM-dd HH:mm:ss,SSS} [%p] [%t] %c{1.}:%L - %m%n</Pattern>
      </PatternLayout>
      <Policies>
        <SizeBasedTriggeringPolicy size="50 MB" />
      </Policies>
      <DefaultRolloverStrategy max="100"/>
    </RollingFile>
    <!--
    According to ActiveMQ/AMQ-3879 (https://issues.apache.org/jira/browse/AMQ-3879) issue
    to set 'jms.watchTopicAdvisories' to false in provider URL will disable the advisory messages that a non-durable
    topic subscriber is created to listen to TempTopic and it will stop the server shutting down gracefully.
    -->
    <JMS name="JmsTopic" destinationBindingName="dynamicTopics/topic.logging"
        providerURL="tcp://localhost:61616?jms.watchTopicAdvisories=false"
        factoryName="org.apache.activemq.jndi.ActiveMQInitialContextFactory"
        factoryBindingName="ConnectionFactory"
        ignoreExceptions="false">
      <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
      <PatternLayout>
        <!-- central logging component will handle message time stamp -->
        <Pattern>[${project.name}] [%p] [%t] %c{1.}:%L - %m</Pattern>
      </PatternLayout>
    </JMS>
    <Async name="Async" bufferSize="262144" shutdownTimeout="60000">
      <AppenderRef ref="JmsTopic" />
      <LinkedTransferQueue />
    </Async>
    <Console name="STDOUT" target="SYSTEM_OUT" ignoreExceptions="false">
      <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss,SSS} [${project.name}] [%p] [%t] %c{1.}:%L - %m%n" />
    </Console>
  </Appenders>
  <Loggers>
    <Root level="DEBUG">
      <AppenderRef ref="RollingFile" />
      <AppenderRef ref="Async" />
      <!-- Uncomment standard output when deploy application alone -->
      <!-- <AppenderRef ref="STDOUT" /> -->
    </Root>
  </Loggers>
</Configuration>

UPDATE ONE MORE TIME: Add issue verification code.

public class VerifyFeatureSetting {

    public static void main(String[] args) {
        // String raw =
        // "{\"source\":\"healthdeal\",\"device\":{\"id\":2,\"code\":\"800010\",\"macAddress\":null,\"addressCode\":null},\"person\":{\"identifiers\":[{\"code\":\"310101195612128347\",\"type\":\"Identity\"}],\"localIds\":null,\"addressCode\":null,\"healthDealCustomerId\":0,\"baseapiUuid\":null},\"data\":{\"measureTime\":\"2016-11-24 10:01:00\",\"measurePeriod\":null,\"measureMethod\":\"DeviceMeasure\",\"rawData\":null,\"systolic\":156,\"diastolic\":78,\"pulseRate\":76,\"detectLocation\":\"FeatureDisabled\"}}";
        String raw = "{\"person\":{\"identifiers\":[{\"code\":\"13611777546\",\"type\":\"Other\"}],\"healthDealCustomerId\":0,\"baseapiUuid\":\"1_2_156_210001_1_0_1_1_31053989174895018506437601\"},\"data\":{\"measureTime\":\"2017-05-22 11:02:21\",\"measureMethod\":\"ManualInput\",\"rawData\":\"{\\\"uuid\\\":\\\"1_2_156_210001_3_0_13735353742587810229240801\\\",\\\"residentUuid\\\":\\\"1_2_156_210001_1_0_1_1_31053989174895018506437601\\\",\\\"deviceUuid\\\":null,\\\"deviceCheckLocation\\\":0,\\\"checkTime\\\":\\\"20170522T110221\\\",\\\"createTime\\\":\\\"20170522T110238\\\",\\\"updateTime\\\":\\\"20170522T110238\\\",\\\"isDeleted\\\":false,\\\"errorFlag\\\":false,\\\"inputType\\\":{\\\"code\\\":\\\"01\\\",\\\"display\\\":null,\\\"system\\\":\\\"wdfw-checkinputtype-2014\\\",\\\"systemName\\\":null},\\\"checkLocation\\\":null,\\\"comeFrom\\\":null,\\\"bloodPressure\\\":{\\\"systolic\\\":{\\\"value\\\":0,\\\"unit\\\":\\\"mmHg\\\"},\\\"diastolic\\\":{\\\"value\\\":0,\\\"unit\\\":\\\"mmHg\\\"},\\\"pulseRate\\\":{\\\"value\\\":68,\\\"unit\\\":\\\"times/min\\\"}}}\",\"systolic\":0,\"diastolic\":0,\"pulseRate\":68}}";
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        objectMapper.setSerializationInclusion(Include.NON_NULL);
        objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        objectMapper.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL);

        JsonToObjectTransformer transformer = new JsonToObjectTransformer(BloodPressureCheckDataMessage.class, new Jackson2JsonObjectMapper(objectMapper));
        try {
            objectMapper.readValue(raw, BloodPressureCheckDataMessage.class);
            MessageBuilder<String> builder = MessageBuilder.withPayload(raw);
            Message<?> message = transformer.transform(builder.build());

            BloodPressureDto dto = new VerifyFeatureSetting().transformBloodPressureMessage2Dto(((Message<BloodPressureCheckDataMessage>) message).getPayload());
            System.out.println(dto);
        } catch (JsonParseException e) {
            e.printStackTrace();
        } catch (JsonMappingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public BloodPressureDto transformBloodPressureMessage2Dto(BloodPressureCheckDataMessage message) {
        BloodPressureDto dto = new BloodPressureDto();
        populateMessageCommonIntoDto(message, dto);
        BloodPressureCheckData data = message.getData();
        dto.setSystolic(data.getSystolic());
        dto.setDiastolic(data.getDiastolic());
        dto.setPulse(data.getPulseRate());
        return dto;
    }

    private <T extends AbstractCheckDataBase, S extends AbstractDtoBase> void populateMessageCommonIntoDto(
            CheckDataMessage<T> message, S dto) {

        // set person town
        PersonInfo person = message.getPerson();
        dto.setAddressCode(person.getAddressCode());

        // set identifiers the priority will social security, health insurance,
        // new farming then health care
        // identity will be set separately
        List<PersonalIdentifier> identifiers = person.getIdentifiers();
        for (PersonalIdentifier identifier : identifiers) {
            switch (identifier.getType()) {
            case Identity:
                dto.setPersonIdentity(identifier.getCode());
                break;
            case SocialSecurityCard:
                dto.setIdentifierType(AbstractDtoBase.CARD_TYPE_SOCIAL_SECURITY_CARD);
                dto.setIdentifierNumber(identifier.getCode());
                dto.setSocialSecurityCardNumber(identifier.getCode());
                break;
            case MedicareCard:
                if (!AbstractDtoBase.CARD_TYPE_SOCIAL_SECURITY_CARD.equals(dto.getIdentifierType())) {
                    dto.setIdentifierType(AbstractDtoBase.CARD_TYPE_HEALTH_INSURANCE_CARD);
                    dto.setIdentifierNumber(identifier.getCode());
                }
                dto.setMedicareCardNumber(identifier.getCode());
                break;
            case NewRuralCooperativeMedicalCard:
                if (null == dto.getIdentifierType()) {
                    dto.setIdentifierType(AbstractDtoBase.CARD_TYPE_NEW_FARMING_CARD);
                    dto.setIdentifierNumber(identifier.getCode());
                } else if (!AbstractDtoBase.CARD_TYPE_SOCIAL_SECURITY_CARD.equals(dto.getIdentifierType())
                        || !AbstractDtoBase.CARD_TYPE_HEALTH_INSURANCE_CARD.equals(dto.getIdentifierType())) {
                    dto.setIdentifierType(AbstractDtoBase.CARD_TYPE_HEALTH_INSURANCE_CARD);
                    dto.setIdentifierNumber(identifier.getCode());
                }
                dto.setNewRuralCooperativeMedicalCardNumber(identifier.getCode());
                break;
            default:
                // do nothing
            }
        }

        // set device information
        DeviceInfo device = message.getDevice();
        if (null != device) {
            dto.setDeviceCode(device.getCode());
        }

        // set data relative information
        T data = message.getData();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        dto.setMeasureTime(sdf.format(data.getMeasureTime()));

        // according to health cloud requirement, the field of measure way needs to be set to 2
        // a fixed valued which means data from fullway device
        dto.setMeasureMethod("2");
        dto.setMeasurePeriod(data.getMeasurePeriod());
    }
}
Flik Shen
  • 27
  • 1
  • 10
  • 3
    I think you've chopped off the stack trace too early. There should be some more which will help pinpoint the problem. – Steve Smith May 23 '17 at 08:35
  • This is all I got in log file although the logger level is set to debug. Will it be helpful to set log level to trace? – Flik Shen May 23 '17 at 09:34
  • I don't think so. The last line says "Caused by: java.lang.NullPointerException", but no details about where that came from which is strange. – Steve Smith May 23 '17 at 09:42
  • I've added my log4j2.xml configuration file. Could you please tell me what configuration should be changed to ensure the full stace trace being printed? thx in advance. – Flik Shen May 23 '17 at 10:04
  • @Flik Shen, It appears that your log4j.xml is not printing the `DEBUG` statements, so just cross check the configuration. You might need to add Error Handler to JMS Listener something like this https://stackoverflow.com/questions/8922532/execution-of-jms-message-listener-failed-and-no-errorhandler-has-been-set – Ashok.N May 23 '17 at 10:17
  • @Ashok.N Thank you for you response. The stack trace information comes from RollingFile appender. JMS appender is used for spring integration logging-channel-adapter. – Flik Shen May 23 '17 at 10:27
  • You have to add something like this in your `log4j.xml` to get debug statements ` ` – Ashok.N May 23 '17 at 10:38
  • You can also use wiretap configuration for logging purpose like this :http://docs.spring.io/spring-integration/reference/html/messaging-channels-section.html#channel-wiretap. – Ashok.N May 23 '17 at 10:44
  • BTW, it appears that you have already configured `int:logging-channel-adapter` but you didn't set the logger level to it. One more thing, You search the log file with the word `preSend`. Your `DEBUG` is working fine if you find that word in the log file/console. Else something is wrong with the log4j configuration/your spring-integration configuration – Ashok.N May 23 '17 at 10:50
  • I wonder why don't you think that your `healthCloudTransformer.transformBloodPressureMessage2Dto` produces that `NPE` somehow?.. – Artem Bilan May 23 '17 at 13:14
  • @Ashok.N In the log file preSend, postSend or other equivelant spring integration work flow infrormation make its apparence properly. For example `2017-05-22 10:00:18,800 [DEBUG] [org.springframework.integration.jms.JmsMessageDrivenEndpoint#5.container-1] o.s.i.c.DirectChannel:430 - preSend on channel 'bloodPressureMessageInboundChannel', message: GenericMessage [payload={"person":{"identifiers":[{"code":"211002193211116561","type":"Identity"}]...(truncated)` – Flik Shen May 24 '17 at 02:51
  • Oh, my friend, you have a bad habit! The `error-channel="nullChannel"` is trap for you. Use `errorChannel` instead. That should provide you more info about errors in logs – Artem Bilan May 24 '17 at 03:10
  • @ArtemBilan I agree with you. According to the stack trace hierarchy, I guess if the transformer does not raise NPE the only possibility is delegate is null. But as we know the transformer is more like a utility, I can easily to make an invocation of method `transformBloodPressuresMessage2Dto` with same message payload and I get right result without `NPE`. And the strange as I mentioned in my question is there are thousands of messages sent to this topic everyday but only about 20 messages trigger this issue. Even messages come from same producer does not certainly raise this issue. – Flik Shen May 24 '17 at 03:16
  • @ArtemBilan Does it really matter in this case even the message flows to next process endpoint? Anyway I will try it. – Flik Shen May 24 '17 at 03:24
  • Please read [How do I ask a good question?](http://stackoverflow.com/help/how-to-ask) before attempting to ask more questions. –  May 24 '17 at 04:04
  • [What does your step debugger tell you?](http://stackoverflow.com/questions/25385173/what-is-a-debugger-and-how-can-it-help-me-diagnose-problems) –  May 24 '17 at 04:04

1 Answers1

1

Well, the mentioned component from Spring Integration is there for a while already. So, if that was with such a flaw you mention, you wouldn't be a first reporting that.

I suggest you to wrap your POJO method logic to the try...catch and see what is the reason of NPE in some other component.

You even can send an ErrorMessage with that exception to some channel for analysis.

If we know more about your code, we would help better. Right now your config is good, so nothing to complain about.

Artem Bilan
  • 113,505
  • 11
  • 91
  • 118