Reverse JSON pretty print with Jackson - java

I know I can reformat JSON objects in Java (using Jackson, GSON, etc.) to go from
{"a":"b", "c":"d"}
to
{
"a": "b",
"c": "d"
}
But how do I go convert a JSON object back to one-object-per-line format, i.e how do I get from
{
"a": "b",
"c": "d"
}
to
{"a":"b", "c":"d"}
in Java using an existing pretty-printer?

Take a look at the following URL:
Jackson Serialization features
This will show you how you can disable features, like indent output on a per call basis, even if you are reusing the same object that has been configured for pretty printing.
I think Pretty Print is a Jackson 1.x nomenclature though... and you should be looking for SerializationFeature.INDENT_OUTPUT
#Test
public void test() throws Exception {
ObjectMapper mapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
String s = "{ \"a\" : \"b\" ,\n \"c\" : \"d\"}";
Object x = mapper.readValue(s, Object.class);
ObjectWriter w = mapper.writer();
// Indented
System.out.println(w.writeValueAsString(x));
// Single Line
System.out.println(w.without(SerializationFeature.INDENT_OUTPUT).writeValueAsString(x));
}

Since you are already using Jackson, it should work out of the box using:
String prettyJson = "{ \"a\" : \"b\" ,\n \"c\" : \"d\"}";
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode;
try {
jsonNode = objectMapper.readValue(prettyJson, JsonNode.class);
System.out.println(jsonNode.toString());
} catch (IOException e) {
e.printStackTrace();
}

Related

How to create a JSON Array of JSON objects with a Java for loop?

I have a for loop which iterates and generates key value pairs for different employees.
I need to create a JSON array like below and write it to a JSON file at the end.
I am having trouble figuring out the ideal way to code it (JSON Objects -> JSON Array -> JSON file?).
I am open to use json-simple/GSON.
Desired JSON file format:
[
{
"employeeFirstName": "Mark",
"employeeLastName": "Williams",
"employeeDepartment": "Sales",
},
{
"employeeFirstName": "John",
"employeeLastName": "Carpenter",
"employeeDepartment": "Accounts",
},
{
"employeeFirstName": "David",
"employeeLastName": "Hunter",
"employeeDepartment": "Marketing",
},
]
I tried using a JSONObject and add it to a JSONArray. But, couldn't figure how to code it for iterations.
My current Java class:
public class Test {
public void createEmployeesJSONArrayFile(ITestContext iTestContext) {
for (ITestResult testResult : iTestContext.getFailedTests().getAllResults()) {
System.out.println("employeeFirstName: " + testResult.getEmployeeFirstName()));
System.out.println("employeeLastName: " + testResult.getEmployeeLastName());
System.out.println("employeeDepartment: " + testResult.getEmployeeDepartment());
}
}
}
What is the simplest or ideal way to achieve this?
A simple way to achieve this would be to use Gson, an API provided by Google. You could write the Collection of ITestResult objects to a file. The toJson function will take the Collection of ITestResult objects and write them to the the given Appenable object, which in this case is a BufferedWriter which points to a file.
(untested, one sec, not at workstation)
Collection<ITestResult> results = iTestContext.getFailedTests().getAllResults();
new GsonBuilder()
.create()
.toJson(results, Files.newBufferedWriter(Paths.get("path", "to", "file")));
If your goal is to write to file eventually, you can also use jackson apis.
ObjectMapper mapper = new ObjectMapper();
//To add indentation to output json
mapper.enable(SerializationFeature.INDENT_OUTPUT);
Collection<ITestResult> results = iTestContext.getFailedTests().getAllResults();
try{
mapper.writeValue(new File("/somepath/output.json"), results);
catch (IOException){
e.printStackTrace();
}
Note: Recommended to use single instance of object mapper
For following snippet:
public static final class Node {
class Employee {
private final String employeeFirstName;
private final String employeeLastName;
private final String employeeDepartment;
public Employee(String employeeFirstName, String employeeLastName, String employeeDepartment) {
this.employeeFirstName = employeeFirstName;
this.employeeLastName = employeeLastName;
this.employeeDepartment = employeeDepartment;
}
}
List<Employee> employees = Arrays.asList(
new Employee("Mark", "Williams", "Sales"),
new Employee("John", "Carpenter", "Accounts"),
new Employee("David", "Hunter", "Marketing"));
// String json = ...
}
Using gson-utils
String json = GsonUtils.writeValue(data);
Using jackson-utils
String json = JacksonUtils.writeValue(data);

What is the cleanest way to unwrap nested JSON values with Jackson in Java?

I have a JSON which looks like this (number of fields heavily reduced for the sake of example):
{
"content": {
"id": {"content": "1"},
"param1": {"content": "A"},
"param2": {"content": "55"}
}
}
Keep in mind, that I don't have control over it, I can't change it, that is what I get from API.
I've created a POJO class for this looking like that:
public class PojoClass {
private String id;
private String param1;
private String param2;
// getters and setters
}
Then I parse JSON with Jackson (I have to use it, please don't suggest GSON or else):
ObjectMapper om = new ObjectMapper();
JsonNode jsonNode = om.readTree(json).get("content");
PojoClass table = om.readValue(jsonNode.toString(), PojoClass.class);
And this doesn't work, because of id, param1 and param2 having JSON in them, not straight values. The code works fine with JSON like this:
{
"content": {
"id": "1",
"param1": "A",
"param2": "55"
}
}
But unfortunately the values I need are stored under "content" fields.
What is the cleanest way to resolve this?
I understand that I can hardcode this and extract all values into variables one by one in constructor or something, but there are a lot of them, not just 3 like in this example and obviously this is not the correct way to do it.
You can modify the JsonNode elements like "id": {"content": "1"} to {"id": "1"} inside your json string accessing them as ObjectNode elements with an iterator and after deserialize the new json obtained {"id":"1","param1":"A","param2":"55"} like below:
String content = "content";
ObjectMapper om = new ObjectMapper();
JsonNode root = om.readTree(json).get(content);
Iterator<String> it = root.fieldNames();
while (it.hasNext()) {
String fieldName = it.next();
((ObjectNode)root).set(fieldName, root.get(fieldName).get(content));
}
PojoClass table = om.readValue(root.toString(), PojoClass.class);
System.out.println(table); //it will print PojoClass{id=1, param1=A, param2=55}

Jackson - Extract Data without Brackets, Commas, and =?

I don't know a ton about Jackson, I'm just using it because I needed to share data from Python to Java. Anyway my code is pretty simple
ObjectMapper mapper = new ObjectMapper();
Map<String,Object> data = mapper.readValue(new File(FileName), Map.class);
System.out.println(data.get("SomeInput"));
This is what I'm getting:
{Y=0.830168776371308, Z=0.16877637130801687, X=0.0010548523206751054}
I really just want to be able to use data to retrieve some type of data structure that holds the data without printing out the {} and the =, etc. Is there a method to do this?
I have a group of nodes, one node for each tag (such as ADP). I want to be able to give the ADP node 0.830... I can do this with the string, but it would involve some really annoying splitting of Strings. I'm assuming there must be an easy way to do this?
EDIT:
The data in the json file that I'm loading looks like this
{
"!": {
"X": 1.0
},
"$": {
"X": 1.0
},
"&": {
"X": 1.0
},
"/m": {
"Y": 1.0
},
.....
ObjectMapper mapper = new ObjectMapper();
Map<String,Object> data = mapper.readValue(new File(FileName), Map.class);
Map<String, Double> tags = (Map) data.get("SomeInput");
double value = 0;
for (String tag : tags.keySet()) {
value = tags.get(tag); //Here I get all the data from the tags inside the input. E.g.: 0.830168776371308
System.out.println(value); //It will print ADP, ADV and X values.
}
You already got a good answer on how to use Map. But for sake of completeness, there is another possibility that sometimes works even better, reading as a tree:
JsonNode root = mapper.readTree(new File(FileName));
JsonNode inputs = root.path("SomeInput");
String exclValue = inputs.path("!").asString();

Extract Specific JSON Object and Display Them Independently

I have data that looks like this
{
"status": "success",
"data": {
"data1": {
"serialNumber": "abc123",
"version": "1.6"
},
"data2": {
"irrelvent": [
"irrelvent",
"irrelvent"
]
},
"data3": {
"irrelevantLibs": {
"irrelevantFiles": [
"irrelevant.jar",
"irrelevant.jar",
"irrelevant.jar"
]
}
},
"data4": {
"configuration": "auth"
}
}
}
I am using the Jackson JSON Processor. What I need to do under the data object is to extract each data(x) into it's own data.
Hard to explain but I will try to be detailed. My intent is to make the JSON data more readable for our customers. So I'm trying to make the JSON data more friendly by splitting each data(x) object into blocks/tables on a website. So data1 will be displayed independently. Then data2 will be displayed independently and so on. So in this case I have four data(x) objects and I want to store those four objects into four different Strings and display them however I want. My problem is how do I get the Jackson Processor to do this?
Not sure if this is helpful but my current JSON function to process the JSON data is this:
public static String stringify(Object o) {
try {
ObjectMapper mapper = new ObjectMapper();
DefaultPrettyPrinter printer = new DefaultPrettyPrinter();
printer.indentArraysWith(new Lf2SpacesIndenter());
return mapper.writer(printer).writeValueAsString(o);
} catch (Exception e) {
return null;
}
}
I'm positive that I can manipulate the processor to get those data separated but I don't know where to start.
EDIT: Hmm, since Jackson seems to be a pretty difficult parser to work with, would it be easier if I used the Javascript JSON parser to extract only the data objects? Since I already have Jackson convert the JSON data into a String, using Javascript would work?
"Hmm, since Jackson seems to be a pretty difficult parser to work with, would it be easier if I used the Javascript JSON parser to extract only the data objects?"
Seeing as you are working with Java have you considered using Sling? http://sling.apache.org/ It is an external library which will allow you parser and explore JSON data structures quite swiftly, and most of all cleanly.
So I was able to figure it out after really digging into the documentation. I had to use JsonNode in order to extract what I wanted. Note that the variable appName is just there for me to easily display the string data(x) while iteNode is just all elements under data(x)
public static List<String> jsonSplit(String o) throws JsonParseException, JsonMappingException, IOException {
List<String> list = new ArrayList<String>();
ObjectMapper mapper = new ObjectMapper();
DefaultPrettyPrinter printer = new DefaultPrettyPrinter();
printer.indentArraysWith(new Lf2SpacesIndenter());
JsonNode rootNode = mapper.readValue(o, JsonNode.class);
Iterator<String> appName = rootNode.get("data").getFieldNames();
Iterator<JsonNode> iteNode = rootNode.get("data").getElements();
while (iteNode.hasNext()){
list.add(appName.next());
list.add(mapper.writer(printer).writeValueAsString(iteNode.next()));
}
return list;
}

Create Json String

I use Jackson library to generate json string like this:
ObjectMapper objectMapper = new ObjectMapper();
String str = objectMapper.writeValueAsString(model);
and this snipped code for instance generate somtething like this:
{"x" : "This is x", "y" : "This is y"}
but I want to generate something like this:
{'x' : 'This is x', 'y' : 'This is y'}
I mean how can I change the double quote string with single quote string.I try to change code like this:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
String str = objectMapper.writeValueAsString(model);
but this snipped code generate the first one.
and of course I can handle this problem with replace method but I want Jackson library do this for me.
How can I handle this problem?
objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); is about allowing single quotes in deserializing (JSON to Objects), not serializing (Objects to JSON) as you want.
In serializing, the issue seems to be with Jackson 1.X's default serializer. Below is the code that Jackson uses to write the String values. As you can see, the double quotes are hard coded and thus unchangeable through configuration:
#Override
public void writeString(String text)
throws IOException, JsonGenerationException
{
_verifyValueWrite("write text value");
if (text == null) {
_writeNull();
return;
}
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = '"'; // <----------------- opening quote
_writeString(text); // <----------------- string actual value
// And finally, closing quotes
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = '"'; // <----------------- closing quote
}
To achieve what you want, there are at least two options:
1: Replace the quotes using Regex:
This is a safe approach because Jackson gives the double quotes (") already escaped (\"). All you have to do is escape the single quotes and switch the " around properties names and values:
ObjectMapper objectMapper = new ObjectMapper();
String str = objectMapper.writeValueAsString(model);
System.out.println("Received.: "+str);
str = str.replaceAll("'", "\\\\'"); // escapes all ' (turns all ' into \')
str = str.replaceAll("(?<!\\\\)\"", "'"); // turns all "bla" into 'bla'
System.out.println("Converted: "+str);
Output:
Received.: {"x":"ab\"c","y":"x\"y'z","z":15,"b":true}
Converted: {'x':'ab\"c','y':'x\"y\'z','z':15,'b':true}
Or 2: User a custom JsonSerializer on every String field
Declare the custom serializer:
public class SingleQuoteStringSerializer extends JsonSerializer<String> {
#Override
public void serialize(String str, JsonGenerator jGen, SerializerProvider sP)
throws IOException, JsonProcessingException {
str = str.replace("'", "\\'"); // turns all ' into \'
jGen.writeRawValue("'" + str + "'"); // write surrounded by single quote
}
}
Use it in the fields you want to single quote:
public class MyModel {
#JsonSerialize(using = SingleQuoteStringSerializer.class)
private String x;
...
And proceed as usual (QUOTE_FIELD_NAMES == false is used to unquote the field names):
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, false);
String str = objectMapper.writeValueAsString(model);
System.out.println("Received.: "+str);
Output:
Received.: {x:'ab"c',y:'x"y\'z',z:15,b:true}
Note: Since you seem to be wanting to embed the JSON into another, this last approach may also require escaping the "s (see x:'ab"c').
Configure ObjectMapper in the following way:
final ObjectMapper mapper = new ObjectMapper();
mapper.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, false);
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
//this may be what you need
mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
Try looking into gson. It would look like this in gson.
House myHouse = new House();
Gson gson = new Gson();
String json = gson.toJson(myHouse);
Done...
http://code.google.com/p/google-gson/
As I said in the comment that's not valid JSON and it doesn't make any sense to escape it. You should handle it in a different way.
You should put that object inside a property.
I think you want to have something like
{"myString":"{\"fake json\":\"foo\"}"}
instead you should have:
{"myString":{"fake json":"foo"}}
That should be the proper way to handle this.

Categories

Resources