In the below code I am replacing the "con" tag value with the newly declared String "con" value("{\"payload_dl\":{\"deveui\":\"23456\"}}"). But when doing so, the value is storing as normal string without escape characters.
How to escape the string value while replacing in the jsonNode??.
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.jayway.jsonpath.JsonPath;
ObjectMapper mapper = new ObjectMapper();
JsonFactory jsonFactory = new JsonFactory();
JsonParser jp = jsonFactory.createJsonParser({"m2m:cin":{"con":"{\"payload_dl\":{\"deveui\":\"765348\"}});
jp.setCodec(new ObjectMapper());
JsonNode jsonNode = jp.readValueAsTree();
String con = "{\"payload_dl\":{\"deveui\":\"23456\"}}";
changePayloadContent(jsonNode, "con", con);
logger.info("Modified Payload content ::: "+ jsonNode);
return mapper.writeValueAsString(jsonNode);
changePayloadContent method,
public static void changePayloadContent(JsonNode parent, String fieldName, String newValue) throws JsonProcessingException, IOException {
logger.debug("Start of change");
ObjectMapper mapper = new ObjectMapper();
if (parent.has(fieldName)) {
try {
JsonNode jsonNode = mapper.readTree(newValue);
((ObjectNode) parent).put(fieldName, jsonNode);
} catch (Exception e) {
logger.info("GenericFlow::replace::NewValue is not JSON String");
((ObjectNode) parent).put(fieldName, newValue);
}
}
for (JsonNode child : parent) {
changePayloadContent(child, fieldName, newValue);
}
logger.debug("End of change");
}
Related
I'm struggling to deserialize a Collection<Collection<?>> using Jackson. When deserializing the serialized object Jackson converts them into a LinkedHashMap instead of Item:
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class JsonTest {
ObjectMapper mapper = new ObjectMapper();
#Test
void main() throws JsonProcessingException {
Set<Integer> firstSet = Set.of(1, 2, 3);
Set<Item> secondSet = Set.of(new Item("abc"), new Item("123"));
Root root = new Root(List.of(firstSet, secondSet));
String json = mapper.writeValueAsString(root);
System.out.println(json);
Root parsed = mapper.readValue(json, Root.class);
assertEquals(firstSet, parsed.data().get(0));
assertEquals(secondSet, parsed.data().get(1));
// the assertion above fails:
// Expected :[Item[id=abc], Item[id=123]]
// Actual :[{id=abc}, {id=123}]
}
}
record Root(List<Set<?>> data) {}
record Item(String id) {}
// build.gradle
plugins {
id 'java'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.0'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
}
test {
useJUnitPlatform()
}
My first idea was to replace the Set<?> with a custom container class that contains an additional type hint and write a custom deserializer:
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class JsonTest {
ObjectMapper mapper = new ObjectMapper();
#Test
void main() throws JsonProcessingException {
TypedList<Item> secondSet = new TypedList<>(Item.class, List.of());
Root root = new Root(secondSet);
String json = mapper.writeValueAsString(root);
System.out.println(json);
Root parsed = mapper.readValue(json, Root.class);
assertEquals(secondSet, parsed.data());
}
}
class TypedCollectionDeserializer<T> extends StdDeserializer<TypedList<T>> {
public TypedCollectionDeserializer() {
super(TypedList.class);
}
#Override
public TypedList<T> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
Class<T> valueType = getTypeClass(p);
String dataKey = p.nextFieldName();
if (!dataKey.equals("data")) {
throw new IllegalStateException();
}
List<T> list = deserializeData(p, valueType);
// skip END_ARRAY
p.nextToken();
return new TypedList<>(valueType, list);
}
private Class<T> getTypeClass(JsonParser p) throws IOException {
String typeKey = p.nextFieldName();
if (!typeKey.equals("type")) {
throw new IllegalStateException();
}
String typeValue = p.nextTextValue();
try {
return (Class<T>) Class.forName(typeValue);
} catch (ClassNotFoundException e) {
throw new IllegalStateException("unexpected type " + typeValue, e);
}
}
private List<T> deserializeData(JsonParser p, Class<T> valueType) throws IOException {
List<T> list = new ArrayList<>();
JsonToken jsonToken = p.nextToken();
if (jsonToken != JsonToken.START_ARRAY) {
throw new IllegalArgumentException();
}
JsonToken maybeStart = p.nextToken();
if (maybeStart == JsonToken.START_OBJECT) {
do {
T t = p.readValueAs(valueType);
if (t != null) {
list.add(t);
}
} while (p.nextToken() == JsonToken.START_OBJECT);
}
return list;
}
}
record Root(#JsonDeserialize(using = TypedCollectionDeserializer.class) TypedList<?> data) {}
record Item(String id) {}
#JsonPropertyOrder({"type", "data"})
record TypedList<T>(Class<T> type, List<T> data) {}
But this looks like I'm re-doing Jackson's own code to deserialize Collections. Is there perhaps a more idiomatic way?
I am trying to save a string list in a jsonobject and deserialise it on load. When I am saving the list, I am creating a JsonObject and adding it as a property by using the GSON.toJson. I have created a String arraylist serialiser to serialise the item and when I check my mongo database it appears to be saving as a jsonArray but when I try to deserialise it, it tells me that it is not a JsonArray.
Here is my code:
Order object:
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
#Getter
#Setter
#RequiredArgsConstructor
public class Order {
private final UUID id;
private final String table;
private short numberOfPeople;
private LocalDate timeOfOrder = LocalDate.now();
private String staffInCharge = "";
private List<String> order = new ArrayList<>();
private String note = "";
}
The #RequiredArgumentsConstructor just creates a constructor for me so I dont have to do public Order() etc
Imports of the Serialise and Deserialise class:
import com.google.gson.*;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import me.oscar.orderbird.OrderBird;
import me.oscar.orderbird.gson.GsonUtil;
import me.oscar.orderbird.mongo.MongoUtils;
import me.oscar.orderbird.profile.food.Food;
import me.oscar.orderbird.profile.order.Order;
import me.oscar.orderbird.profile.staff.Staff;
import me.oscar.orderbird.profile.table.Table;
import org.bson.Document;
import java.util.*;
Serialise:
if (!this.orders.isEmpty()){
JsonArray orderArray = new JsonArray();
this.orders.values().forEach(order -> {
JsonObject ordersObect = new JsonObject();
ordersObect.addProperty("id", order.getId().toString());
ordersObect.addProperty("name", order.getTable());
ordersObect.addProperty("note", order.getNote());
ordersObect.addProperty("numberOfPeople", order.getNumberOfPeople());
ordersObect.addProperty("staffInCharge", order.getStaffInCharge());
ordersObect.addProperty("orderItems", GsonUtil.GSON.toJson(order.getOrder()));
orderArray.add(ordersObect);
});
document.put("orders", orderArray.toString());
}
Deserialise:
if (document.containsKey("orders")) {
if (document.get("orders") instanceof String) {
JsonArray ordersArray = PARSER.parse(document.getString("orders")).getAsJsonArray();
for (JsonElement jsonElement : ordersArray) {
JsonObject jsonObject = jsonElement.getAsJsonObject();
try {
Order order = new Order(UUID.fromString(jsonObject.get("id").getAsString()), jsonObject.get("name").getAsString());
order.setNote(jsonObject.get("note").getAsString());
order.setNumberOfPeople(jsonObject.get("numberOfPeople").getAsShort());
order.setStaffInCharge(jsonObject.get("staffInCharge").getAsString());
order.setOrder(GsonUtil.GSON.fromJson(jsonObject.get("orderItems").getAsJsonObject(), ArrayList.class));
this.orders.put(jsonObject.get("name").getAsString(), order);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
ArrayListAdapter:
package me.oscar.orderbird.gson.impl;
import com.google.gson.*;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
public class StringArrayAdapter implements JsonDeserializer<List<String>>, JsonSerializer<List<String>> {
#Override
public List<String> deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
JsonArray jsonArray = jsonElement.getAsJsonArray();
List<String> values = new ArrayList<>();
for (int i = 0; i < jsonArray.size(); i++){
values.set(i, jsonArray.get(i).getAsJsonPrimitive().getAsString());
}
return values;
}
#Override
public JsonElement serialize(List<String> stringList, Type type, JsonSerializationContext jsonSerializationContext) {
JsonArray jsonArray = new JsonArray();
for (String string : stringList) {
jsonArray.add(new JsonPrimitive(string));
}
return jsonArray;
}
}
When I attempt to set the order I am getting the error:
java.lang.IllegalStateException: Not a JSON Object: "[\n \"Steak\"\n]"
There are two issues with your implementation
While changing from Object to Document, you need to preserve property class type for orderItems
change
ordersObect.addProperty("orderItems", GsonUtil.GSON.toJson(order.getOrder()));
TO
ordersObect.addProperty("orderItems", GSON.toJson(order.getOrder(), ArrayList.class));
While reading from Document, need to read as the same class type
change
GsonUtil.GSON.fromJson(jsonObject.get("orderItems").getAsJsonObject(), ArrayList.class)
TO
GSON.fromJson(jsonObject.get("orderItems").getAsString(),ArrayList.class)
So working code is as below:
import com.Order;
import com.StringArrayAdapter;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.bson.Document;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
JsonParser PARSER = new JsonParser();
Gson GSON = new GsonBuilder()
.registerTypeHierarchyAdapter(ArrayList.class, new StringArrayAdapter())
.setPrettyPrinting()
.serializeNulls()
.create();
Document document = new Document();
Map<String, Order> orders = new HashMap<>();
for (int i = 0; i < 2; i++) {
Order order = new Order(UUID.randomUUID(), "" + i);
orders.put(order.getTable(), order);
}
// SO Post Code
if (!orders.isEmpty()) {
JsonArray orderArray = new JsonArray();
orders.values().forEach(order -> {
JsonObject ordersObect = new JsonObject();
ordersObect.addProperty("id", order.getId().toString());
ordersObect.addProperty("name", order.getTable());
ordersObect.addProperty("note", order.getNote());
ordersObect.addProperty("numberOfPeople", order.getNumberOfPeople());
ordersObect.addProperty("staffInCharge", order.getStaffInCharge());
ordersObect.addProperty("orderItems", GSON.toJson(order.getOrder(), ArrayList.class));
orderArray.add(ordersObect);
});
document.put("orders", orderArray.toString());
}
System.out.println("document: " + document);
Map<String, Order> readOrders = new HashMap<>();
if (document.containsKey("orders")) {
if (document.get("orders") instanceof String) {
JsonArray ordersArray = PARSER.parse(document.getString("orders")).getAsJsonArray();
for (JsonElement jsonElement : ordersArray) {
JsonObject jsonObject = jsonElement.getAsJsonObject();
try {
Order order = new Order(UUID.fromString(jsonObject.get("id").getAsString()), jsonObject.get("name").getAsString());
order.setNote(jsonObject.get("note").getAsString());
order.setNumberOfPeople(jsonObject.get("numberOfPeople").getAsShort());
order.setStaffInCharge(jsonObject.get("staffInCharge").getAsString());
order.setOrder((ArrayList<String>)GSON.fromJson(jsonObject.get("orderItems").getAsString(), ArrayList.class));
readOrders.put(jsonObject.get("name").getAsString(), order);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
System.out.println("Orders read : " + readOrders);
OUTPUT:
document: Document{{orders=[{"id":"e853617a-b516-4daf-ba6c-e5d731c556de","name":"0","note":"","numberOfPeople":0,"staffInCharge":"","orderItems":"[]"},{"id":"31004bbd-164d-4e64-b468-7021e1c21c39","name":"1","note":"","numberOfPeople":0,"staffInCharge":"","orderItems":"[]"}]}}
Orders read : {0=Order(id=e853617a-b516-4daf-ba6c-e5d731c556de, table=0, numberOfPeople=0, timeOfOrder=2021-06-16, staffInCharge=, order=[], note=), 1=Order(id=31004bbd-164d-4e64-b468-7021e1c21c39, table=1, numberOfPeople=0, timeOfOrder=2021-06-16, staffInCharge=, order=[], note=)}
I currently have this code, how can I add to it so I can get a JsonObject from Gson to append it to an existing Json file?
private static void writeFile(File f, String w_username, String w_password) throws IOException{
Gson gson = new Gson();
JsonWriter writer = new JsonWriter(new FileWriter(f));
}
JSON structure does not allow just to append more data at the end of the file. In this case more suitable could be CSV format.
To solve your problem you need to read the whole file as JsonObject, add new "key-value" pair and save it back.
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Objects;
public class GsonApp {
public static void main(String[] args) throws IOException {
File store = Files.createTempFile("store", "json").toFile();
// Add two users
JsonFileAppender jsonFileAppender = new JsonFileAppender();
jsonFileAppender.appendToObject(store, "jon", "ewemn!32");
jsonFileAppender.appendToObject(store, "rick", "923djks");
// Print whole file
System.out.println(String.join("", Files.readAllLines(store.toPath())));
}
}
class JsonFileAppender {
private final Gson gson;
public JsonFileAppender() {
this.gson = new GsonBuilder().create();
}
public void appendToObject(File jsonFile, String username, String password) throws IOException {
Objects.requireNonNull(jsonFile);
Objects.requireNonNull(username);
Objects.requireNonNull(password);
if (jsonFile.isDirectory()) {
throw new IllegalArgumentException("File can not be a directory!");
}
JsonObject node = readOrCreateNew(jsonFile);
node.addProperty(username, password);
writeToFile(jsonFile, node);
}
private JsonObject readOrCreateNew(File jsonFile) throws IOException {
if (jsonFile.exists() && jsonFile.length() > 0) {
try (BufferedReader reader = new BufferedReader(new FileReader(jsonFile))) {
return gson.fromJson(reader, JsonObject.class);
}
}
return new JsonObject();
}
private void writeToFile(File jsonFile, JsonObject node) throws IOException {
try (FileWriter writer = new FileWriter(jsonFile)) {
gson.toJson(node, writer);
}
}
}
Above code prints:
{"jon":"ewemn!32","rick":"923djks"}
I expected to get JSON data from a webhook.
I get this form of data below and the content/type was application/x-www-form-urlencoded instead of application/json
results%5B6%5D%5Bid%5D=7&results%5B18%5D%5Bid%5D=19&results%5B0%5D%5Bname%5D=data+autre&results%5B1%5D%5Bname%5D=data2+autre&assessments%5B0%5D%5Bstatus%5D=finish&results%5B10%5D%5Bscore%5D=6&results%5B7%5D%5Bname%5D=data3&results%5B6%5D%5Bname%5D=Accept&results%5B8%5D%5Bname%5D=data4&results%5B2%5D%5Bname%5D=autres&results%5B3%5D%5Bname%5D=data6&results%5B4%5D%5Bname%5D=autre&results%5B5%5D%5Bname%5D=autres3&results%5B9%5D%5Bname%5D=data8&results%5B17%5D%5Bid%5D=18&reports%5B4%5D%5Bid%5D=8&reports%5B4%5D%5Bis_available%5D=0&results%5B7%5D%5Bscore%5D=7&results%5B17%5D%5Bscore%5D=4&reports%5B1%5D%5Bis_available%5D=1&assessments%5B2%5D%5Blink%5D=https%3A%2F%2Ftest%3D123&lastname=aaa&results%5B3%5D%5Bscore%5D=10&reports%5B3%5D%5Bid%5D=15&results%5B16%5D%5Bid%5D=17®ister_link=&results%5B7%5D%5Bid%5D=8&results%5B19%5D%5Bid%5D=20&results%5B13%5D%5Bscore%5D=5&assessments%5B1%5D%5Bstatus%5D=todo&results%5B4%5D%5Bid%5D=5&status=accepted&results%5B9%5D%5Bid%5D=10&results%5B15%5D%5Bid%5D=16&results%5B3%5D%5Bid%5D=4&reports%5B4%5D%5Bname%5D=data9&reports%5B3%5D%5Bname%5D=data10&results%5B18%5D%5Bscore%5D=1&email=test#test.com&results%5B9%5D%5Bscore%5D=6&synthesis=
How can I convert this to json ?
Thanks
if you are looking to convert this in java, may be you can try the following code:
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class URLEncodeDecode {
public static void main(String[] args) {
String url2 = "results%5B6%5D%5Bid%5D=7&results%5B18%5D%5Bid%5D=19";
String decodeURL = decode(url2);
System.out.println("Decoded URL: " + decodeURL);
System.out.println(Stream.of(decodeURL.split("&")).map(elem -> new String(elem)).collect(Collectors.toList()));
List<String> uriToList = Stream.of(decodeURL.split("&")).map(elem -> new String(elem))
.collect(Collectors.toList());
Map<String, String> uriToListToMap = new HashMap<>();
for (String individualElement : uriToList) {
uriToListToMap.put(individualElement.split("=")[0], individualElement.split("=")[1]);
}
// Use this builder to construct a Gson instance when you need to set
// configuration options other than the default.
GsonBuilder gsonMapBuilder = new GsonBuilder();
Gson gsonObject = gsonMapBuilder.create();
String uriToJSON = gsonObject.toJson(uriToListToMap);
System.out.println(uriToJSON);
}
public static String decode(String url) {
try {
String prevURL = "";
String decodeURL = url;
while (!prevURL.equals(decodeURL)) {
prevURL = decodeURL;
decodeURL = URLDecoder.decode(decodeURL, "UTF-8");
}
return decodeURL;
} catch (UnsupportedEncodingException e) {
return "Issue while decoding" + e.getMessage();
}
}
}
I am integrating with an old system and have a need to parse the following xml into my object. I am trying to do this with jackson but I can't get the mapping to work. Anyone know how to map the following xml to the pojo?
#JacksonXmlRootElement(localName = "properties")
#Data
public class Example {
private String token;
private String affid;
private String domain;
}
xml example:
<properties>
<entry key="token">rent</entry>
<entry key="affid">true</entry>
<entry key="domain">checking</entry>
</properties>
I have tried adding
#JacksonXmlProperty(isAttribute = true, localName = "key")
to the properties but this of course doesn't work and I do not see another way to get this to work. Any ideas?
I am using the mapper like so...
ObjectMapper xmlMapper = new XmlMapper();
dto = xmlMapper.readValue(XML_STRING, Example .class);
I am using the following dependencies
compile('org.springframework.boot:spring-boot-starter-web')
runtime('org.springframework.boot:spring-boot-devtools')
compileOnly('org.projectlombok:lombok')
testCompile('org.springframework.boot:spring-boot-starter-test')
compile('org.apache.commons:commons-lang3:3.5')
compile('com.fasterxml.jackson.dataformat:jackson-dataformat-xml')
compile('com.squareup.okhttp3:okhttp:3.10.0')
This does work.
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.List;
public class XmlParserDemo {
public static void main(String[] args) throws IOException, XMLStreamException {
String xmlString = "<properties>\n" +
" <entry key=\"token\">rent</entry>\n" +
" <entry key=\"affid\">true</entry>\n" +
" <entry key=\"domain\">checking</entry>\n" +
"</properties>";
XMLStreamReader sr = null;
sr = XMLInputFactory.newFactory().createXMLStreamReader(new StringReader(xmlString));
sr.next();
XmlMapper mapper = new XmlMapper();
List<Entry> entries = mapper.readValue(sr, new TypeReference<List<Entry>>() {
});
sr.close();
entries.forEach(e ->
System.out.println(e.key + ":" + e.value));
}
public static class Entry {
#JacksonXmlProperty(isAttribute = true, localName = "key")
private String key;
#JacksonXmlText
private String value;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}
Output is:
token:rent
affid:true
domain:checking
I have looked through Jackson thoroughly and it doesn't seem that there is a way to accomplish this. However, I will share my solution here in case it is useful to someone else.
package com.example.config;
import com.example.dto.Example;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
public class Converter extends AbstractHttpMessageConverter<Example> {
private static final XPath XPATH_INSTANCE = XPathFactory.newInstance().newXPath();
private static final StringHttpMessageConverter MESSAGE_CONVERTER = new StringHttpMessageConverter();
#Override
protected boolean supports(Class<?> aClass) {
return aClass == Example.class;
}
#Override
protected Example readInternal(Class<? extends LongFormDTO> aClass, HttpInputMessage httpInputMessage) throws IOException, HttpMessageNotReadableException {
String responseString = MESSAGE_CONVERTER.read(String.class, httpInputMessage);
Reader xmlInput = new StringReader(responseString);
InputSource inputSource = new InputSource(xmlInput);
Example dto = new Example();
Node xml;
try {
xml = (Node) XPATH_INSTANCE.evaluate("/properties", inputSource, XPathConstants.NODE);
} catch (XPathExpressionException e) {
log.error("Unable to parse response", e);
return dto;
}
log.info("processing populate application response={}", responseString);
dto.setToken(getString("token", xml));
dto.setAffid(getInt("affid", xml, 36));
dto.domain(getString("domain", xml));
xmlInput.close();
return dto;
}
private String getString(String propName, Node xml, String defaultValue) {
String xpath = String.format("//entry[#key='%s']/text()", propName);
try {
String value = (String) XPATH_INSTANCE.evaluate(xpath, xml, XPathConstants.STRING);
return StringUtils.isEmpty(value) ? defaultValue : value;
} catch (XPathExpressionException e) {
log.error("Received error retrieving property={} from xml", propName, e);
}
return defaultValue;
}
private String getString(String propName, Node xml) {
return getString(propName, xml, null);
}
private int getInt(String propName, Node xml, int defaultValue) {
String stringValue = getString(propName, xml);
if (!StringUtils.isEmpty(stringValue)) {
try {
return Integer.parseInt(stringValue);
} catch (NumberFormatException e) {
log.error("Attempted to parse value={} as integer but received error", stringValue, e);
}
}
return defaultValue;
}
private int getInt(String propName, Node xml) {
return getInt(propName, xml,0);
}
private boolean getBoolean(String propName, Node xml) {
String stringValue = getString(propName, xml );
return Boolean.valueOf(stringValue);
}
#Override
protected void writeInternal(Example dto, HttpOutputMessage httpOutputMessage) throws IOException, HttpMessageNotWritableException {
throw new UnsupportedOperationException("Responses of type=" + MediaType.TEXT_PLAIN_VALUE + " are not supported");
}
}
I chose to hide this in a message converter so I don't have to look at it again but you can apply these steps where you see fit. If you choose this route, you will need to configure a rest template to use this converter. If not, it is important to cache the xml into a Node object as regenerating each time will be very costly.
package com.example.config;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.MediaType;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
#Configuration
public class RestConfig {
#Bean
#Primary
public RestTemplate restTemplate() {
return new RestTemplate(new OkHttp3ClientHttpRequestFactory());
}
#Bean
public RestTemplate restTemplateLe(RestTemplateBuilder builder) {
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
ExampleConverter exampleConverter = new ExampleConverter();
exampleConverter.setSupportedMediaTypes(Collections.singletonList(MediaType.TEXT_PLAIN));
messageConverters.add(exampleConverter);
return builder.messageConverters(messageConverters)
.requestFactory(new OkHttp3ClientHttpRequestFactory())
.build();
}
}