I have one Json node:
{
"name":
{
"first": "Tatu",
"last": "Saloranta"
},
"title": "Jackson founder",
"company": "FasterXML"
}
I have another Json node (the one which I want to insert):
{
"country": "My country",
"hobbies": "some hobbies"
}
I want my resulting node to be:
{
"additional info":
{
"country": "My country",
"hobbies": "some hobbies"
},
"name":
{
"first": "Tatu",
"last": "Saloranta"
},
"title": "Jackson founder",
"company": "FasterXML"
}
How do I do that in Java? Here is my java code:
private final static ObjectMapper JSON_MAPPER = new ObjectMapper();
JsonNode biggerNode = parseTree(someObject);
JsonNode nodeToBeInsertede = JSON_MAPPER.valueToTree(anotheObj);
//I want to do something like this:
//biggerNode.put("additionalInfo", nodeToBeInsertede)
Instead of JsonNode read a Map and use standard Map.put() to modify the bigger object:
ObjectMapper mapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
TypeReference<Map<String, Object>> type = new TypeReference<>() {};
Map<String, Object> biggerMap = mapper.readValue(biggerJson, type);
Map<String, Object> smallerMap = mapper.readValue(smallerJson, type);
biggerMap.put("additional_info", smallerMap);
String outJson = mapper.writeValueAsString(biggerMap);
System.out.println(outJson);
will output:
{
"name" : {
"first" : "Tatu",
"last" : "Saloranta"
},
"title" : "Jackson founder",
"company" : "FasterXML",
"additional_info" : {
"country" : "My country",
"hobbies" : "some hobbies"
}
}
Related
I'm not fluent in API testing hence my question. I have a body to POST (mock) that will consist of:
{
"request":
{
"urlPath": "path/to/",
"method": "POST",
"bodyPatterns":[{
"equalToJson" : "{\n\"query\": [\n{\n\"name\": \"name1\",\n\"value\": \"123\"\n },\n{\n\"name\": \"name2\",\n\"value\": \"345\"\n},\n{\n\"name\": \"name3\",\n\"value\": \"someName\"\n}\n],\n\"anotherItem\": [],\n\"side\": 77,\n\"pageSize\": 44\n}", "jsonCompareMode": "LENIENT"
}]
},
"response":
{
"status": 200,
"headers":
{
"Content-Type" : "application/json"
},
"body": "{"items\": [\n{\n\"item\": 1,\n
\"item2\": 2,\n
etc
"\n}\n]\n}"
}
}
I want to use some pojo classes to separately create Request and Response:
public Request initRequest() {
BodyPattern bodyPat = new BodyPattern();
Query query = new Query();
Query query2 = new Query();
Query query3 = new Query();
EqualToJson equalToJ = new EqualToJson();
query.setName("name1");
query.setValue("123");
query2.setName("name2");
query2.setValue("345");
query3.setName("name2");
query3.setValue("someName");
List<Query> queryList = new ArrayList<>();
queryList.add(query);
queryList.add(query2);
queryList.add(query3);
equalToJ.setQuery(queryList);
List<Filter> filtersList = new ArrayList<>();
equalToJ.setFilter(filtersList);
equalToJ.setSide(77);
equalToJ.setPageSize(44);
List<EqualToJson> eqList = new ArrayList<>();
eqList.add(equalToJ);
req.setUrlPath(URL + "/Test001");
req.setMethod("POST");
bodyPat.setEqualToJson(eqList);
bodyPat.setJsonCompareMode("LENIENT");
List<BodyPattern> bodyPatList = new ArrayList<>();
bodyPatList.add(bodyPat);
req.setBodyPatterns(bodyPatList);
return req;
}
To see it in more user-friendly view, here you go:
{
"request": {
"urlPath": "/path/to",
"method": "POST",
"bodyPatterns": [
{
"equalToJson": {
"query": [
{
"name": "name1",
"value": "123"
},
{
"name": "name2",
"value": "345"
},
{
"name": "name3",
"value": "someName"
}
],
"filter": [
],
"side": 77,
"pageSize": 44
},
"jsonCompareMode": "LENIENT"
}
]
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"body": {
"side": 77,
"pageSize": 44,
"items": [
{
"name1": "123",
"name2": "345",
"name3": "someName"
etc...
}
]
}
}
}
Similarly, I do with Response.
My question is, how can I make to have just a part of this json (BodyPatters) as escaped signs? Mock is created this way that it only accepts escaped characters in this part of json.
I can of course hardcode this payload, but I want to have control over those fields' values and steer them, as parameters.
I really have no idea how to handle this.
You can use objectmapper of jackson to convert Object to String. For example:
void name2() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
Query query = new Query("name1", "123");
EqualToJson equalToJson = new EqualToJson();
equalToJson.setQuery(Arrays.asList(query));
BodyPattern bodyPattern = new BodyPattern();
bodyPattern.setEqualToJson(mapper.writeValueAsString(equalToJson));
String bodyPatternText = mapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(bodyPattern);
System.out.println(bodyPatternText);
}
#Data
#AllArgsConstructor
static class Query{
private String name;
private String value;
}
#Data
static class EqualToJson {
private List<Query> query;
}
#Data
static class BodyPattern {
private String equalToJson;
}
This is a result:
{
"equalToJson" : "{\"query\":[{\"name\":\"name1\",\"value\":\"123\"}]}"
}
I'm using a Map<String, Map> resultMap having values like this:
[
{main={group={street={cnt=Burundi, zip=123}, code=asd, subtype={OrgType=1,2}}}},
{main={info={text=bbb}}},
{main={group={subId=5, attrib={attribId=1,2}}}}
]
I have to create a JSON out of those Maps that should look like this:
{ "main": [
{
"group": {
"street": {
"cnt": "Burundi",
"zip": "123"
},
"code": "asd",
"subtype": {
"OrgType": "1,2"
},
"subId": "5",
"attribId": "1,2"
},
"info": {
"text": "bbb"
}
}
]
}
Any idea how could I merge those Maps doing a GSON.toJson(resultMap); to obtain this JSON ?
I tried to merge the Map
public String produceJsonFromMap(Map<String, Map> initialMap) {
Map<String, Object> resultMap = new HashMap<>();
for(Map map: initialMap.values()) {
resultMap.putAll(map);
}
return GSON.toJson(resultMap);
}
But this overwrites my previous maps and I don't know how can I obtain the desired merged map...
I'm using jackson 2.9.8 and I'm trying to beutify my json.
The code I'm using is:
protected void setSuccessMessage(HttpServletResponse response, JSONObject jObj) throws IOException {
// Set the status
response.setStatus(200);
// Create the response
response.setContentType("application/json");
PrintWriter out = response.getWriter();
jObj.put("success", 1);
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
mapper.setVisibility(PropertyAccessor.ALL, Visibility.ANY);
out.print(mapper.writeValueAsString(jObj));
out.close();
}
However, my output has a new map tag which I don't want. The output is:
{
"map" : {
"success" : 1,
"documents_metata" : {
"myArrayList" : [ {
"map" : {
"documentType" : "PS_XML",
"patientId" : "x",
"effectiveTime" : "2019-05-08",
"author" : "xxx",
"repositoryId" : "xxx",
"id" : "xxx",
"title" : "xxx"
}
}, {
"map" : {
"documentType" : "PS_PDF",
"patientId" : "x",
"effectiveTime" : "2019-05-08",
"author" : "xxx",
"repositoryId" : "xxx",
"id" : "xxx",
"title" : "xxx"
}
} ]
}
}
}
The correct one should be:
{
"success": 1,
"documents_metadata": [
[
{
"documentType": "PS_PDF",
"patientId": "x",
"effectiveTime": "2019-05-08",
"author": "xxx",
"repositoryId": "xxx",
"id": "xxx",
"title": "xxx"
},
{
"documentType": "PS_XML",
"patientId": "x",
"effectiveTime": "2019-05-08",
"author": "xxx",
"repositoryId": "xxx",
"id": "xxx",
"title": "xxx"
}
]
]
}
The json without the jackson is fine but's it's not indented. Do you know how to fix this?
Jackson doesn't know anything about JSONObject which comes from another library. So it's writing its internal structure like it would any other class. Use https://github.com/FasterXML/jackson-datatype-json-org to tell Jackson how to treat it:
import com.fasterxml.jackson.datatype.jsonorg.JsonOrgModule;
mapper.registerModule(new JsonOrgModule());
Or use Jackson's own JsonNode (see e.g. Working with Tree Model Nodes in Jackson for a tutorial).
I am consuming an external web service and receiving a JSON response. In this response, there is an object "entities" containing multiple arrays in it, with a name before each array.
I want to add the name before the array in the array object itself.
For example this is the original response:
{
"entities": {
"entity": [
{
"confidence": 1,
"value": "user",
"type": "value"
},
{
"confidence": 1,
"value": "insurance form",
"type": "value"
}
],
"ui_page_step": [
{
"confidence": 1,
"value": "step 1",
"type": "value"
}
],
"userrole_ano": [
{
"confidence": 0.96535832252792,
"value": "anonymous user"
}
]
}
}
I need to convert it to:
{
"entities": {
"entity": [
{
"name": "entity",
"confidence": 1,
"value": "user",
"type": "value"
},
{
"name": "entity",
"confidence": 1,
"value": "insurance form",
"type": "value"
}
],
"ui_page_step": [
{
"name": "ui_page_step",
"confidence": 1,
"value": "step 1",
"type": "value"
}
],
"userrole_ano": [
{
"name": "userrole_ano",
"confidence": 0.96535832252792,
"value": "anonymous user"
}
]
}
}
How can I convert the original response to the desired one in Java?
Here is a (one of several possible) solutions:
It uses Jackson library to parse the Json into a java Map that is (relatively) easier to navigate and modify than JSONObject.
the method putCollectionNamesInsideEntries() assumes one root "entities" entry that has several collections as values. it iterates over all of them, adding "name" entry with name of collection.
the map is serialized back to Json (and sent to System.out)
import java.io.*;
import java.nio.file.*;
import java.util.*;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonTest
{
public static void main(String[] args) {
try (InputStream is = Files.newInputStream(Paths.get("C:/temp/test.json"))) {
ObjectMapper mapper = new ObjectMapper();
// deserialize json into map
Map<String, Object> map = (Map<String, Object>)mapper.readValue(is, Map.class);
putCollectionNamesInsideEntries(map);
// serialize map into json
mapper.writeValue(System.out, map);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void putCollectionNamesInsideEntries(Map<String, Object> map) {
// get root "entities" entry
Map<String, Object> entitiesMap = (Map<String, Object>)map.get("entities");
for (Map.Entry<String, Object> entitiesEntry : entitiesMap.entrySet()) {
// iterate over collection entries
if (entitiesEntry.getValue() instanceof Collection) {
Collection coll = (Collection)entitiesEntry.getValue();
// iterate over entries in collection
for (Object collEntry : coll) {
if (collEntry instanceof Map) {
// add "name" with ame of collection (key entry under "entries")
((Map<String, Object>)collEntry).put("name", entitiesEntry.getKey());
}
}
}
}
}
}
{"myContainer" :
{ "couldBeAnything" : [
{"id":1, "name":"sb", "category":"couldBeAnything"},
{"id":2, "name":"bs", "category":"couldBeAnything"}
],
"somethingElse" : [
{"id":1, "name":"sdsa","category":"somethingElse"},
{"id":2, "name":"ve","category":"somethingElse"}
]
},
"id" : 0
}
So far I have :
Type myContainerType = new TypeToken<MyContainer>(){}.getType();
MyContainerType myContainerType = gson.fromJson(myJson.getValue(), myContainerType);
Where
public class MyContainer {
private int id;
private Map<String, List<Foo>> foo; // and foo has id, name, category
The result, no errors, a populated id field, but just a null map
I think the json is wrong for the structure Map<String, List<Foo>>. When you say map you need not enclose each key-value with {. Just put the whole key values in one {} and seprate with commas. eg
{
"myContainer": {
"couldBeAnything": [
{
"id": 1,
"name": "sb",
"category": "couldBeAnything"
},
{
"id": 2,
"name": "bs",
"category": "couldBeAnything"
}
],
"somethingElse": [
{
"id": 1,
"name": "sdsa",
"category": "somethingElse"
},
{
"id": 2,
"name": "ve",
"category": "somethingElse"
}
]
},
"id": 0
}
With this json it works perfectly
public static void main(String[] args){
String json = "{\"myContainer\":{\"couldBeAnything\":[{\"id\":1,\"name\":\"sb\",\"category\":\"couldBeAnything\"},{\"id\":2,\"name\":\"bs\",\"category\":\"couldBeAnything\"}],\"somethingElse\":[{\"id\":1,\"name\":\"sdsa\",\"category\":\"somethingElse\"},{\"id\":2,\"name\":\"ve\",\"category\":\"somethingElse\"}]},\"id\":0}";
Map<String, List<Foo>> obj = new HashMap<String, List<Foo>>();
Gson gson = new Gson();
obj = gson.fromJson(json, obj.getClass());
System.out.println(obj);
}
Output
{id=0.0, myContainer={couldBeAnything=[{id=1.0, name=sb, category=couldBeAnything}, {id=2.0, name=bs, category=couldBeAnything}], somethingElse=[{id=1.0, name=sdsa, category=somethingElse}, {id=2.0, name=ve, category=somethingElse}]}}
The issue with your approach was the naming of the field foo. Your json contains the Map<String, List<Foo>> name as myContainer. So modify your container class like below and it will work fine :)
public class MyContainer {
private int id;
private Map<String, List<Foo>> myContainer;
}
Now this will work
Type myContainerType = new TypeToken<MyContainer>(){}.getType();
MyContainer myContainer = gson.fromJson(json, myContainerType);
System.out.println(myContainer);