Data mapping and transformation with Camunda Spin and Java 8

By
  • Blog
  • >
  • Data mapping and transformation with Camunda Spin and Java 8
TOPICS

30 Day Free Trial

Bring together legacy systems, RPA bots, microservices and more with Camunda

Sign Up for Camunda Content

Get the latest on Camunda features, events, top trends, and more.

TRENDING CONTENT
Working with text based data formats such as Xml and JSON is a common requirement when implementing BPMN processes. 

 

Since version 7.2 Camunda provides an optional library which is called Camunda Spin. Spin is a lightweight wrapper library which provides a easy to use API when working with text based data formats such as XML and JSON.

 
In this post I show how the Camunda Spin can be used for implementing data transformations and mapping in combination with the Java 8 Stream processing API and contrast this to the classical Java 6 / 7 way of doing it. 

 

Example

The example we use is how to transform a list of The Big Bang Theory episodes (provided as Xml) into JSON output.
 
This source was obtained from the TVRage API and looks like this:
<?xml version="1.0" encoding="UTF-8" ?>
<show>
  <name>The Big Bang Theory</name>
  <totalseasons>8</totalseasons>
  <episodelist>
    <season no="1">
      <episode>
        <epnum>1</epnum>
        <seasonnum>01</seasonnum>
        <prodnum>276023</prodnum>
        <airdate>2007-09-24</airdate>
        <link>https://www.tvrage.com/The_Big_Bang_Theory/episodes/550436</link>
        <title>Pilot</title>
      </episode>
      <episode>
        <epnum>2</epnum>
        <seasonnum>02</seasonnum>
        <prodnum>3T6601</prodnum>
        <airdate>2007-10-01</airdate>
        <link>https://www.tvrage.com/The_Big_Bang_Theory/episodes/603610</link>
        <title>The Big Bran Hypothesis</title>
      </episode>
...

As Output we want to obtain a JSON list of all episodes which aired after 2012:

[{
  "name":"The Shiny Trinket Maneuver",
  "air-date":"2012-01-12"
 },
 {
  "name":"The Recombination Hypothesis",
  "air-date":"2012-01-19"
 }, ... ]

 

Enable Spin in your project

In order to enable Camunda Spin in your project,

1) add it to your maven dependencies:

<dependencymanagement>
    <dependencies>
      <dependency>
        <groupid>org.camunda.bpm</groupid>
        <artifactid>camunda-bom</artifactid>
        <version>7.3.0-alpha1</version>
        <scope>import</scope>
        <type>pom</type>
      </dependency>
    </dependencies>
  </dependencymanagement>

  <dependencies>
    <dependency>
      <groupid>org.camunda.spin</groupid>
      <artifactid>camunda-spin-core</artifactid>
    </dependency>

    <dependency>
      <groupid>org.camunda.spin</groupid>
      <artifactid>camunda-spin-dataformat-json-jackson</artifactid>
    </dependency>

    <dependency>
      <groupid>org.camunda.spin</groupid>
      <artifactid>camunda-spin-dataformat-xml-dom</artifactid>
    </dependency>
  </dependencies>

2) In your Java Code, add the following static import:

import static org.camunda.spin.Spin.*;

 

Parsing the Xml input with Spin

In order to parse the Xml input, we can use Spin’s XML(…) method:
 
XML(xmlInput)
 
Spin can consume Xml in the form of a string or a java.io.Reader instance. 

 

The Java 6/7 way

We’ll start with the classical Java way of transforming the input.

Using Spin’s xPath function to iterate through all episodes

In order to iterate through all episodes in the document, we can use Spin’s xPath function:
 
for (SpinXmlElement element : XML(xmlInput).xPath("/Show/Episodelist/Season/episode").elementList()) {
  // work with the element        
}

Getting the production Year as Integer

Since we only want to retain those episodes which aired after 2012, we need to get the production year element for the episode and interpret it as integer:
for (SpinXmlElement element : XML(xmlInput).xPath("/Show/Episodelist/Season/episode").elementList()) {

  int productionYear = Integer.parseInt(element.childElement("airdate").textContent().substring(0, 4));

}

Creating an empty JSON Document

Next, lets create an empty JSON document into which we can collect the episodes which aired after 2012:
 
SpinJsonNode resultJson = JSON("[]");

Transform the Episodes into JSON

Next we create a JSON object into which we copy the values from the xml source:

SpinJsonNode episodeJson = JSON("{}")
      .prop("name", episode.childElement("title").textContent())
      .prop("air-date", episode.childElement("airdate").textContent());

The complete Java 6/7 source code then looks like this:

SpinJsonNode resultJson = JSON("[]");

for (SpinXmlElement episode : XML(xmlInput).xPath("/Show/Episodelist/Season/episode").elementList()) {
  int productionYear = Integer.parseInt(episode.childElement("airdate").textContent().substring(0, 4));
  if(productionYear >= 2012) {

    SpinJsonNode episodeJson = JSON("{}")
      .prop("name", episode.childElement("title").textContent())
      .prop("air-date", episode.childElement("airdate").textContent());

    resultJson.append(episodeJson);
  }
}

The Java 8 Way

Java 8 introduces the Stream API and lambdas. This allows us to write a very compact representation for obtaining the same thing:

final SpinJsonNode resultJson = JSON("[]");

XML(xmlInput)
  .xPath("/Show/Episodelist/Season/episode").elementList()
  .stream()
  .filter(e -> Integer.parseInt(e.childElement("airdate").textContent().substring(0, 4)) >= 2012)
  .map(e -> JSON("{}")
              .prop("name", e.childElement("title").textContent())
              .prop("air-date", e.childElement("airdate").textContent()))
  .forEach(e -> resultJson.append(e));

What is missing?

The above example is not “purely” functional. In the forEach method we collect the generated customers and append them to the resultJson object.

A more functional approach would use a java.util.stream.Collector:

SpinJsonNode resultJson = XML(xmlInput)
  .xPath("/Show/Episodelist/Season/episode").elementList()
  .stream()
  .filter(e -> Integer.parseInt(e.childElement("airdate").textContent().substring(0, 4)) >= 2012)
  .map(e -> JSON("{}")
              .prop("name", e.childElement("title").textContent())
              .prop("air-date", e.childElement("airdate").textContent()))
  .collect(asJsonList());

The SpinCollectors.asJsonList() method does not exist yet. This would be something the Spin library could provide. In case anybody would use this?

Camunda Developer Community

Join Camunda’s global community of developers sharing code, advice, and meaningful experiences

Try All Features of Camunda

Related Content

See how Funding Societies is taking advantage of process orchestration to automate their lending process, greatly improving outcomes for their customers.
Process blueprints can now be found on Camunda marketplace! Read on to learn how they can help you and how you can contribute.
Achieve operational superiority with the intelligent backbone of service orchestration. Learn how and why you should orchestrate your services.