Quantcast

MessageFormatException using requestBody InOut over activemq JMS

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

MessageFormatException using requestBody InOut over activemq JMS

MarkD
Hi all,

I have a pojo that returns a Map of Custom objects. In my camel context this pojo is wired to receive requests from a jms (activemq) queue, i.e., it can act as a simple service. Code below:

@Override
public Map<String, ParameterGroup> getParameterGroups() {
    return model.getParameterGroups();
}

I have a client which is a pojo producer (template injected using @Produce). It invokes the service using the template.requestBody(Object) method. Code below:

@Produce(uri = "activemq:requestParameterGroups")
ProducerTemplate requestParameterGroupsProducerTemplate;

@Override
public List<ParameterGroup> requestParameterGroups() {
    // testing service call
    List<ParameterGroup> parameterGroups = new ArrayList<ParameterGroup>();
    parameterGroups = (List<ParameterGroup>) requestParameterGroupsProducerTemplate.requestBody(null);
    System.out.println("Received " + parameterGroups.size() + " parameter groups.");
    return parameterGroups;
}

I have a question and an error. First the error:

The request makes it to the pojo service bean which attempts to return the Map of custom objects but the return message times out. Looking at the logs I can see a Camel runtime exception wrapping a spring jms MessageFormatException which claims "Only objectified primitive objects, String, Map, and List types are allowed but was...it then lists the entire value part of the returned Map (Note, it does not print out the key)


On a side note: I assume the requestBody parameter Object can be null if you don't need to send any parameters to the request, i.e., if the service simply acts like a getter as in the case above.

Looks like the error is an activemq message. I can't find much info on it other than it seems to occur when people attempt to put Objects in the Header.

Thanks!
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: MessageFormatException using requestBody InOut over activemq JMS

MarkD
Looking at this closer, it seems to suggest I cannot return/send a custom objects, only String, Map, List and objectified primitives.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: MessageFormatException using requestBody InOut over activemq JMS

MarkD
For what it is worth, i've just noticed the incorrect return type on the invoker. Obviously that's not the cause of the error.

@Override
public List<ParameterGroup> requestParameterGroups() {
    // testing service call
    List<ParameterGroup> parameterGroups = new ArrayList<ParameterGroup>();
    parameterGroups = (List<ParameterGroup>) requestParameterGroupsProducerTemplate.requestBody(null);
    System.out.println("Received " + parameterGroups.size() + " parameter groups.");
    return parameterGroups;
}

should be

@Override
        public Map<String, ParameterGroup> requestParameterGroups() {
                Map<String, ParameterGroup> parameterGroups = new HashMap<String, ParameterGroup>();
                parameterGroups = (Map<String, ParameterGroup>) requestParameterGroupsProducerTemplate.requestBody(null);
                System.out.println("Received " + parameterGroups.size() + " parameter groups.");

                return parameterGroups;
        }
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: MessageFormatException using requestBody InOut over activemq JMS

MarkD
Ok, I looked into this and found the message in the Activemq source. It looks like it is trying to set an Object Property using the values part of the return map. Maybe something it getting confused somewhere.

Changing the server to return a List instead solved the problem. Not sure why!
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: MessageFormatException using requestBody InOut over activemq JMS

MarkD
Sorry:

Changing the server to return a List instead solved the problem.

Should read:

Changing the service to return a List instead solved the problem.

i.e.
@Override
public List<ParameterGroup> getParameterGroups() {
   return model.getParameterGroupsAsList();
}
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: MessageFormatException using requestBody InOut over activemq JMS

bjpeter
Aloha,

I recently got the same exception as MarkD did.  I'm using Camel version 2.9.0. Attached is my source code for some tests. The first three test cases pass, but the fourth one fails.

Is there a fix for this issue?  I'd like to put a map containing any serializable object into the body without having to wrap the map in some serializable object. The latter works, but I'd much prefer just using the map.

Thanks!
BJ

**************************************************

package com.test;

import java.io.Serializable;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import org.apache.activemq.camel.component.ActiveMQComponent;
import org.apache.camel.CamelContext;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.log4j.Appender;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;

/**
 * This program puts four different objects in the body of a Camel message. If
 * the object is a map that contains an object that is not an objectified
 * primitive (e.g. not an Integer), an exception is thrown.
 *
 * @author BJ Peter DeLaCruz <bjpeter@hawaii.edu>
 */
public class TestCamelJmsWithMap {

  private static final Logger LOGGER = Logger.getLogger(TestCamelJmsWithMap.class);

  private static final String DIRECT_URL = "direct:start";
  private static final String QUEUE_URL = "activemq:queue:myqueue";

  /**
   * This program runs four different test cases, which are:<br>
   * <br>
   * <ol>
   * <li>A serialized object called TestObject.</li>
   * <li>A map of primitive types.</li>
   * <li>An object that wraps a map of TestObjects.</li>
   * <li>A map of TestObjects.</li>
   * </ol>
   * The first three test cases pass, but the last one fails.<br>
   * <br>
   *
   * @param args None.
   * @throws Exception If there are problems.
   */
  public static void main(String... args) throws Exception {
    // test(new TestObjectBodyFactory()); // This test case works.
    // test(new PrimitiveMapBodyFactory()); // This test case works.
    // test(new WrappedObjectBodyFactory()); // This test case works.
    test(new TestObjectMapBodyFactory()); // This test case fails!
  }

  /**
   * Sends an object in the body of a Camel message.
   *
   * @param bodyFactory The factory for creating the object to be used in the
   * body.
   * @throws Exception If there are problems.
   */
  public static void test(BodyFactory bodyFactory) throws Exception {
    Logger logger = Logger.getRootLogger();
    for (Enumeration<?> appenders = logger.getAllAppenders(); appenders.hasMoreElements();) {
      Appender appender = (Appender) appenders.nextElement();
      if (appender instanceof ConsoleAppender) {
        logger.removeAppender(appender);
      }
    }
    ConsoleAppender console = new ConsoleAppender(new PatternLayout("%d [%t] %-5p %c - %m%n"),
        "System.out");
    logger.addAppender(console);
    logger.setLevel(Level.INFO);

    final CamelContext context = new DefaultCamelContext();
    context.addComponent("activemq",
        ActiveMQComponent.activeMQComponent("vm://localhost?broker.persistent=false"));

    context.addRoutes(new RouteBuilder() {
      public void configure() throws Exception {
        from(DIRECT_URL).to(QUEUE_URL);
        from(QUEUE_URL).log("received message: ${body}");
      }
    });
    context.start();

    ProducerTemplate producerTemplate = context.createProducerTemplate();
    while (true) {
      try {
        producerTemplate.sendBody(DIRECT_URL, bodyFactory.createBody());
      }
      catch (Exception e) {
        LOGGER.error("", e);
      }
      Thread.sleep(1000L);
    }
  }

  /** A factory for creating objects to be used in test cases. */
  public static interface BodyFactory {
    /** Creates the object used in the body of a Camel message. */
    public Object createBody();
  }

  /** A factory for creating a map of primitives. */
  static class PrimitiveMapBodyFactory implements BodyFactory {
    /** {@inheritDoc} */
    @Override
    public Object createBody() {
      Map<Integer, Integer> map = new HashMap<Integer, Integer>();
      map.put(1, 2);
      return map;
    }
  }

  /** A factory for creating a TestObject. */
  static class TestObjectBodyFactory implements BodyFactory {
    /** {@inheritDoc} */
    @Override
    public Object createBody() {
      return new TestObject();
    }
  }

  /** A factory for creating a map of TestObjects. */
  static class TestObjectMapBodyFactory implements BodyFactory {
    /** {@inheritDoc} */
    @Override
    public Object createBody() {
      Map<Integer, TestObject> map = new HashMap<Integer, TestObject>();
      map.put(1, new TestObject());
      return map;
    }
  }

  /** A factory for creating an object that contains a map. */
  static class WrappedObjectBodyFactory implements BodyFactory {
    /** {@inheritDoc} */
    @Override
    public Object createBody() {
      Map<Integer, TestObject> map = new HashMap<Integer, TestObject>();
      map.put(1, new TestObject());
      return new Wrapper(map);
    }
  }

  /** The test object. */
  static class TestObject implements Serializable {
    /** {@inheritDoc} */
    @Override
    public String toString() {
      return "This is a test.";
    }
  }

  /** A wrapper that wraps an object. */
  static class Wrapper implements Serializable {

    private Object contents;

    /**
     * Creates a new Wrapper.
     * @param contents The object to wrap.
     */
    public Wrapper(Object contents) {
      this.contents = contents;
    }

    /** {@inheritDoc} */
    @Override
    public String toString() {
      return this.contents.toString();
    }

  }

}
Loading...