0

I am working on a component for an enterprise message queue that consumes a message from a queue and sends it as a text message. The message is picked up by my consumer in JSON format (I do not have the ability to modify how the message is received).

{
   "id":"19ADFASDFGG456SDGE",
   "body":"Hello World!",
   "to":[15189511011, 19178567788]
}

Once it is received by my consumer I need to populate an XML file like this

<Request>
   <Identification>
      <UserID>CONSTANT_USER</UserID>
      <Password>CONSTANT_PASS</Password>
   </Identification>
   <Service>
      <ServiceName>SendMessage</ServiceName>
      <ServiceDetail>
         <CombiMessage>
            <CombiList>
               <Individual type='sms'>${to}</Individual>
            </CombiList>
            <Text>${body}</Text>
         </CombiMessage>
      </ServiceDetail>
   </Service>
</Request>

Where ${to} and ${body} are populated by by the JSON object. That XML cannot be generated in the code (it needs to reside in a resource folder as an xml file). In addition to consuming the message and subsequently sending a text message, the consumer also has logging capabilities and it passes the JSON object (or a POJO containing that data) off to another system.

Basically when a JSON object is consumed off the queue right now I am using a library called Jackson to populate a Pojo that looks like this.

public class Message {
    private Set<PhoneNumber> to;
    private String body;
    private String id;
}

And the JSON object populates that Pojo via Jackson like this.

public static Message getMessage(String json) {
    ObjectMapper mapper = new ObjectMapper();

    return mapper.readValue(json, Message.class);
}

From there I now have a POJO that is an exact copy of the JSON object and I can send it off to the logging system, to the other system, and also I can populate the XML with it.

However I haven't found an ideal way to populate the XML. Currently I have something simple like this

private static String populate(String request, Message message) {
    return request.replaceAll("${to}", message.getTo().toString()).replaceAll("${body}", message.getBody());
}

This is fine in this regard but only because I oversimplified for the sake of asking this question. Sometimes the XML file has nearly a thousand fields that need to be populated. Can anyone recommend a solution for this last step? How to do this dynamically? Basically I would like to map fields in my POJO with nodes in the xml file (also remembering that I need to keep that xml file external).

  • 4
    Your title talks about "MQ architecture" but the question doesn't seem to have anything to do with MQ. Instead it seems that you are looking for an approach to transform JSON to XML. Where you get the message and where it goes are not really relevant to that. Am I missing something? – JimmyJames Jul 27 '17 at 13:57
  • You are correct although I may have phrased my question wrong. A hard requirement is that I get in a JSON object with data and i need to get it to and XML template. Currently I have a POJO middle step. so I am going from json to pojo to xml. The issue I am having is with pojo to xml and thts what i asked. However I am equally open to a better architected solution that doesn't require 3 steps – Chris Maggiulli Jul 27 '17 at 14:12
  • So the big problem is that you have an XML template with hundreds or thousands of tags in it that need to be replaced with data from the POJO? – Dan Pichelman Jul 27 '17 at 14:13
  • The issue is that I populate a POJO based off a JSON object. The POJO fields need to be named exactly the same as the JSON objects in order for the population to happen. However I also need to populate the XML nodes based off this object and the XML nodes have different names. I cant change the name of the xml nods or of the JSON object properties/arrays. – Chris Maggiulli Jul 27 '17 at 14:25
  • "The POJO fields need to be named exactly the same as the JSON objects in order for the population to happen." presumably you are saying this is a requirement to use Jackson. It's not true in general. see GSON – JimmyJames Jul 27 '17 at 14:30
1

I would use either DOM or a template engine such as FreeMarker for generating the XML. The benefit of DOM is that it guarantees XML validity; the benefit of template engine is that you see with a text editor what the XML looks like. If using a template engine, remember proper escaping of the substituted variables!

You will also need a JSON library. I haven't read JSON previously with Java; I have just written it (using a custom-made JSON library), so I don't know what your options are. I'm pretty sure you are able to find many JSON libraries using a simple Google search.

To indent properly in DOM, do this:

TransformerFactory tf;
Transformer t;

tf = TransformerFactory.newInstance();
t = tf.newTransformer();
t.setOutputProperty(OutputKeys.INDENT, "yes");
t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");

...and then use the constructed Transformer to transform an XML document into a stream.

1

IMHO, the best way would be to use JAXB. You are already converting your JSON to POJOs. So if you have a schema (.xsd) to which your XML conforms to, then you can use maven plugin to automatically generate the DTOs for JAXB and then use marshalling to convert your POJO to XML.

Since your POJOs are different from each other you will have to map them. You can use Dozer or any other strategy to perform the same.

  • 2
    Does this solve the problem of the JSON element names being different from the XML element names? – Robert Harvey Jul 27 '17 at 15:40
  • Thanks @Robert Harvey for pointing out the difference in the fields. Have updated my answer. – phoenixSid Jul 27 '17 at 16:05
0

Can anyone recommend a solution for this last step? How to do this dynamically? Basically, I would like to map fields in my POJO with nodes in the XML file (also remembering that I need to keep that XML file external).

You almost have it, don't reinvent the wheel at this last step.

We have here two options that -I think- are compatible with you actual strategy. Templating and Expression evaluators.

Templating

As for templating, Freemaker can do the job exactly as you want. Loading the external XML as the template and replacing the placeholders from a POJO or map.

In essence, Freemaker evaluates expressions. So you could go straight to the solution looking for the Java's expression evaluators that best suits your needs.

Evaluating expression

For example, if you have Spring in the technology stack, you might be interested in Spring Expression, if you haven't, MVEL -which seems to be fairly known by the community- might do the job too.

String myXmlString = parser.parseExpression(
        "<MyTag><Tag>#{T(java.lang.Math).random()}</Tag></MyTag>",
        new TemplateParserContext()).getValue(String.class);

// <MyTag><Tag>0.7038186818312008</Tag></MyTag>

Additionally

For more sophisticated Json data bindings, take a look to the Jackson Annotations. As for XMLs, Jackson XML data bindings, which also provides annotations.

A little example of how to bind XML nodes and JSON attributes with different names to the same POJO

@JacksonXmlProperty(localName = "OnBoardingPending")
@JsonProperty(value = "on-boarding-pending", index = 1)
public int getOnBoardingPending() {
    return onBoardingPending;
}

@JacksonXmlProperty(localName = "NotActive")
@JsonProperty(value = "not-active", index = 2)
public int getNotActive() {
    return notActive;
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.