title: Spring JMS receive topic messages
body: <p>I am working on a simple tutorial. I have a publisher that sends message on a topic and subscribers to receive it. When I start the application, spring config file loads up and then I get the following error </p>
  
  <pre><code>    2011-10-20 21:50:39,340 DEBUG [org.springframework.jms.support.destination.JndiDestinationResolver] - Located object with JNDI name [RateTopic]
  2011-10-20 21:50:39,340 DEBUG [org.springframework.jms.support.destination.JndiDestinationResolver] - Located object with JNDI name [RateTopic]
  2011-10-20 21:50:39,340 DEBUG [org.springframework.jms.connection.CachingConnectionFactory] - Closing cached Session: ActiveMQSession {id=ID:Reverb0253-PC-62259-1319161839013-0:1:3,started=true}
  2011-10-20 21:50:39,340 DEBUG [org.springframework.jms.connection.CachingConnectionFactory] - Closing cached Session: ActiveMQSession {id=ID:Reverb0253-PC-62259-1319161839013-0:1:2,started=true}
  2011-10-20 21:50:44,348 WARN [org.springframework.jms.listener.DefaultMessageListenerContainer] - Setup of JMS message listener invoker failed for destination 'RateTopic' - trying to recover. Cause: Destination [RateTopic] is not of expected type [javax.jms.Queue]
  org.springframework.jms.support.destination.DestinationResolutionException: Destination [RateTopic] is not of expected type [javax.jms.Queue]
      at org.springframework.jms.support.destination.JndiDestinationResolver.validateDestination(JndiDestinationResolver.java:147)
      at org.springframework.jms.support.destination.JndiDestinationResolver.resolveDestinationName(JndiDestinationResolver.java:112)
      at org.springframework.jms.support.destination.JmsDestinationAccessor.resolveDestinationName(JmsDestinationAccessor.java:100)
      at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.createListenerConsumer(AbstractPollingMessageListenerContainer.java:221)
      at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.initResourcesIfNecessary(DefaultMessageListenerContainer.java:1081)
      at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1057)
      at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1050)
      at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:947)
      at java.lang.Thread.run(Thread.java:722)
  </code></pre>
  
  <p>Why does spring think that it should be a queue instead of topic</p>
  
  <p>my jndi file looks like this</p>
  
  <pre><code>java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory
  java.naming.provider.url = tcp://localhost:61616
  java.naming.security.principal=system
  java.naming.security.credentials=manager
  connectionFactoryNames = TopicCF
  topic.RateTopic = RateTopic
  </code></pre>
  
  <p>spring config file is</p>
  
  <pre><code>&lt;bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate"&gt;
      &lt;property name="environment"&gt;
          &lt;props&gt;
              &lt;prop key="java.naming.factory.initial"&gt;
                  org.apache.activemq.jndi.ActiveMQInitialContextFactory
              &lt;/prop&gt;
              &lt;prop key="java.naming.provider.url"&gt;tcp://localhost:61616&lt;/prop&gt;
              &lt;prop key="java.naming.security.principal"&gt;system&lt;/prop&gt;
              &lt;prop key="java.naming.security.credentials"&gt;manager&lt;/prop&gt;
          &lt;/props&gt;
      &lt;/property&gt;
  &lt;/bean&gt;
  
  &lt;bean id="jndiTopicConnFactory" class="org.springframework.jndi.JndiObjectFactoryBean"&gt;
      &lt;property name="jndiTemplate" ref="jndiTemplate"/&gt;
      &lt;!-- JNDI name of connection factory as defined by provider --&gt;
      &lt;property name="jndiName" value="TopicCF"/&gt;
  &lt;/bean&gt;
  
  &lt;bean id="topicConnFactory" class="org.springframework.jms.connection.CachingConnectionFactory"&gt;
      &lt;property name="targetConnectionFactory" ref="jndiTopicConnFactory"/&gt;
      &lt;!-- Number of sessions that will be cached --&gt;
      &lt;property name="sessionCacheSize" value="1"/&gt;
  &lt;/bean&gt;
  
  &lt;bean id="destinationResolver" class="org.springframework.jms.support.destination.JndiDestinationResolver"&gt;
      &lt;property name="jndiTemplate" ref="jndiTemplate"/&gt;
      &lt;property name="cache" value="true"/&gt;
      &lt;!-- do not create a dynamic destination if the destination name is not found in JNDI --&gt;
      &lt;property name="fallbackToDynamicDestination" value="false"/&gt;
  &lt;/bean&gt;
  
  &lt;bean id="messageListener" class="com.merc.springjmspubsublenderborrower.TBorrower"/&gt;
  
  &lt;bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"&gt;
      &lt;property name="connectionFactory" ref="topicConnFactory"/&gt;
      &lt;property name="destinationResolver" ref="destinationResolver"/&gt;
      &lt;property name="concurrentConsumers" value="3" /&gt;
      &lt;property name="destinationName" value="RateTopic"/&gt;
      &lt;property name="messageListener" ref="messageListener" /&gt;
      &lt;property name="sessionAcknowledgeModeName" value="AUTO_ACKNOWLEDGE"/&gt;
  &lt;/bean&gt;
  </code></pre>
  
  <p>My subscriber implements MessageListener</p>
  
  <pre><code>@Override
  public void onMessage(Message message) {
      try {
          // Get the data from the message
          BytesMessage msg = (BytesMessage) message;
          double newRate = msg.readDouble();
          // If the rate is at least 1 point lower than the current rate, then
          //recommend refinancing
          if ((currentRate - newRate) &gt;= 1.0) {
              System.out.println(
                      "New rate = " + newRate + " - Consider refinancing loan");
          } else {
              System.out.println("New rate = " + newRate + " - Keep existing loan");
          }
          System.out.println("\nWaiting for rate updates...");
      } catch (Exception ex) {
          ex.printStackTrace(System.out);
          System.exit(1);
      }
  }
  
  public static void main(String argv[]) {
  
      ApplicationContext ctx = new ClassPathXmlApplicationContext("app-context.xml");
  
      try {
          // Run until enter is pressed
          BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
          System.out.println("TBorrower application started");
          System.out.println("Press enter to quit application");
          stdin.readLine();
      } catch (IOException ioe) {
          ioe.printStackTrace();
      }
  }
  </code></pre>