I'm using the following code (found on this webpage) and the Gson library (2.8.2) to format JSON code with pretty printing.
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class GsonExample {
public static void main(String[] args) {
String jsonData = "{\"name\":\"mkyong\",\"age\":35,\"position\":\"Founder\",\"salary\":10000,\"skills\":[\"java\",\"python\",\"shell\"]}";
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String json = gson.toJson(jsonData);
System.out.println(json);
}
}
This is the expected result:
{
"name": "mkyong",
"age": 35,
"position": "Founder",
"salary": 10000,
"skills": [
"java",
"python",
"shell"
]
}
Unfortunately "pretty printing" doesn't work at all and I get everything in one line:
{\"name\":\"mkyong\",\"age\":35,\"position\":\"Founder\",\"salary\":10000,\"skills\":[\"java\",\"python\",\"shell\"]}"
Any ideas what I'm doing wrong?
You have to parse the JSON, and then call gson.toJson() on the resulting parsed JSON.
JsonElement jsonElement = new JsonParser().parse(jsonData);
String json = gson.toJson(jsonElement);
Your current code is just telling GSON to convert some String into JSON, and the result of that is the same String.
nickb made my day! :-)
The correct code must look like this:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParser;
import com.google.gson.JsonElement;
public class GsonExample {
public static void main(String[] args) {
String jsonData = "{\"name\":\"mkyong\",\"age\":35,\"position\":\"Founder\",\"salary\":10000,\"skills\":[\"java\",\"python\",\"shell\"]}";
JsonElement jsonElement = new JsonParser().parse(jsonData);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String json = gson.toJson(jsonElement);
System.out.println(json);
}
}
Output:
{
"name": "mkyong",
"age": 35,
"position": "Founder",
"salary": 10000,
"skills": [
"java",
"python",
"shell"
]
}
i know i'm late. But JsonParser.parse() is deprecated from com.google.code.gson v2.8.6
instead use the static method parseString​(String json):
public String formatFormat(String source) {
JsonElement jsonElement = JsonParser.parseString(source);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
return gson.toJson(jsonElement);
}
import statement : import com.google.gson.*;
You can also use static methods like parseReader​(JsonReader reader) or parseReader​(java.io.Reader reader) if your input source type is different from string.
Related
I am new to Rest Assured & GraphQL, Please can someone help me to create the body request from the following output:
{
"variables": {
"EmployeeName": "ABC",
"EmployeeDept": "Computers",
"EmployeeStatus": false,
"employeeRegion": [{
"country": "USA",
"values": ["NewYork"]
}]
}
}
My sample:
ObjectNode variables = mapper.createObjectNode()
.put("EmployeeName", EmployeeName)
.put("EmployeeDept", "EmployeeDept")
.put("EmployeeStatus", "EmployeeStatus")
Not sure how to construct the employeeRegion in variables?
To make json array, just use List in java.
Example:
Region usa = new Region("USA", Arrays.asList("NewYork", "LA"));
Region uk = new Region("UK", Arrays.asList("London", "Manchester"));
List<Region> list = Arrays.asList(usa, uk);
....
put("employeeRegion", list);
Region.java
import lombok.Data;
import java.util.List;
#Data
public class Region {
private String country;
private List<String> values;
public Region(String country, List<String> values) {
this.country = country;
this.values = values;
}
}
I have been using the SearchTemplateRequest class to execute my requests which uses Mustache templating to parse my template string with the passed parameters.
Elasticsearch Template - Converting Parameters to JSON
However, I have to change my implementation where I will be switching to the Java Low-Level Client. I want to use the Mustache implementation that SearchTemplateRequest uses internally to parse the template.
I'm okay to use the Mustache dependency or use the Elasticsearch implementation of it. Could someone help me out here?
My Template String:
{
"query": {
"bool": {
"filter": "{{#toJson}}clauses{{/toJson}}"
}
}
}
My Params Object:
{
"clauses": [
{
"term": {
"field1": "field1Value"
}
}
]
}
My test code:
StringWriter writer = new StringWriter();
MustacheFactory mustacheFactory = new DefaultMustacheFactory();
mustacheFactory.compile(new StringReader(requestTemplate), "templateName").execute(writer, params);
writer.flush();
The above code returns me the request template string with empty strings replacing the template.
Returned Response:
{
"query": {
"bool": {
"filter": ""
}
}
}
Expected Response:
{
"query": {
"bool": {
"filter": [
{
"term": {
"field1": "field1Value"
}
}
]
}
}
}
I finally figured out the solution.
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptEngine;
import org.elasticsearch.script.TemplateScript;
import org.elasticsearch.script.mustache.MustacheScriptEngine;
import java.util.Map;
import static java.util.Collections.singletonMap;
public class CustomMustacheScriptEngine {
private final String JSON_MIME_TYPE_WITH_CHARSET = "application/json; charset=UTF-8";
private final String JSON_MIME_TYPE = "application/json";
private final String PLAIN_TEXT_MIME_TYPE = "text/plain";
private final String X_WWW_FORM_URLENCODED_MIME_TYPE = "application/x-www-form-urlencoded";
private final String DEFAULT_MIME_TYPE = JSON_MIME_TYPE;
private final Map<String, String> params = singletonMap(Script.CONTENT_TYPE_OPTION, JSON_MIME_TYPE_WITH_CHARSET);
public String compile(String jsonScript, final Map<String, Object> scriptParams) {
jsonScript = jsonScript.replaceAll("\"\\{\\{#toJson}}", "{{#toJson}}").replaceAll("\\{\\{/toJson}}\"", "{{/toJson}}");
final ScriptEngine engine = new MustacheScriptEngine();
TemplateScript.Factory compiled = engine.compile("ScriptTemplate", jsonScript, TemplateScript.CONTEXT, params);
TemplateScript executable = compiled.newInstance(scriptParams);
String renderedJsonScript = executable.execute();
return renderedJsonScript;
}
}
I'm using Spring Boot Mongo example. I went through many links like: I want result with distinct value of one field from mongodb using spring data, but still did not get any break through. I am using below code:
List<Object> obj = mongoTemplate.query(Health.class).distinct("healths").all();
List<Health> healths = null;
if (!CollectionUtils.isEmpty(obj)) {
healths = obj.stream().map(e -> (Health) e).collect(Collectors.toList());
}
With this code I am getting duplicate HealthCode=E, Is there any way if I can take decision with the healthCd field ? Note: healths is embedded document within Patient document.
Response:
[
{
"healthCd": "D",
"healthName": "ABC",
"effDate": "2012-08-24T07:16:33"
},
{
"healthCd": "C",
"healthName": "MONO",
"effDate": "2012-08-24T07:16:33"
},
{
"healthCd": "E",
"healthName": "BONO",
"effDate": "2012-08-24T07:16:33"
},
{
"healthCd": "B",
"healthName": "JOJO",
"effDate": "2012-08-24T07:16:33"
},
{
"healthCd": "A",
"healthName": "KOKO",
"effDate": "2012-08-24T07:16:33"
},
{
"healthCd": "1",
"healthName": "LULU",
"effDate": "2012-08-24T07:16:33"
},
{
"healthCd": "E",
"healthName": "BOBO",
"effDate": "2014-07-26T22:37:49"
}
]
Health
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class Health {
#Field
private String healthCd;
#Field
private String healthName;
#Field
private LocalDateTime effDate;
}
You may use MongoBD aggregation to get desired result (Take a look):
db.health.aggregate([
{
$sort: {
"healths.effDate": 1
}
},
{
$group: {
_id: "$healths.healthCd",
healths: {
$first: "$healths"
}
}
},
{
$replaceRoot: {
newRoot: "$healths"
}
}
])
MongoPlayground
Spring Boot Implementation
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
#SpringBootApplication
public class DemoApplication implements CommandLineRunner {
#Autowired
private MongoTemplate mongoTemplate;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
// //If your operator is not available inside Aggregation or query is too complex,
// //use below code to write MongoDB shell code directly as JSON
// new AggregationOperation() {
//
// #Override
// public Document toDocument(AggregationOperationContext context) {
// return new Document("$group",
// new Document("_id", "$healths.healthCd")
// .append("healths", new Document("$first", "$healths")));
// }
//
// },
Aggregation agg = Aggregation.newAggregation(
Aggregation.sort(Direction.ASC, "healths.effDate"),
Aggregation.group("healths.healthCd").first("healths").as("healths"),
Aggregation.replaceRoot("healths")
);
AggregationResults<Healths> healths = mongoTemplate.aggregate(agg,
mongoTemplate.getCollectionName(Health.class), Healths.class);
for (Healths health : healths.getMappedResults()) {
Gson gson = new GsonBuilder().setPrettyPrinting().create();
System.out.println(gson.toJson(health));
}
}
}
My rest webservice returns the following output:
{
"result": {
"TICKET1": {
"number": "TICKET1",
"description": "aa"
},
"TICKET2": {
"number": "TICKET2",
"description": "dd"
}
}
}
To convert this into a list of Tickets I tried as below.
class TicketResponse {
private List<Ticket> result;
// Get Set
}
class Ticket {
private String number;
private String description;
// Get Set
}
TicketResponse response = restTemplate.getForObject(WEB_SERVICE_URL, TicketResponse.class);
But I get response as null. How to do this.
I'll provide two ways to do with the JSON structure you have.
Option 1:
Modify your TicketResponse class like below:
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
public class TicketResponse {
#JsonProperty("result")
private Map<String, Ticket> ticketsMap = new HashMap<>();
#JsonAnySetter
public void setUnknownField(String name, Ticket value) {
ticketsMap.put(name, value);
}
#JsonIgnore private List<Ticket> ticketsList;
public List<Ticket> getTicketsList() {
return ticketsMap.entrySet().stream().map(Entry::getValue).collect(Collectors.toList());
}
}
then you can get your list of tickets from:
response.getTicketsList();
Option 2:
Read your response in to a String
String response = restTemplate.getForObject(WEB_SERVICE_URL, String.class);
and use below code to convert it to a List<Ticket>
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode = mapper.readTree(response);
JsonNode wantedJsonNode = jsonNode.get("result");
Map<String, Ticket> map =
mapper.convertValue(wantedJsonNode, new TypeReference<Map<String, Ticket>>() {});
List<Ticket> tickets =
map.entrySet().stream().map(Entry::getValue).collect(Collectors.toList());
The object you provided doesn't contain a list/array, which would be inside square brackets, like this:
{
"result": {
"tickets": [
{
"number": "TICKET1",
"description": "aa"
},
{
"number": "TICKET2",
"description": "dd"
}
]
}
}
Change your service if possible to return a list/array. Otherwise what you have is an object with individual fields named TICKET1 and TICKET2, so you'll need a field for each.
TicketResponse must have a structure that corresponds to response of the service.
You can change your TicketResponse class and add getTicketArray method:
public class TicketResponse {
private Map<String,Ticket> result;
// getter setter
public List<Ticket> getTicketsAsArray(){
return new ArrayList<Ticket>(result.values());
}
}
I have pojo like this:
public class Test implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private String hash;
private java.util.Hashtable<Integer, Long> myTempTable;
public java.util.Hashtable<Integer, Long> getMyTempTable() {
return this.myTempTable;
}
public void setMyTempTable(java.util.Hashtable<Integer, Long> myTempTable) { this.myTempTable = myTempTable; }
//And some few variables
}
In response I get this POJO in JSON format but while converting this JSON to "Test" java object like this.
gson.fromJson(tempString, Test.class);
It is giving error as
java.lang.IllegalArgumentException: Can not set java.util.Hashtable field <package_name>.Temp.myTempTable to java.util.LinkedHashMap
Why GSON is converting HashTable to LinkedHashMap?
And does this error means?
UPDATE: JSON File as
{
"hash": "abc",
"myTempTable": {
"1": 30065833999,
"2": 34364325903,
"3": 536872959
}
}
For converting an Object to JSON String.
public static <T> String convertObjectToStringJson(T someObject, Type type) {
Gson mGson = new Gson();
String strJson = mGson.toJson(someObject, type);
return strJson;
}
For converting a JSON String to an Object.
public static <T> T getObjectFromJson(String json, Type type) {
Gson mGson = new Gson();
if (json != null) {
if (json.isEmpty()) {
return null;
}
}
return mGson.fromJson(json, type);
}
where
Type is type of your Object.
ex:
for object:
new TypeToken<YOUR_POJO>(){}.getType();
for list:
new TypeToken<List<YOUR_POJO>>(){}.getType();