Note that there are some explanatory texts on larger screens.

plurals
  1. POHow do I load properties with Spring when also using Camel?
    primarykey
    data
    text
    <p>I have a HelloWorld Java project that uses Camel to obtain a Map, and print out its contents in JSON format. The Map currently has hardcoded values, but I really want to change my code so that it uses Spring to load a sensor.properties file of nested key,value pairs into this Map.</p> <p>I have another Java project I wrote that only uses Spring, and can load the sensor.properties file just fine into an Arraylist object.</p> <p>However, when I try to use code from that project to load the sensor.properties in my HelloWorld project I get the following Camel error with a NPE:</p> <pre><code>Returning Map 3310 [hello.world.request.timer] ERROR org.apache.camel.processor.DefaultErrorHandler - Failed delivery for exchangeId: 4e984884-df7f-4b82-a977-f5cf4c311814. Exhausted after delivery attempt: 1 caught: java.lang.NullPointerException java.lang.NullPointerException at sample.SensorGenerator.getSensors(SensorGenerator.java:17) at sample.HelloWorld.returnMap(HelloWorld.java:22) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.apache.camel.component.bean.MethodInfo.invoke(MethodInfo.java:231) at org.apache.camel.component.bean.MethodInfo$1.proceed(MethodInfo.java:146) at org.apache.camel.component.bean.BeanProcessor.process(BeanProcessor.java:138) org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:67) at org.apache.camel.processor.DelegateProcessor.processNext(DelegateProcessor.java:53) at org.apache.camel.processor.DelegateProcessor.proceed(DelegateProcessor.java:82) at org.apache.camel.processor.interceptor.TraceInterceptor.process(TraceInterceptor.java:97) at org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:67) at org.apache.camel.processor.RedeliveryErrorHandler.processExchange(RedeliveryErrorHandler.java:185) at org.apache.camel.processor.RedeliveryErrorHandler.processErrorHandler(RedeliveryErrorHandler.java:151) at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:89) at org.apache.camel.processor.DefaultErrorHandler.process(DefaultErrorHandler.java:49) at org.apache.camel.processor.DefaultChannel.process(DefaultChannel.java:228) at org.apache.camel.processor.Pipeline.process(Pipeline.java:75) at org.apache.camel.processor.UnitOfWorkProcessor.processNext(UnitOfWorkProcessor.java:70) at org.apache.camel.processor.DelegateProcessor.process(DelegateProcessor.java:48) at org. apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:67) at org.apache.camel.component.timer.TimerConsumer.sendTimerExchange(TimerConsumer.java:102) at org.apache.camel.component.timer.TimerConsumer$1.run(TimerConsumer.java:49) at java.util.TimerThread.mainLoop(Timer.java:555) at java.util.TimerThread.run(Timer.java:505) </code></pre> <p>Is there something I need to add to my applicationContext.xml to tell Camel that Spring will load my sensor.properties? Do I need to use the Spring integration component specified at <a href="http://camel.apache.org/springintegration.html" rel="nofollow">http://camel.apache.org/springintegration.html</a> ?</p> <p>Here is my current ApplicationContext.xml:</p> <pre><code> &lt;?xml version="1.0" encoding="UTF-8"?&gt; &lt;beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:camel="http://camel.apache.org/schema/spring" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"&gt; &lt;bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" /&gt; &lt;context:component-scan base-package="sample" /&gt; &lt;context:annotation-config /&gt; &lt;camel:camelContext id="HelloWorldContext"&gt; &lt;!-- Add Jackson library to render Java Map into JSON --&gt; &lt;camel:dataFormats&gt; &lt;camel:json id="jack" library="Jackson"/&gt; &lt;/camel:dataFormats&gt; &lt;camel:route&gt; &lt;!-- sends a request to the hello world JMS queue every 10 seconds --&gt; &lt;camel:from uri="timer://hello.world.request.timer?fixedRate=true&amp;amp;period=10000" /&gt; &lt;camel:to uri="log:hello.world.request?level=INFO?showAll=true" /&gt; &lt;camel:bean ref="helloWorld" /&gt; &lt;!-- now print out the map in JSON format --&gt; &lt;camel:marshal ref ="jack"/&gt; &lt;camel:convertBodyTo type="java.lang.String" /&gt; &lt;camel:log message="${body}"/&gt; &lt;!-- now log the message --&gt; &lt;camel:to uri="log:hello.world.response?level=INFO?showAll=true" /&gt; &lt;/camel:route&gt; &lt;/camel:camelContext&gt; &lt;bean id="jms" class="org.apache.activemq.camel.component.ActiveMQComponent"&gt; &lt;property name="configuration" ref="jmsConfig" /&gt; &lt;/bean&gt; &lt;bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration"&gt; &lt;property name="connectionFactory" ref="jmsConnectionFactory" /&gt; &lt;property name="transacted" value="false" /&gt; &lt;property name="concurrentConsumers" value="1" /&gt; &lt;/bean&gt; &lt;bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"&gt; &lt;property name="brokerURL" value="vm://localhost" /&gt; &lt;property name="redeliveryPolicy" ref="redeliveryPolicy" /&gt; &lt;property name="prefetchPolicy" ref="prefetchPolicy" /&gt; &lt;/bean&gt; &lt;bean id="prefetchPolicy" class="org.apache.activemq.ActiveMQPrefetchPolicy"&gt; &lt;property name="queuePrefetch" value="5" /&gt; &lt;/bean&gt; &lt;bean id="redeliveryPolicy" class="org.apache.activemq.RedeliveryPolicy"&gt; &lt;property name="maximumRedeliveries" value="1" /&gt; &lt;property name="backOffMultiplier" value="2" /&gt; &lt;property name="initialRedeliveryDelay" value="2000" /&gt; &lt;property name="useExponentialBackOff" value="true" /&gt; &lt;/bean&gt; &lt;!-- creates a java.util.Properties instance with values loaded from the supplied location --&gt; &lt;util:properties id="sensorProperties" location="classpath:/sensor.properties"/&gt; &lt;bean class="sample.SensorGenerator"&gt; &lt;property name="sourceProperties" ref="sensorProperties" /&gt; &lt;/bean&gt; &lt;/beans&gt; </code></pre> <p>Here are the four Java Classes I have (HelloWorldMain.java, HelloWorld.java, Sensor.java, and SensorGenerator.Java):</p> <p>UPDATED: The issue was that I had a constructor in my HelloWorld.java calling SensorGenerator instead of using @Autowired to let Spring do it. The answer by Frederic at the bottom shows the old code Constructor. The @Autowired annotation is shown below in HelloWorld.java:</p> <p>HelloWorldMain.java:</p> <pre><code>package sample; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class HelloWorldMain { // define context to load properties with Spring public static void main(String[] args) throws Exception { AbstractApplicationContext context = new ClassPathXmlApplicationContext( "applicationContext.xml"); Thread.currentThread().join(); } } </code></pre> <p>HelloWorld.java:</p> <pre><code>package sample; import java.util.*; import org.apache.camel.Handler; import org.springframework.stereotype.Service; /** * POJO that returns Hello World string * */ @Service public class HelloWorld { @AutoWired SensorGenerator sensorGenerator; @Handler public Map&lt;?, ?&gt; returnMap(){ System.out.println(); System.out.println("Returning Map"); // get the map of Sensors Map&lt;String,String&gt; mySensorMap = sensorGenerator.getSensors(); // print out the Sensors in the map on the console Set keys = mySensorMap.keySet(); for (Iterator i = keys.iterator(); i.hasNext();) { String key = (String) i.next(); String value = (String) mySensorMap.get(key); System.out.println("key= " + key + ", value= " + value); } return mySensorMap; } } </code></pre> <p>Sensor.java (which defines the fields I'm reading from sensor.properties):</p> <pre><code>package sample; public class Sensor { private String make; private String makeDataType; private String model; private String modelDataType; private String serialNumber; private String serialNumberDataType; private String sensorType; private String sensorTypeDataType; // getters and setters public String getMake() { return make; } public void setMake(String make) { this.make = make; } public String getMakeDataType() { return makeDataType; } public void setMakeDataType(String makeDataType) { this.makeDataType = makeDataType; } public String getModel() { return model; } public void setModel(String model) { this.model = model; } public String getModelDataType() { return modelDataType; } public void setModelDataType(String modelDataType) { this.modelDataType = modelDataType; } public String getSerialNumber() { return serialNumber; } public void setSerialNumber(String serialNumber) { this.serialNumber = serialNumber; } public String getSerialNumberDataType() { return serialNumberDataType; } public void setSerialNumberDataType(String serialNumberDataType) { this.serialNumberDataType = serialNumberDataType; } public String getSensorType() { return sensorType; } public void setSensorType(String sensorType) { this.sensorType = sensorType; } public String getSensorTypeDataType() { return sensorTypeDataType; } public void setSensorTypeDataType(String sensorTypeDataType) { this.sensorTypeDataType = sensorTypeDataType; } } </code></pre> <p>SensorGenerator.java (the class where I current hard-code the properties but want to have Spring load them from sensor.properties. If I comment out the For loop and any lines referencing sourceProperties I can get the map returned with the hard coded values just fine. That's why I suspect its some sort of Spring/Camel integration issue):</p> <p>package sample;</p> <pre><code>import java.util.HashMap; import java.util.Map; import java.util.Properties; public class SensorGenerator { private Properties sourceProperties; // variable to increment key number for each sensor int sensorNumber = 1; // method to inject sensor.properties into a Map using Spring Map&lt;String, String&gt; getSensors() { Map&lt;String, String&gt; sensorMap = new HashMap&lt;String, String&gt;(); for (Object key : sourceProperties.keySet()) { // Separate out each of the key,value pairs as an entry in the // values array String[] values = sourceProperties.getProperty((String) key).split( ","); System.out.println("values array size= " + values.length); // define string buffer that appends sensor number for each sensor's // keys. Ex: sensor1 would have s1make, s1makeDataType, etc. StringBuffer sensorNumberStringBuffer = new StringBuffer(); sensorNumberStringBuffer.append("s"); sensorNumberStringBuffer.append(sensorNumber); // make and its data type (with sensor number prefix) StringBuffer makeStringBuffer = new StringBuffer(); makeStringBuffer.append(sensorNumberStringBuffer); makeStringBuffer.append("make"); StringBuffer makeDataTypeStringBuffer = new StringBuffer(); makeDataTypeStringBuffer.append(sensorNumberStringBuffer); makeDataTypeStringBuffer.append("makeDataType"); // model and its data type (with sensor number prefix) StringBuffer modelStringBuffer = new StringBuffer(); modelStringBuffer.append(sensorNumberStringBuffer); modelStringBuffer.append("model"); StringBuffer modelDataTypeStringBuffer = new StringBuffer(); modelDataTypeStringBuffer.append(sensorNumberStringBuffer); modelDataTypeStringBuffer.append("modelDataType"); // serialNumber and its data type (with sensor number prefix) StringBuffer serialNumberStringBuffer = new StringBuffer(); serialNumberStringBuffer.append(sensorNumberStringBuffer); serialNumberStringBuffer.append("serialNumber"); StringBuffer serialNumberDataTypeStringBuffer = new StringBuffer(); serialNumberDataTypeStringBuffer.append(sensorNumberStringBuffer); serialNumberDataTypeStringBuffer.append("serialNumberDataType"); // sensorType and its data type (with sensor number prefix) StringBuffer sensorTypeStringBuffer = new StringBuffer(); sensorTypeStringBuffer.append(sensorNumberStringBuffer); sensorTypeStringBuffer.append("sensorType"); StringBuffer sensorTypeDataTypeStringBuffer = new StringBuffer(); sensorTypeDataTypeStringBuffer.append(sensorNumberStringBuffer); sensorTypeDataTypeStringBuffer.append("sensorTypeDataType"); /* put all the key,value pairs for this sensor in the sensorMap */ //TODO: Change all the hard coded values below to be elements // from the values array once Spring can load spring.properties // make and and its data type sensorMap.put(makeStringBuffer.toString(), "DummyMake"); sensorMap.put(makeDataTypeStringBuffer.toString(), "String"); // model and and its data type sensorMap.put(modelStringBuffer.toString(), "DummyModel"); sensorMap.put(modelDataTypeStringBuffer.toString(), "String"); // serialNumber and and its data type sensorMap.put(serialNumberStringBuffer.toString(), "1234567890"); sensorMap.put(serialNumberDataTypeStringBuffer.toString(), "long"); // sensorType and its data type sensorMap.put(sensorTypeStringBuffer.toString(), "DummyType"); sensorMap.put(sensorTypeDataTypeStringBuffer.toString(), "String"); // increment for next sensor sensorNumber++; } return sensorMap; } public void setSourceProperties(Properties properties) { this.sourceProperties = properties; } } </code></pre> <p>Btw: Line 17 of SensorGenerator.java as mentioned in the stack trace above is:</p> <pre><code> for (Object key : sourceProperties.keySet()) { </code></pre> <p>Here is an example sensor.properties file:</p> <pre><code>sensor1=DummySensor1:String,SensorModel1:String,1234567890:long,SensorType1:String sensor2=DummySensor2:String,SensorModel2:String,8675309123:long,SensorType2:String </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload