Custom Class Mediator for Integer to String Conversion — WSO2 EI

Nipuna Dilhara
4 min readSep 28, 2019

Anyone here familiar with WSO2 mediation and Synapse?

I expect YES for the answer. :)

Excellent.

When using WSO2 products, we often get requirements to alter the request or response payload. So there can be situations where we need to convert the integer values of the JSON payload to a string.

If you have the experience of doing all kind of nasty things to the payload in the mediation flow, you might be thinking ‘EASYY…’!

You only need to add ‘synapse.commons.json.output.autoPrimitive=false’ property to the <PRODUCT_HOME>/repository/conf/synapse.properties file. All the integer values will be converted to strings. Easy huh?

Yeah, it’s a fine approach. But there is a downside to it.

The above change will affect all the Proxy and API services running in your product instance.

So, how can we make it affect only for a selected service?

There is no out of the box approach to achieve this requirement. No worries. That’s why we are presenting this custom class mediator which can be used to apply changes only to the selected services.

package org.wso2.sample;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.synapse.MessageContext;
import org.apache.synapse.commons.json.JsonUtil;
import org.apache.synapse.mediators.AbstractMediator;
import org.apache.synapse.core.axis2.Axis2MessageContext;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.Iterator;

public class ConvertJsonNumericValuesToStringMediator extends AbstractMediator {

private static Log log = LogFactory.getLog(ConvertJsonNumericValuesToStringMediator.class);
private JSONObject jsonPayloadObject = null;
private JSONObject convertedJsonPayloadObject = null;

public boolean mediate(MessageContext context) {
try{
String regexPattern = (String)context.getProperty("pattern");
if(StringUtils.isEmpty(regexPattern)){
regexPattern="[0-9]+";
}
jsonPayloadObject = new JSONObject(JsonUtil.jsonPayloadToString(((Axis2MessageContext) context)
.getAxis2MessageContext()));
convertedJsonPayloadObject = replaceNumericByStringInJSONPayload(jsonPayloadObject, regexPattern);
JsonUtil.newJsonPayload(((Axis2MessageContext) context).getAxis2MessageContext(),
String.valueOf(convertedJsonPayloadObject), true, true);
return true;
} catch (Exception e){
handleException("Error while invoking custom mediator: ", e, context);
}
return false;
}

public static JSONObject replaceNumericByStringInJSONPayload(JSONObject jsonPayloadObject, String regexPattern) throws Exception{
Iterator iterator = jsonPayloadObject.keys();
while (iterator.hasNext()) {
Object key = iterator.next();
String keyString = (String) key;
Object value = jsonPayloadObject.get(keyString);

if (value instanceof JSONObject) {
replaceNumericByStringInJSONPayload((JSONObject) value, regexPattern);
} else if (value instanceof JSONArray) {
for (int i = 0; i < ((JSONArray) value).length(); i++) {
replaceNumericByStringInJSONPayload(((JSONArray) value).getJSONObject(i), regexPattern);
}
} else if(value.toString().matches(regexPattern)){
jsonPayloadObject.put(keyString, value.toString());
}
}
return jsonPayloadObject;
}
}

You can simply create a maven project and add the above class.

I’m not going to explain every code line here. But you can always raise questions under the comment section if it’s not clear enough for you.

Below is the corresponding POM file.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<modelVersion>4.0.0</modelVersion>
<groupId>org.wso2.sample</groupId>
<artifactId>ConvertJsonNumericValuesToStringMediator</artifactId>
<version>1.0</version>
<dependencies>
<dependency>
<groupId>org.apache.synapse</groupId>
<artifactId>synapse-commons</artifactId>
<version>2.1.7-wso2v111</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20090211</version>
</dependency>
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>com.google.gdata.wso2</groupId>
<artifactId>gdata-core</artifactId>
<version>1.47.0.wso2v1</version>
</dependency>
<dependency>
<groupId>org.apache.axis2.wso2</groupId>
<artifactId>axis2</artifactId>
<version>1.6.1.wso2v20</version>
</dependency>
<dependency>
<groupId>org.apache.synapse</groupId>
<artifactId>synapse-core</artifactId>
<version>2.1.7-wso2v111</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
<repositories>
<repository>
<releases>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
<checksumPolicy>ignore</checksumPolicy>
</releases>
<id>wso2-nexus</id>
<url>http://maven.wso2.org/nexus/content/groups/wso2-public/</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<releases>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
<checksumPolicy>ignore</checksumPolicy>
</releases>
<id>wso2-nexus</id>
<url>http://maven.wso2.org/nexus/content/groups/wso2-public/</url>
</pluginRepository>
</pluginRepositories>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.4</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>ConvertJsonNumericValuesToStringMediator</Bundle-SymbolicName>
<Bundle-Name>ConvertJsonNumericValuesToStringMediator</Bundle-Name>
<Export-Package>org.wso2.sample</Export-Package>
<DynamicImport-Package>*</DynamicImport-Package>
</instructions>
</configuration>
</plugin>
<plugin>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<buildcommands>
<buildcommand>org.eclipse.jdt.core.javabuilder</buildcommand>
</buildcommands>
<projectnatures>
<projectnature>org.wso2.developerstudio.eclipse.artifact.mediator.project.nature</projectnature>
<projectnature>org.eclipse.jdt.core.javanature</projectnature>
</projectnatures>
</configuration>
</plugin>
</plugins>
</build>
</project>

Then build the mediator using the command ‘mvn clean install’. If everything went as expected, you will see a file named ‘ConvertJsonNumericValuesToStringMediator-1.0.jar’ inside the <project_root>/target folder.

If anyone is confused with terms like Maven and pom file, this blog post from my colleague Kawee will give you a better understanding [1].

Then follow the below steps to test the developed mediator in the mediation flow. Please be noted that I tested this using the WSO2 EI v6.5. So from here on, the instructions will be based on the EI.

  1. Add the ‘ConvertJsonNumericValuesToStringMediator-1.0.jar’ to the <EI_Home>/lib directory.
  2. Restart the server.
  3. Configure the custom class mediator as shown in the below API configuration.
<api xmlns="http://ws.apache.org/ns/synapse" name="TestAPI" context="/testApi">
<resource methods="POST" uri-template="/post">
<inSequence>
<property name="pattern" value="^4[0-9]{12}(?:[0-9]{3})?$" scope="default"/>
<class name="org.wso2.sample.ConvertJsonNumericValuesToStringMediator"/>
<send>
<endpoint>
<address uri="http://www.mocky.io/v2/5d8fc6f23200004d00adece8"/>
</endpoint>
</send>
</inSequence>
</resource>
</api>

Doesn’t know how to create an API in WSO2 EI? Check this WSO2 document [2].

Ohh.. almost forgot to tell. Did you notice this property declaration in the API configuration?

<property name="pattern" value="^4[0-9]{12}(?:[0-9]{3})?$" scope="default"/>

What the hell is that?

The mediator has the ability to not only convert integers to strings, but it can also check for a given regex pattern and make the changes apply only to matching integers. So here we have set the regex pattern for Visa/Master Card numbers.

If you call this API by using a JSON payload as follows:

{  
"info":{
"id":1,
"name":"sample name",
"age":27,
"card_number":4616791111562985
}
}

The payload will go through the mediator and provide the below output:

{  
"info":{
"id":1,
"name":"sample name",
"age":27,
"card_number":"4616791111562985"
}
}

Here is a sample curl command to call the created API. Other than this you can use any HTTP client you prefer.

curl -X POST http://<ip_address>:8280/testApi/post -H 'Content-Type: application/json' -d '{"info":{"id":1,"name":"sample name","age":27,"card_number":4616791111562985}}'

You can observe the outgoing payload form the mediator by enabling wire logs by adding the following two lines to the <EI_HOME>/conf/log4j.properties file.

log4j.logger.org.apache.synapse.transport.http.headers=DEBUG
log4j.logger.org.apache.synapse.transport.http.wire=DEBUG

You have to restart the server after making above changes in order to make them effective. Then you will observe a terminal log similar to below when calling the API.

...
[2019-09-29 02:25:48,630] [EI-Core] DEBUG - wire HTTP-Sender I/O dispatcher-4 << "{"info":{"card_number":"4616791111562985","name":"sample name","id":1,"age":27}}[\r][\n]"
...

Integers only matching to the given regex pattern will be converted to strings. If no pattern is given, then the mediator will convert all the integers in the payload.

So that’s it. Feel free to test this mediator in your configurations. Also, with slight modifications, this mediator can be used to capture null values, empty values, other data type conversions, etc.

If you got any doubts or difficulties while following my instructions, feel free to leave a comment. I’m always here to help you.

Cheers.

[1] https://medium.com/@kaweelenaduwa/introduction-to-maven-76bfdb438f3e

[2] https://docs.wso2.com/display/EI640/Working+with+APIs

--

--