Creating hashmap from json data - java

I am working on a very simple application for a website, just a basic desktop application.
So I've figured out how to grab all of the JSON Data I need, and if possible, I am trying to avoid the use of external libraries to parse the JSON.
Here is what I am doing right now:
package me.thegreengamerhd.TTVPortable;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import me.thegreengamerhd.TTVPortable.Utils.Messenger;
public class Channel
{
URL url;
String data;
String[] dataArray;
String name;
boolean online;
int viewers;
int followers;
public Channel(String name)
{
this.name = name;
}
public void update() throws IOException
{
// grab all of the JSON data from selected channel, if channel exists
try
{
url = new URL("https://api.twitch.tv/kraken/channels/" + name);
URLConnection connection = url.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
data = new String(in.readLine());
in.close();
// clean up data a little, into an array
dataArray = data.split(",");
}
// channel does not exist, throw exception and close client
catch (Exception e)
{
Messenger.sendErrorMessage("The channel you have specified is invalid or corrupted.", true);
e.printStackTrace();
return;
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < dataArray.length; i++)
{
sb.append(dataArray[i] + "\n");
}
System.out.println(sb.toString());
}
}
So here is what is printed when I enter an example channel (which grabs data correctly)
{"updated_at":"2013-05-24T11:00:26Z"
"created_at":"2011-06-28T07:50:25Z"
"status":"HD [XBOX] Call of Duty Black Ops 2 OPEN LOBBY"
"url":"http://www.twitch.tv/zetaspartan21"
"_id":23170407
"game":"Call of Duty: Black Ops II"
"logo":"http://static-cdn.jtvnw.net/jtv_user_pictures/zetaspartan21-profile_image-121d2cb317e8a91c-300x300.jpeg"
"banner":"http://static-cdn.jtvnw.net/jtv_user_pictures/zetaspartan21-channel_header_image-7c894f59f77ae0c1-640x125.png"
"_links":{"subscriptions":"https://api.twitch.tv/kraken/channels/zetaspartan21/subscriptions"
"editors":"https://api.twitch.tv/kraken/channels/zetaspartan21/editors"
"commercial":"https://api.twitch.tv/kraken/channels/zetaspartan21/commercial"
"teams":"https://api.twitch.tv/kraken/channels/zetaspartan21/teams"
"features":"https://api.twitch.tv/kraken/channels/zetaspartan21/features"
"videos":"https://api.twitch.tv/kraken/channels/zetaspartan21/videos"
"self":"https://api.twitch.tv/kraken/channels/zetaspartan21"
"follows":"https://api.twitch.tv/kraken/channels/zetaspartan21/follows"
"chat":"https://api.twitch.tv/kraken/chat/zetaspartan21"
"stream_key":"https://api.twitch.tv/kraken/channels/zetaspartan21/stream_key"}
"name":"zetaspartan21"
"delay":0
"display_name":"ZetaSpartan21"
"video_banner":"http://static-cdn.jtvnw.net/jtv_user_pictures/zetaspartan21-channel_offline_image-b20322d22543539a-640x360.jpeg"
"background":"http://static-cdn.jtvnw.net/jtv_user_pictures/zetaspartan21-channel_background_image-587bde3d4f90b293.jpeg"
"mature":true}
Initializing User Interface - JOIN
All of this is correct. Now what I want to do, is to be able to grab, for example the 'mature' tag, and it's value. So when I grab it, it would be like as simple as:
// pseudo code
if(mature /*this is a boolean */ == true){ // do stuff}
So if you don't understand, I need to split away the quotes and semicolon between the values to retrieve a Key, Value.

It's doable with the following code :
public static Map<String, Object> parseJSON (String data) throws ParseException {
if (data==null)
return null;
final Map<String, Object> ret = new HashMap<String, Object>();
data = data.trim();
if (!data.startsWith("{") || !data.endsWith("}"))
throw new ParseException("Missing '{' or '}'.", 0);
data = data.substring(1, data.length()-1);
final String [] lines = data.split("[\r\n]");
for (int i=0; i<lines.length; i++) {
String line = lines[i];
if (line.isEmpty())
continue;
line = line.trim();
if (line.indexOf(":")<0)
throw new ParseException("Missing ':'.", 0);
String key = line.substring(0, line.indexOf(":"));
String value = line.substring(line.indexOf(":")+1);
if (key.startsWith("\"") && key.endsWith("\"") && key.length()>2)
key = key.substring(1, key.length()-1);
if (value.startsWith("{"))
while (i+1<line.length() && !value.endsWith("}"))
value = value + "\n" + lines[++i].trim();
if (value.startsWith("\"") && value.endsWith("\"") && value.length()>2)
value = value.substring(1, value.length()-1);
Object mapValue = value;
if (value.startsWith("{") && value.endsWith("}"))
mapValue = parseJSON(value);
else if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false"))
mapValue = new Boolean (value);
else {
try {
mapValue = Integer.parseInt(value);
} catch (NumberFormatException nfe) {
try {
mapValue = Long.parseLong(value);
} catch (NumberFormatException nfe2) {}
}
}
ret.put(key, mapValue);
}
return ret;
}
You can call it like that :
try {
Map<String, Object> ret = parseJSON(sb.toString());
if(((Boolean)ret.get("mature")) == true){
System.out.println("mature is true !");
}
} catch (ParseException e) {
}
But, really, you shouldn't do this, and use an already existing JSON parser, because this code will break on any complex or invalid JSON data (like a ":" in the key), and if you want to build a true JSON parser by hand, it will take you a lot more code and debugging !

This is a parser of an easy json string:
public static HashMap<String, String> parseEasyJson(String json) {
final String regex = "([^{}: ]*?):(\\{.*?\\}|\".*?\"|[^:{}\" ]*)";
json = json.replaceAll("\n", "");
Matcher m = Pattern.compile(regex).matcher(json);
HashMap<String, String> map = new HashMap<>();
while (m.find())
map.put(m.group(1), m.group(2));
return map;
}
Live Demo

Related

Return a value present from recursive function in Java

I am trying to extract a value from a while loop. In the output, I am able to capture the value in the Else statement but not able to return it when it is in the console log from the main statement. I want to be able to return "103" when I call the getValueFromkey() function.
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Iterator;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.XML;
public class Tesst {
static String line = "", str = "";
public static void main(String[] args) throws Exception {
String filepath = "C:/Users/Navi/Downloads/sample.xml";
BufferedReader br = new BufferedReader(new FileReader(filepath));
while ((line = br.readLine()) != null) {
str += line;
}
br.close();
JSONObject jsondata = XML.toJSONObject(str);
System.out.println("From main: " + getValueFromKey(jsondata, "routing_bic"));
}
private static Integer getValueFromKey(JSONObject json, String key) {
boolean exists = json.has(key);
Iterator<?> keys;
String nextKeys;
Integer foundKey = 0;
if(!exists) {
keys = json.keys();
while (keys.hasNext()) {
// Store next Key in nextKeys
nextKeys = (String)keys.next();
try {
// Check if the given Key is a JSON Object
if(json.get(nextKeys) instanceof JSONObject) {
// If Key does not exist
if(!exists) {
// Recursive function call
getValueFromKey(json.getJSONObject(nextKeys), key);
}
} else if (json.get(nextKeys) instanceof JSONArray) {
JSONArray jsonArray = json.getJSONArray(nextKeys);
for(int i = 0; i < jsonArray.length(); i++) {
String jsonArrayString = jsonArray.get(i).toString();
JSONObject innerJsonObject = new JSONObject(jsonArrayString);
// Recursive function call
if(!exists) {
getValueFromKey(innerJsonObject.getJSONObject(nextKeys), key);
}
}
}
} catch (Exception e) {
System.out.println(e);
}
}
} else {
// If key exists, print value
foundKey += parseObject(json, key);
System.out.println("From loop: " + foundKey);
return foundKey;
}
// System.out.println("Found Key = " + foundKey);
return 1; // Return 1 when key not found
}
private static Integer parseObject(JSONObject json, String key) {
System.out.println("From parseObject = " + json.get(key));
return (Integer) json.get(key);
}
}
Sample XML
<Test>
<BIBRq>
<UserId>123</UserId>
<CIFNo>123</CIFNo>
<CompanyId>asd</CompanyId>
<LegalId>123</LegalId>
<LegalIdType>ABC</LegalIdType>
<LegalIdCountry>ABC</LegalIdCountry>
</BIBRq>
<SubSvcRq>
<SubSvc>
<SubSvcRqHeader>
<SvcCode>ABCD</SvcCode>
<SubSvcSeq>1</SubSvcSeq>
<TxnRef>12345</TxnRef>
<ClientUserID/>
</SubSvcRqHeader>
<SubSvcRqDetail>
<ft_tnx_record>
<additional_field>
<account_details>
<routing_bic>103</routing_bic>
</account_details>
</additional_field>
</ft_tnx_record>
</SubSvcRqDetail>
</SubSvc>
</SubSvcRq>
</Test>
Output:
From parseObject = 103
From loop: 103
From main: 1
There are two errors in your code.
I notice that you recursively call the function getValueFromKey. That will never work if you don't assign the variable foundKey with the return value of the recursive invocation.
So, just change each recursive calls in this:
foundKey = getValueFromKey(..., key);
In addition, the last statement return 1 is wrong, because it will override any possible value returned by the subsequent recursive invocation. So, in replacement, you have to return always the foundKey variable.
I slightly changed your code and tested it with your sample file and it works fine. Differently than yours, I also wrapped the BufferedReader with try-with-resouce block, which I always prefer to simple try-catch, because it garantees that it closes the stream for you, even in case of exceptions.
Here is the code:
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.Iterator;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.XML;
public class Test {
static String line = "", str = "";
public static void main(String[] args) throws Exception {
String filepath = "C:\\Users\\marco\\Downloads\\sample.xml";
try ( BufferedReader br = new BufferedReader(new FileReader(filepath)); ) {
while ((line = br.readLine()) != null) {
str += line;
}
}
JSONObject jsondata = XML.toJSONObject(str);
System.out.println("From main: " + getValueFromKey(jsondata, "routing_bic"));
}
private static Integer getValueFromKey(JSONObject json, String key) {
boolean exists = json.has(key);
Iterator<?> keys;
String nextKeys;
Integer foundKey = 0;
if(!exists) {
keys = json.keys();
while (keys.hasNext()) {
// Store next Key in nextKeys
nextKeys = (String)keys.next();
try {
// Check if the given Key is a JSON Object
if(json.get(nextKeys) instanceof JSONObject) {
// If Key does not exist
if(!exists) {
// Recursive function call
foundKey = getValueFromKey(json.getJSONObject(nextKeys), key);
}
} else if (json.get(nextKeys) instanceof JSONArray) {
JSONArray jsonArray = json.getJSONArray(nextKeys);
for(int i = 0; i < jsonArray.length(); i++) {
String jsonArrayString = jsonArray.get(i).toString();
JSONObject innerJsonObject = new JSONObject(jsonArrayString);
// Recursive function call
if(!exists) {
foundKey = getValueFromKey(innerJsonObject.getJSONObject(nextKeys), key);
}
}
}
} catch (Exception e) {
System.out.println(e);
}
}
} else {
// If key exists, print value
foundKey += parseObject(json, key);
System.out.println("From loop: " + foundKey);
}
// System.out.println("Found Key = " + foundKey);
return foundKey; // Return 1 when key not found
}
private static Integer parseObject(JSONObject json, String key) {
System.out.println("From parseObject = " + json.get(key));
return (Integer) json.get(key);
}
}
And here is the output:
From parseObject = 103
From loop: 103
From main: 103

How to output my JSONObject, but nicer with different lines and indentation? [duplicate]

I'm using json-simple and I need to pretty-print JSON data (make it more human readable).
I haven't been able to find this functionality within that library.
How is this commonly achieved?
Google's GSON can do this in a nice way:
Gson gson = new GsonBuilder().setPrettyPrinting().create();
JsonParser jp = new JsonParser();
JsonElement je = jp.parse(uglyJsonString);
String prettyJsonString = gson.toJson(je);
or since it is now recommended to use the static parse method from JsonParser you can also use this instead:
Gson gson = new GsonBuilder().setPrettyPrinting().create();
JsonElement je = JsonParser.parseString​(uglyJsonString);
String prettyJsonString = gson.toJson(je);
Here is the import statement:
import com.google.gson.*;
Here is the Gradle dependency:
implementation 'com.google.code.gson:gson:2.8.7'
I used org.json built-in methods to pretty-print the data.
import org.json.JSONObject;
JSONObject json = new JSONObject(jsonString); // Convert text to object
System.out.println(json.toString(4)); // Print it with specified indentation
The order of fields in JSON is random per definition. A specific order is subject to parser implementation.
With Jackson (com.fasterxml.jackson.databind):
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObject))
From: How to enable pretty print JSON output (Jackson)
I know this is already in the answers, but I want to write it separately here because chances are, you already have Jackson as a dependency and so all you will need would be an extra line of code
It seems like GSON supports this, although I don't know if you want to switch from the library you are using.
From the user guide:
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String jsonOutput = gson.toJson(someObject);
Using org json. Reference link
JSONObject jsonObject = new JSONObject(obj);
String prettyJson = jsonObject.toString(4);
Using Gson. Reference link
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String json = gson.toJson(obj);
Using Jackson. Reference link
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
String json = mapper.writeValueAsString(obj);
Using Genson. Reference link.
Genson prettyGenson = new GensonBuilder().useIndentation(true).create();
String prettyJson = prettyGenson.serialize(obj);
Using javax.json. Reference link.
Map<String, Boolean> config = new HashMap<>();
config.put(JsonGenerator.PRETTY_PRINTING, true);
JsonWriterFactory writerFactory = Json.createWriterFactory(config);
Writer writer = new StringWriter();
writerFactory.createWriter(writer).write(jsonObject);
String json = writer.toString();
Using Moshi library. Reference link.
String json = jsonAdapter.indent(" ").toJson(emp1);
(OR)
Buffer buffer = new Buffer();
JsonWriter jsonWriter = JsonWriter.of(buffer);
jsonWriter.setIndent(" ");
jsonAdapter.toJson(jsonWriter, emp1);
json = buffer.readUtf8();
If you are using a Java API for JSON Processing (JSR-353) implementation then you can specify the JsonGenerator.PRETTY_PRINTING property when you create a JsonGeneratorFactory.
The following example has been originally published on my blog post.
import java.util.*;
import javax.json.Json;
import javax.json.stream.*;
Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JsonGenerator.PRETTY_PRINTING, true);
JsonGeneratorFactory jgf = Json.createGeneratorFactory(properties);
JsonGenerator jg = jgf.createGenerator(System.out);
jg.writeStartObject() // {
.write("name", "Jane Doe") // "name":"Jane Doe",
.writeStartObject("address") // "address":{
.write("type", 1) // "type":1,
.write("street", "1 A Street") // "street":"1 A Street",
.writeNull("city") // "city":null,
.write("verified", false) // "verified":false
.writeEnd() // },
.writeStartArray("phone-numbers") // "phone-numbers":[
.writeStartObject() // {
.write("number", "555-1111") // "number":"555-1111",
.write("extension", "123") // "extension":"123"
.writeEnd() // },
.writeStartObject() // {
.write("number", "555-2222") // "number":"555-2222",
.writeNull("extension") // "extension":null
.writeEnd() // }
.writeEnd() // ]
.writeEnd() // }
.close();
Pretty printing with GSON in one line:
System.out.println(new GsonBuilder().setPrettyPrinting().create().toJson(new JsonParser().parse(jsonString)));
Besides inlining, this is equivalent to the accepted answer.
My situation is my project uses a legacy (non-JSR) JSON parser that does not support pretty printing. However, I needed to produce pretty-printed JSON samples; this is possible without having to add any extra libraries as long as you are using Java 7 and above:
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine scriptEngine = manager.getEngineByName("JavaScript");
scriptEngine.put("jsonString", jsonStringNoWhitespace);
scriptEngine.eval("result = JSON.stringify(JSON.parse(jsonString), null, 2)");
String prettyPrintedJson = (String) scriptEngine.get("result");
Most of the existing answers either depend on some external library, or requiring a special Java version. Here is a simple code to pretty print a JSON string, only using general Java APIs (available in Java 7 for higher; haven't tried older version although).
The basic idea is to tigger the formatting based on special characters in JSON. For example, if a '{' or '[' is observed, the code will create a new line and increase the indent level.
Disclaimer: I only tested this for some simple JSON cases (basic key-value pair, list, nested JSON) so it may need some work for more general JSON text, like string value with quotes inside, or special characters (\n, \t etc.).
/**
* A simple implementation to pretty-print JSON file.
*
* #param unformattedJsonString
* #return
*/
public static String prettyPrintJSON(String unformattedJsonString) {
StringBuilder prettyJSONBuilder = new StringBuilder();
int indentLevel = 0;
boolean inQuote = false;
for(char charFromUnformattedJson : unformattedJsonString.toCharArray()) {
switch(charFromUnformattedJson) {
case '"':
// switch the quoting status
inQuote = !inQuote;
prettyJSONBuilder.append(charFromUnformattedJson);
break;
case ' ':
// For space: ignore the space if it is not being quoted.
if(inQuote) {
prettyJSONBuilder.append(charFromUnformattedJson);
}
break;
case '{':
case '[':
// Starting a new block: increase the indent level
prettyJSONBuilder.append(charFromUnformattedJson);
indentLevel++;
appendIndentedNewLine(indentLevel, prettyJSONBuilder);
break;
case '}':
case ']':
// Ending a new block; decrese the indent level
indentLevel--;
appendIndentedNewLine(indentLevel, prettyJSONBuilder);
prettyJSONBuilder.append(charFromUnformattedJson);
break;
case ',':
// Ending a json item; create a new line after
prettyJSONBuilder.append(charFromUnformattedJson);
if(!inQuote) {
appendIndentedNewLine(indentLevel, prettyJSONBuilder);
}
break;
default:
prettyJSONBuilder.append(charFromUnformattedJson);
}
}
return prettyJSONBuilder.toString();
}
/**
* Print a new line with indention at the beginning of the new line.
* #param indentLevel
* #param stringBuilder
*/
private static void appendIndentedNewLine(int indentLevel, StringBuilder stringBuilder) {
stringBuilder.append("\n");
for(int i = 0; i < indentLevel; i++) {
// Assuming indention using 2 spaces
stringBuilder.append(" ");
}
}
Now this can be achieved with the JSONLib library:
http://json-lib.sourceforge.net/apidocs/net/sf/json/JSONObject.html
If (and only if) you use the overloaded toString(int indentationFactor) method and not the standard toString() method.
I have verified this on the following version of the API:
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20140107</version>
</dependency>
Following the JSON-P 1.0 specs (JSR-353) a more current solution for a given JsonStructure (JsonObject or JsonArray) could look like this:
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import javax.json.Json;
import javax.json.JsonStructure;
import javax.json.JsonWriter;
import javax.json.JsonWriterFactory;
import javax.json.stream.JsonGenerator;
public class PrettyJson {
private static JsonWriterFactory FACTORY_INSTANCE;
public static String toString(final JsonStructure status) {
final StringWriter stringWriter = new StringWriter();
final JsonWriter jsonWriter = getPrettyJsonWriterFactory()
.createWriter(stringWriter);
jsonWriter.write(status);
jsonWriter.close();
return stringWriter.toString();
}
private static JsonWriterFactory getPrettyJsonWriterFactory() {
if (null == FACTORY_INSTANCE) {
final Map<String, Object> properties = new HashMap<>(1);
properties.put(JsonGenerator.PRETTY_PRINTING, true);
FACTORY_INSTANCE = Json.createWriterFactory(properties);
}
return FACTORY_INSTANCE;
}
}
In JSONLib you can use this:
String jsonTxt = JSONUtils.valueToString(json, 8, 4);
From the Javadoc:
You can use Gson like below
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String jsonString = gson.toJson(object);
From the post JSON pretty print using Gson
Alternatively, You can use Jackson like below
ObjectMapper mapper = new ObjectMapper();
String perttyStr = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(object);
From the post Pretty print JSON in Java (Jackson)
Hope this help!
Update: new JsonParser().parse(...) is #deprecated
Based on the javadoc for Gson 2.8.6:
No need to instantiate this class, use the static methods instead.
JsonParser static methods:
JsonParser.parseString​(jsonString);
JsonParser.parseReader​(reader);
Packages:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParser;
Example:
private Gson GSON = new GsonBuilder().setPrettyPrinting().create();
public static String getPerfectJSON(String unformattedJSON) {
String perfectJSON = GSON.toJson(JsonParser.parseString(unformattedJSON));
return perfectJSON;
}
Google Gson dependency using Maven:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
Reference:
JsonParser is deprecated
This worked for me, using Jackson:
mapper.writerWithDefaultPrettyPrinter().writeValueAsString(JSONString)
So I too like the json-simple lib, and looked into pretty printing its output. Unfortunately, while it's an open issue there, I couldn't find any code for it. So I thought I'd give it a try, here's what I came up with (using their own source)..
public class JsonPrinter {
public static String toJson(Map<?,?> map) {
StringBuilder out = new StringBuilder(32);
new JsonPrinter(out).print(map);
return out.toString();
}
public static String toJson(List<?> list) {
StringBuilder out = new StringBuilder(32);
new JsonPrinter(out).print(list);
return out.toString();
}
private final Appendable out;
private final String indentUnit;
private final String newLine;
private int indents;
public JsonPrinter(Appendable out) {
this(out, " ", System.lineSeparator());
}
/**
*
*/
public JsonPrinter(Appendable out, String indentUnit, String newLine) {
this.out = Objects.requireNonNull(out, "null out");
this.indentUnit = Objects.requireNonNull(indentUnit, "null indentUnit");
this.newLine = Objects.requireNonNull(newLine, "null newLine");
if (!indentUnit.isBlank())
throw new IllegalArgumentException(
"indentUnit must be a blank sequence (quoted): '" + indentUnit + "'");
if (!"\r\n".equals(newLine) && ! "\n".equals(newLine))
throw new IllegalArgumentException(
"unrecognized newLine (quoted): '" + newLine + "'");
}
public void print(List<?> list) throws UncheckedIOException {
try {
assert indents == 0;
printImpl(list);
assert indents == 0;
} catch (IOException iox) {
throw new UncheckedIOException("on print(List): " + list, iox);
}
}
public void print(Map<?,?> map) throws UncheckedIOException {
try {
assert indents == 0;
printImpl(map);
assert indents == 0;
} catch (IOException iox) {
throw new UncheckedIOException("on print(Map): " + map, iox);
}
}
protected void printImpl(List<?> list) throws IOException {
if (list == null) {
out.append("null");
return;
}
boolean first = true;
var iter = list.iterator();
open('[');
while (iter.hasNext()) {
if (first)
first = false;
else
out.append(',');
out.append(newLine);
appendIndents();
appendValue(iter.next());
}
close(']');
}
protected void printImpl(Map<?, ?> map) throws IOException {
if (map == null) {
out.append("null");
return;
}
boolean first = true;
var iter = map.entrySet().iterator();
open('{');
while (iter.hasNext()) {
if (first)
first = false;
else
out.append(',');
out.append(newLine);
appendIndents();
var entry = iter.next();
print(entry.getKey().toString(), entry.getValue());
}
close('}');
}
private void open(char c) throws IOException {
out.append(c);
++indents;
}
private void close(char c) throws IOException {
--indents;
out.append(newLine);
appendIndents();
out.append(c);
}
private void appendIndents() throws IOException {
for (int count = indents; count-- > 0; )
out.append(indentUnit);
}
private void print(String key, Object value) throws IOException {
out.append('"');
appendString(key);
out.append('"').append(':').append(' ');
appendValue(value);
}
private void appendString(String s) throws IOException {
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
switch(ch){
case '"':
out.append("\\\"");
break;
case '\\':
out.append("\\\\");
break;
case '\b':
out.append("\\b");
break;
case '\f':
out.append("\\f");
break;
case '\n':
out.append("\\n");
break;
case '\r':
out.append("\\r");
break;
case '\t':
out.append("\\t");
break;
case '/':
out.append("\\/");
break;
default:
//Reference: http://www.unicode.org/versions/Unicode5.1.0/
if ((ch>='\u0000' && ch<='\u001F') || (ch>='\u007F' && ch<='\u009F') || (ch>='\u2000' && ch<='\u20FF')) {
String ss = Integer.toHexString(ch);
out.append("\\u");
for (int k=0; k < 4-ss.length(); k++) {
out.append('0');
}
out.append(ss.toUpperCase());
}
else{
out.append(ch);
}
}
}//for
}
private void appendValue(Object value) throws IOException {
if (value == null) {
out.append("null");
} else if (value instanceof String) {
out.append('"');
appendString(value.toString());
out.append('"');
} else if (value instanceof Double) {
var num = (Double) value;
if (num.isInfinite() || num.isNaN())
out.append("null");
else
out.append(value.toString());
} else if (value instanceof Float) {
var num = (Float) value;
if (num.isInfinite() || num.isNaN())
out.append("null");
else
out.append(value.toString());
} else if (value instanceof Map) {
printImpl((Map<?,?>) value);
} else if (value instanceof List) {
printImpl((List<?>) value);
// } else if (value instanceof Number || value instanceof Boolean) {
// out.append(value.toString());
} else {
out.append(value.toString());
}
}
}
It works for JSONObject and JSONArray even tho it has no dependeny on them.. cuz these are regular Map and List objects resp. (and the fact code was lifted from same lib).
https://github.com/crums-io/io-util/blob/master/src/main/java/io/crums/util/json/JsonPrinter.java
You can use small json library
String jsonstring = ....;
JsonValue json = JsonParser.parse(jsonstring);
String jsonIndendedByTwoSpaces = json.toPrettyString(" ");
I also use the org.json.simple package. I have simply coded the formatter, but since I don't have nulls, numbers or booleans in my JSON objects in the program that I wrote, I only coded for strings, objects and arrays. If anyone is interested, let this just be in the public domain. You are welcome to add the missing data types (where it says in the comment "it's a string"). Also, you can add the indentation as a parameter whereas mine is just two spaces. Please reshare after you've tested your improvements.
Usage: printJsonObject(jsonObject, "");
Functions:
public static void printJsonObject(JSONObject object, String prefix) {
boolean notFirst = false;
System.out.println(prefix + "{");
for (Object key : object.keySet()) {
if (notFirst) {
System.out.println(", ");
}
notFirst = true;
Object value = object.get(key);
System.out.print(prefix + " " + "\"" + key + "\"" + ": ");
if (value instanceof JSONObject) {
printJsonObject((JSONObject) value, prefix + " ");
} else if (value instanceof JSONArray) {
printJsonArray((JSONArray) value, prefix + " ");
} else { // it's a string
System.out.print("\"" + value + "\"");
}
}
System.out.println("");
System.out.print(prefix + "}");
}
public static void printJsonArray(JSONArray array, String prefix) {
boolean notFirst = false;
System.out.println("[");
for (Object item : array) {
if (notFirst) {
System.out.println(", ");
}
notFirst = true;
if (item instanceof JSONObject) {
printJsonObject((JSONObject) item, prefix + " ");
} else if (item instanceof JSONArray) {
printJsonArray((JSONArray) item, prefix + " ");
} else {
System.out.print(prefix + " " + "\"" + item + "\"");
}
}
System.out.println("");
System.out.print(prefix + "]");
}
This would be a public method to print a pretty version of your object (You need the Gson dependency installed:
import com.google.gson.GsonBuilder;
...
public void printMe(){
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String prettyJSON = gson.toJson(this);
System.out.println(printable);
}
Underscore-java has static method U.formatJson(json).
Five format types are supported: 2, 3, 4, tabs and compact. Live example
import com.github.underscore.U;
import static com.github.underscore.Json.JsonStringBuilder.Step.TABS;
import static com.github.underscore.Json.JsonStringBuilder.Step.TWO_SPACES;
public class MyClass {
public static void main(String args[]) {
String json = "{\"Price\": {"
+ " \"LineItems\": {"
+ " \"LineItem\": {"
+ " \"UnitOfMeasure\": \"EACH\", \"Quantity\": 2, \"ItemID\": \"ItemID\""
+ " }"
+ " },"
+ " \"Currency\": \"USD\","
+ " \"EnterpriseCode\": \"EnterpriseCode\""
+ "}}";
System.out.println(U.formatJson(json, TWO_SPACES));
System.out.println(U.formatJson(json, TABS));
}
}
Output:
{
"Price": {
"LineItems": {
"LineItem": {
"UnitOfMeasure": "EACH",
"Quantity": 2,
"ItemID": "ItemID"
}
},
"Currency": "USD",
"EnterpriseCode": "EnterpriseCode"
}
}
{
"Price": {
"LineItems": {
"LineItem": {
"UnitOfMeasure": "EACH",
"Quantity": 2,
"ItemID": "ItemID"
}
},
"Currency": "USD",
"EnterpriseCode": "EnterpriseCode"
}
}

Reading input from a CSV to create multiple entries in a web form with Java and Selenium

So I am trying to create 5 different entries into a web form using Java Selenium.
With the code below it is reading from the CSV and inputting the first entry but then just adds the same data 5 times rather than the 5 different entries in the csv and I can't figure out where I have gone wrong?
#Then("^I can make multiple bookings$")
public void i_can_make_multiple_bookings() throws Throwable {
String csvFile = "hotelsDatas.csv";
BufferedReader br = null;
String line = "";
String cvsSplitBy = ",";
try {
br = new BufferedReader(new FileReader(csvFile));
while ((line = br.readLine()) != null) {
// Use comma as separator
String[] hotels = line.split(cvsSplitBy);
// Reading a line column by column
for (int i = 0; i < hotels.length; i++) {
System.out.print(hotels[i].replaceAll("\"", ""));
driver.findElement(By.id("firstName")).sendKeys(hotels[0].replaceAll("\"", ""));
driver.findElement(By.id("lastName")).sendKeys(hotels[1].replaceAll("\"", ""));
driver.findElement(By.id("totalPrice")).sendKeys(hotels[2].replaceAll("\"", ""));
driver.findElement(By.id("depositPaid")).sendKeys(hotels[3].replaceAll("\"", ""));
driver.findElement(By.id("checkIn")).sendKeys(hotels[4].replaceAll("\"", ""));
driver.findElement(By.id("checkOut")).sendKeys(hotels[5].replaceAll("\"", ""));
driver.findElement(By.id("createBooking")).click();
}
System.out.println(); // next line
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Why don't you just read in the CSV file first as a List<Map> and work from there?
After that, you can iterate over the List and for each Map, do things with each Key-Value pair.
import java.io.*;
import java.lang.reflect.Type;
import java.util.*;
import java.util.stream.Collectors;
import com.opencsv.CSVReader;
public class Reader {
public static List<Map<String, Object>> readCsv(String filename) throws IOException {
return readCsv(filename, null, null);
}
public static List<Map<String, Object>> readCsv(String filename, String[] headers) throws IOException {
return readCsv(filename, headers, null);
}
public static List<Map<String, Object>> readCsv(String filename, Type[] types) throws IOException {
return readCsv(filename, null, types);
}
public static List<Map<String, Object>> readCsv(String filename, String[] headers, Type[] types) throws IOException {
List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
InputStream is = Reader.class.getClassLoader().getResourceAsStream(filename);
InputStreamReader reader = new InputStreamReader(is);
CSVReader csv = new CSVReader(reader);
if (headers == null) {
headers = csv.readNext();
}
String[] row;
while ((row = csv.readNext()) != null) {
Map<String, Object> entry = new HashMap<String, Object>();
for (int i = 0; i < row.length; i++) {
String value = row[i];
if (types != null) {
if (types[i] == Double.class) {
entry.put(headers[i], Double.parseDouble(value));
} else if (types[i] == Date.class) {
entry.put(headers[i], new Date(Long.parseLong(value)));
} else if (types[i] == Boolean.class) {
entry.put(headers[i], new Boolean(value.toLowerCase().equals("true") || value.toLowerCase().equals("yes")));
} else {
entry.put(headers[i], value);
}
}
}
result.add(entry);
}
csv.close();
reader.close();
is.close();
return result;
}
public static void main(String[] args) {
try {
Type[] types = { String.class, String.class, Double.class, Boolean.class, Date.class, Date.class };
List<Map<String, Object>> records = readCsv("data.csv", types);
System.out.println(records.stream().map(Object::toString).collect(Collectors.joining(System.lineSeparator())));
} catch (IOException e) {
e.printStackTrace();
}
}
}
Input
firstName,lastName,totalPrice,depositPaid,checkIn,checkOut
Jane,Doe,200.00,yes,1512129600000,1512331200000
John,Smith,350.00,no,1512720000000,1512925200000
Output
{firstName=Jane, lastName=Doe, checkIn=Fri Dec 01 07:00:00 EST 2017, totalPrice=200.0, checkOut=Sun Dec 03 15:00:00 EST 2017, depositPaid=true}
{firstName=John, lastName=Smith, checkIn=Fri Dec 08 03:00:00 EST 2017, totalPrice=350.0, checkOut=Sun Dec 10 12:00:00 EST 2017, depositPaid=false}
Dependencies
Gradle
compile 'com.opencsv:opencsv:4.1'
or Maven
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>4.1</version>
<type>pom</type>
</dependency>
or Direct Download
>> opencsv-4.1 (jar)
Below code is causing you trouble:
String[] hotels = line.split(cvsSplitBy);
// Reading a line column by column
for (int i = 0; i < hotels.length; i++) {
System.out.print(hotels[i].replaceAll("\"", ""));
driver.findElement(By.id("firstName")).sendKeys(hotels[0].replaceAll("\"", ""));
driver.findElement(By.id("lastName")).sendKeys(hotels[1].replaceAll("\"", ""));
driver.findElement(By.id("totalPrice")).sendKeys(hotels[2].replaceAll("\"", ""));
driver.findElement(By.id("depositPaid")).sendKeys(hotels[3].replaceAll("\"", ""));
driver.findElement(By.id("checkIn")).sendKeys(hotels[4].replaceAll("\"", ""));
driver.findElement(By.id("checkOut")).sendKeys(hotels[5].replaceAll("\"", ""));
driver.findElement(By.id("createBooking")).click();
}
Lets suppose data in csv file looks like this:
"one","two","three","four","five","six","seven","eight","nine","ten"
You split data with , and create an instance of String[] with String[] hotels = line.split(cvsSplitBy);
This means your hotels[] array looks like this:
hotels[0] = "\"one\""; (I used String escape, because as I can see, you are replacing " in your code in for loop.
hotels[1] = "\"two\"";
hotels[2] = "\"three\"";
hotels[3] = "\"four\"";
hotels[4] = "\"five\"";
hotels[5] = "\"six\"";
hotels[6] = "\"seven\"";
hotels[7] = "\"eight\"";
hotels[8] = "\"nine\"";
hotels[9] = "\"ten\"";
Now take a look at for loop
for (int i = 0; i < hotels.length; i++)
Since the hotels.length gives you 10 elements, for loop wil be performed 10 times.
NOW TAKE A LOOK AT EACH ITERATION:
i=0
System.out.println will print one in the console.
driver will enter one in firstName
driver will enter two in lastName
driver will enter three in totalPrice
etc.
and it will click createBooking element.
AND IT WAS ONLY THE FIRST ITERATION.
When we go to iteration i=1 then System will print two. But since driver.findElement's code is in for loop, it will enter THE SAME DATA IN THE SAME FIELDS AGAIN. AND IT WILL KEEP DOING THAT OVER AND OVER, UNTIL ITERATION FINISHES.
You should get rid of for loop. You don't need it.

Comparing stock values in Array Java

I managed to print this website in JSON in Eclipse
https://www.quandl.com/api/v3/datasets/SSE/HYQ.json?start_date=2017-01-01&end_date=2017-01-31
As you can see, we have an array in which are stock values of a certain company. The array has a length of 22. For example:
["2017-01-27",89.13,87.611,88.18,87.699,750] //Array index 2
["2017-01-26",89.22,87.699,87.699,88.315,190]//Array index 3
["2017-01-31",86.77,84.312,84.32,84.81,1205]//Array index 0
My task is to check which one has the greater values. Like, checking if 89.13 is greater than 89.22? No, therefore checking if 89.22 > than 86.77, no and so on. And then printing out, at which date was the greatest value. The problem is to check that in Java. I don't know how to compare these 3 (not to mention 22)
EDIT: The logic is clear for me, my problem is to solve that in Java. An Example with these 3 given above would be nice.
Here is my code:
package query;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.util.*;
import java.io.*;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class Stockquery {
public static void main(String[] args) {
String jsonString = callURL(
"https://www.quandl.com/api/v3/datasets/SSE/HYQ.json?start_date=2017-01-01&end_date=2017-01-31");
try {
JSONObject jsonobjects = new JSONObject(jsonString);
JSONObject dataset = jsonobjects.getJSONObject("dataset");
JSONArray array = dataset.getJSONArray("data");
System.out.println(array.get(2));
System.out.println(array.get(3));
array.getString(0);
System.out.println(array.getString(0));
} catch (JSONException e) {
e.printStackTrace();
}
}
public static String callURL(String myURL) {
// System.out.println("Requested URL:" + myURL);
StringBuilder sb = new StringBuilder();
URLConnection urlConn = null;
InputStreamReader in = null;
try {
URL url = new URL(myURL);
urlConn = url.openConnection();
if (urlConn != null)
urlConn.setReadTimeout(60 * 1000);
if (urlConn != null && urlConn.getInputStream() != null) {
in = new InputStreamReader(urlConn.getInputStream(), Charset.defaultCharset());
BufferedReader bufferedReader = new BufferedReader(in);
if (bufferedReader != null) {
int cp;
while ((cp = bufferedReader.read()) != -1) {
sb.append((char) cp);
}
bufferedReader.close();
}
}
in.close();
} catch (Exception e) {
throw new RuntimeException("Exception while calling URL:" + myURL, e);
}
return sb.toString();
}
}
JSON array's element is a JSON element. Since JSON element can be a JSON array, a JSON array can contains JSON arrays as its elements.
Something like that will do it:
JSONArray array = dataset.getJSONArray("data");
// Save the first array's values
String biggestDate = array.get(0).get(0); // index 0 is the date
double biggest = array.get(0).get(1); // index 1 is the stock price
// Iterate over all arrays and update biggest
for (int i = 0; i < 22; i++) {
JSONArray arrayI = array.get(i);
if (arrayI.get(1) > biggest) {
biggest = arrayI.get(1); // updating biggest
biggestDate = arrayI.get(0); // updating biggest's date
}
}
return biggestDate;
Note: Not tested!
Of course, don't use 22 and other hard-coded constants
Used double for simplicity, use BigDecimal
Implement the method below.
private static String getDateWithMaxValue(JSONArray array) throws JSONException {
JSONArray stockData;
String dateWithMaxValue = "";
double maxValue = Double.MIN_VALUE;
for (int i = 0; i < array.length(); i++) {
stockData = array.getJSONArray(i);
if (stockData.get(1) instanceof Double) {
if (((Double) stockData.get(1)).doubleValue() > maxValue) {
maxValue = ((Double) stockData.get(1)).doubleValue();
if (stockData.get(0) instanceof String) {
dateWithMaxValue = (String) stockData.get(0);
}
}
}
}
return dateWithMaxValue;
}
And just add the call
System.out.println(getDateWithMaxValue(array));
in your main to print the date with the maximum value at index 1, where array is the JSONArray that you already declared.
(Code tested and returned date 2017-01-26, which is correct)
Did array.get(0).get(0) work for you?
For me not. I had to parse:
Optional<String> maxRow = array.toList().stream().map(Object::toString).max(new Comparator<String>() { #Override public int compare(String o1, String o2) {
return Double.valueOf(o1.split(",")[1]).compareTo(Double.valueOf(o2.split(",")[1])); }
});
System.out.println("Max row: " + maxRow.get());
which resulted with the "max" line:
Max row: [2017-01-26, 89.22, 87.699, 87.699, 88.315, 190.0]

Pretty JSON format with GAE Java [duplicate]

I'm using json-simple and I need to pretty-print JSON data (make it more human readable).
I haven't been able to find this functionality within that library.
How is this commonly achieved?
Google's GSON can do this in a nice way:
Gson gson = new GsonBuilder().setPrettyPrinting().create();
JsonParser jp = new JsonParser();
JsonElement je = jp.parse(uglyJsonString);
String prettyJsonString = gson.toJson(je);
or since it is now recommended to use the static parse method from JsonParser you can also use this instead:
Gson gson = new GsonBuilder().setPrettyPrinting().create();
JsonElement je = JsonParser.parseString​(uglyJsonString);
String prettyJsonString = gson.toJson(je);
Here is the import statement:
import com.google.gson.*;
Here is the Gradle dependency:
implementation 'com.google.code.gson:gson:2.8.7'
I used org.json built-in methods to pretty-print the data.
import org.json.JSONObject;
JSONObject json = new JSONObject(jsonString); // Convert text to object
System.out.println(json.toString(4)); // Print it with specified indentation
The order of fields in JSON is random per definition. A specific order is subject to parser implementation.
With Jackson (com.fasterxml.jackson.databind):
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObject))
From: How to enable pretty print JSON output (Jackson)
I know this is already in the answers, but I want to write it separately here because chances are, you already have Jackson as a dependency and so all you will need would be an extra line of code
It seems like GSON supports this, although I don't know if you want to switch from the library you are using.
From the user guide:
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String jsonOutput = gson.toJson(someObject);
Using org json. Reference link
JSONObject jsonObject = new JSONObject(obj);
String prettyJson = jsonObject.toString(4);
Using Gson. Reference link
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String json = gson.toJson(obj);
Using Jackson. Reference link
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
String json = mapper.writeValueAsString(obj);
Using Genson. Reference link.
Genson prettyGenson = new GensonBuilder().useIndentation(true).create();
String prettyJson = prettyGenson.serialize(obj);
Using javax.json. Reference link.
Map<String, Boolean> config = new HashMap<>();
config.put(JsonGenerator.PRETTY_PRINTING, true);
JsonWriterFactory writerFactory = Json.createWriterFactory(config);
Writer writer = new StringWriter();
writerFactory.createWriter(writer).write(jsonObject);
String json = writer.toString();
Using Moshi library. Reference link.
String json = jsonAdapter.indent(" ").toJson(emp1);
(OR)
Buffer buffer = new Buffer();
JsonWriter jsonWriter = JsonWriter.of(buffer);
jsonWriter.setIndent(" ");
jsonAdapter.toJson(jsonWriter, emp1);
json = buffer.readUtf8();
If you are using a Java API for JSON Processing (JSR-353) implementation then you can specify the JsonGenerator.PRETTY_PRINTING property when you create a JsonGeneratorFactory.
The following example has been originally published on my blog post.
import java.util.*;
import javax.json.Json;
import javax.json.stream.*;
Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JsonGenerator.PRETTY_PRINTING, true);
JsonGeneratorFactory jgf = Json.createGeneratorFactory(properties);
JsonGenerator jg = jgf.createGenerator(System.out);
jg.writeStartObject() // {
.write("name", "Jane Doe") // "name":"Jane Doe",
.writeStartObject("address") // "address":{
.write("type", 1) // "type":1,
.write("street", "1 A Street") // "street":"1 A Street",
.writeNull("city") // "city":null,
.write("verified", false) // "verified":false
.writeEnd() // },
.writeStartArray("phone-numbers") // "phone-numbers":[
.writeStartObject() // {
.write("number", "555-1111") // "number":"555-1111",
.write("extension", "123") // "extension":"123"
.writeEnd() // },
.writeStartObject() // {
.write("number", "555-2222") // "number":"555-2222",
.writeNull("extension") // "extension":null
.writeEnd() // }
.writeEnd() // ]
.writeEnd() // }
.close();
Pretty printing with GSON in one line:
System.out.println(new GsonBuilder().setPrettyPrinting().create().toJson(new JsonParser().parse(jsonString)));
Besides inlining, this is equivalent to the accepted answer.
My situation is my project uses a legacy (non-JSR) JSON parser that does not support pretty printing. However, I needed to produce pretty-printed JSON samples; this is possible without having to add any extra libraries as long as you are using Java 7 and above:
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine scriptEngine = manager.getEngineByName("JavaScript");
scriptEngine.put("jsonString", jsonStringNoWhitespace);
scriptEngine.eval("result = JSON.stringify(JSON.parse(jsonString), null, 2)");
String prettyPrintedJson = (String) scriptEngine.get("result");
Most of the existing answers either depend on some external library, or requiring a special Java version. Here is a simple code to pretty print a JSON string, only using general Java APIs (available in Java 7 for higher; haven't tried older version although).
The basic idea is to tigger the formatting based on special characters in JSON. For example, if a '{' or '[' is observed, the code will create a new line and increase the indent level.
Disclaimer: I only tested this for some simple JSON cases (basic key-value pair, list, nested JSON) so it may need some work for more general JSON text, like string value with quotes inside, or special characters (\n, \t etc.).
/**
* A simple implementation to pretty-print JSON file.
*
* #param unformattedJsonString
* #return
*/
public static String prettyPrintJSON(String unformattedJsonString) {
StringBuilder prettyJSONBuilder = new StringBuilder();
int indentLevel = 0;
boolean inQuote = false;
for(char charFromUnformattedJson : unformattedJsonString.toCharArray()) {
switch(charFromUnformattedJson) {
case '"':
// switch the quoting status
inQuote = !inQuote;
prettyJSONBuilder.append(charFromUnformattedJson);
break;
case ' ':
// For space: ignore the space if it is not being quoted.
if(inQuote) {
prettyJSONBuilder.append(charFromUnformattedJson);
}
break;
case '{':
case '[':
// Starting a new block: increase the indent level
prettyJSONBuilder.append(charFromUnformattedJson);
indentLevel++;
appendIndentedNewLine(indentLevel, prettyJSONBuilder);
break;
case '}':
case ']':
// Ending a new block; decrese the indent level
indentLevel--;
appendIndentedNewLine(indentLevel, prettyJSONBuilder);
prettyJSONBuilder.append(charFromUnformattedJson);
break;
case ',':
// Ending a json item; create a new line after
prettyJSONBuilder.append(charFromUnformattedJson);
if(!inQuote) {
appendIndentedNewLine(indentLevel, prettyJSONBuilder);
}
break;
default:
prettyJSONBuilder.append(charFromUnformattedJson);
}
}
return prettyJSONBuilder.toString();
}
/**
* Print a new line with indention at the beginning of the new line.
* #param indentLevel
* #param stringBuilder
*/
private static void appendIndentedNewLine(int indentLevel, StringBuilder stringBuilder) {
stringBuilder.append("\n");
for(int i = 0; i < indentLevel; i++) {
// Assuming indention using 2 spaces
stringBuilder.append(" ");
}
}
Now this can be achieved with the JSONLib library:
http://json-lib.sourceforge.net/apidocs/net/sf/json/JSONObject.html
If (and only if) you use the overloaded toString(int indentationFactor) method and not the standard toString() method.
I have verified this on the following version of the API:
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20140107</version>
</dependency>
Following the JSON-P 1.0 specs (JSR-353) a more current solution for a given JsonStructure (JsonObject or JsonArray) could look like this:
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import javax.json.Json;
import javax.json.JsonStructure;
import javax.json.JsonWriter;
import javax.json.JsonWriterFactory;
import javax.json.stream.JsonGenerator;
public class PrettyJson {
private static JsonWriterFactory FACTORY_INSTANCE;
public static String toString(final JsonStructure status) {
final StringWriter stringWriter = new StringWriter();
final JsonWriter jsonWriter = getPrettyJsonWriterFactory()
.createWriter(stringWriter);
jsonWriter.write(status);
jsonWriter.close();
return stringWriter.toString();
}
private static JsonWriterFactory getPrettyJsonWriterFactory() {
if (null == FACTORY_INSTANCE) {
final Map<String, Object> properties = new HashMap<>(1);
properties.put(JsonGenerator.PRETTY_PRINTING, true);
FACTORY_INSTANCE = Json.createWriterFactory(properties);
}
return FACTORY_INSTANCE;
}
}
In JSONLib you can use this:
String jsonTxt = JSONUtils.valueToString(json, 8, 4);
From the Javadoc:
You can use Gson like below
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String jsonString = gson.toJson(object);
From the post JSON pretty print using Gson
Alternatively, You can use Jackson like below
ObjectMapper mapper = new ObjectMapper();
String perttyStr = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(object);
From the post Pretty print JSON in Java (Jackson)
Hope this help!
Update: new JsonParser().parse(...) is #deprecated
Based on the javadoc for Gson 2.8.6:
No need to instantiate this class, use the static methods instead.
JsonParser static methods:
JsonParser.parseString​(jsonString);
JsonParser.parseReader​(reader);
Packages:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParser;
Example:
private Gson GSON = new GsonBuilder().setPrettyPrinting().create();
public static String getPerfectJSON(String unformattedJSON) {
String perfectJSON = GSON.toJson(JsonParser.parseString(unformattedJSON));
return perfectJSON;
}
Google Gson dependency using Maven:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
Reference:
JsonParser is deprecated
This worked for me, using Jackson:
mapper.writerWithDefaultPrettyPrinter().writeValueAsString(JSONString)
So I too like the json-simple lib, and looked into pretty printing its output. Unfortunately, while it's an open issue there, I couldn't find any code for it. So I thought I'd give it a try, here's what I came up with (using their own source)..
public class JsonPrinter {
public static String toJson(Map<?,?> map) {
StringBuilder out = new StringBuilder(32);
new JsonPrinter(out).print(map);
return out.toString();
}
public static String toJson(List<?> list) {
StringBuilder out = new StringBuilder(32);
new JsonPrinter(out).print(list);
return out.toString();
}
private final Appendable out;
private final String indentUnit;
private final String newLine;
private int indents;
public JsonPrinter(Appendable out) {
this(out, " ", System.lineSeparator());
}
/**
*
*/
public JsonPrinter(Appendable out, String indentUnit, String newLine) {
this.out = Objects.requireNonNull(out, "null out");
this.indentUnit = Objects.requireNonNull(indentUnit, "null indentUnit");
this.newLine = Objects.requireNonNull(newLine, "null newLine");
if (!indentUnit.isBlank())
throw new IllegalArgumentException(
"indentUnit must be a blank sequence (quoted): '" + indentUnit + "'");
if (!"\r\n".equals(newLine) && ! "\n".equals(newLine))
throw new IllegalArgumentException(
"unrecognized newLine (quoted): '" + newLine + "'");
}
public void print(List<?> list) throws UncheckedIOException {
try {
assert indents == 0;
printImpl(list);
assert indents == 0;
} catch (IOException iox) {
throw new UncheckedIOException("on print(List): " + list, iox);
}
}
public void print(Map<?,?> map) throws UncheckedIOException {
try {
assert indents == 0;
printImpl(map);
assert indents == 0;
} catch (IOException iox) {
throw new UncheckedIOException("on print(Map): " + map, iox);
}
}
protected void printImpl(List<?> list) throws IOException {
if (list == null) {
out.append("null");
return;
}
boolean first = true;
var iter = list.iterator();
open('[');
while (iter.hasNext()) {
if (first)
first = false;
else
out.append(',');
out.append(newLine);
appendIndents();
appendValue(iter.next());
}
close(']');
}
protected void printImpl(Map<?, ?> map) throws IOException {
if (map == null) {
out.append("null");
return;
}
boolean first = true;
var iter = map.entrySet().iterator();
open('{');
while (iter.hasNext()) {
if (first)
first = false;
else
out.append(',');
out.append(newLine);
appendIndents();
var entry = iter.next();
print(entry.getKey().toString(), entry.getValue());
}
close('}');
}
private void open(char c) throws IOException {
out.append(c);
++indents;
}
private void close(char c) throws IOException {
--indents;
out.append(newLine);
appendIndents();
out.append(c);
}
private void appendIndents() throws IOException {
for (int count = indents; count-- > 0; )
out.append(indentUnit);
}
private void print(String key, Object value) throws IOException {
out.append('"');
appendString(key);
out.append('"').append(':').append(' ');
appendValue(value);
}
private void appendString(String s) throws IOException {
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
switch(ch){
case '"':
out.append("\\\"");
break;
case '\\':
out.append("\\\\");
break;
case '\b':
out.append("\\b");
break;
case '\f':
out.append("\\f");
break;
case '\n':
out.append("\\n");
break;
case '\r':
out.append("\\r");
break;
case '\t':
out.append("\\t");
break;
case '/':
out.append("\\/");
break;
default:
//Reference: http://www.unicode.org/versions/Unicode5.1.0/
if ((ch>='\u0000' && ch<='\u001F') || (ch>='\u007F' && ch<='\u009F') || (ch>='\u2000' && ch<='\u20FF')) {
String ss = Integer.toHexString(ch);
out.append("\\u");
for (int k=0; k < 4-ss.length(); k++) {
out.append('0');
}
out.append(ss.toUpperCase());
}
else{
out.append(ch);
}
}
}//for
}
private void appendValue(Object value) throws IOException {
if (value == null) {
out.append("null");
} else if (value instanceof String) {
out.append('"');
appendString(value.toString());
out.append('"');
} else if (value instanceof Double) {
var num = (Double) value;
if (num.isInfinite() || num.isNaN())
out.append("null");
else
out.append(value.toString());
} else if (value instanceof Float) {
var num = (Float) value;
if (num.isInfinite() || num.isNaN())
out.append("null");
else
out.append(value.toString());
} else if (value instanceof Map) {
printImpl((Map<?,?>) value);
} else if (value instanceof List) {
printImpl((List<?>) value);
// } else if (value instanceof Number || value instanceof Boolean) {
// out.append(value.toString());
} else {
out.append(value.toString());
}
}
}
It works for JSONObject and JSONArray even tho it has no dependeny on them.. cuz these are regular Map and List objects resp. (and the fact code was lifted from same lib).
https://github.com/crums-io/io-util/blob/master/src/main/java/io/crums/util/json/JsonPrinter.java
You can use small json library
String jsonstring = ....;
JsonValue json = JsonParser.parse(jsonstring);
String jsonIndendedByTwoSpaces = json.toPrettyString(" ");
I also use the org.json.simple package. I have simply coded the formatter, but since I don't have nulls, numbers or booleans in my JSON objects in the program that I wrote, I only coded for strings, objects and arrays. If anyone is interested, let this just be in the public domain. You are welcome to add the missing data types (where it says in the comment "it's a string"). Also, you can add the indentation as a parameter whereas mine is just two spaces. Please reshare after you've tested your improvements.
Usage: printJsonObject(jsonObject, "");
Functions:
public static void printJsonObject(JSONObject object, String prefix) {
boolean notFirst = false;
System.out.println(prefix + "{");
for (Object key : object.keySet()) {
if (notFirst) {
System.out.println(", ");
}
notFirst = true;
Object value = object.get(key);
System.out.print(prefix + " " + "\"" + key + "\"" + ": ");
if (value instanceof JSONObject) {
printJsonObject((JSONObject) value, prefix + " ");
} else if (value instanceof JSONArray) {
printJsonArray((JSONArray) value, prefix + " ");
} else { // it's a string
System.out.print("\"" + value + "\"");
}
}
System.out.println("");
System.out.print(prefix + "}");
}
public static void printJsonArray(JSONArray array, String prefix) {
boolean notFirst = false;
System.out.println("[");
for (Object item : array) {
if (notFirst) {
System.out.println(", ");
}
notFirst = true;
if (item instanceof JSONObject) {
printJsonObject((JSONObject) item, prefix + " ");
} else if (item instanceof JSONArray) {
printJsonArray((JSONArray) item, prefix + " ");
} else {
System.out.print(prefix + " " + "\"" + item + "\"");
}
}
System.out.println("");
System.out.print(prefix + "]");
}
This would be a public method to print a pretty version of your object (You need the Gson dependency installed:
import com.google.gson.GsonBuilder;
...
public void printMe(){
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String prettyJSON = gson.toJson(this);
System.out.println(printable);
}
Underscore-java has static method U.formatJson(json).
Five format types are supported: 2, 3, 4, tabs and compact. Live example
import com.github.underscore.U;
import static com.github.underscore.Json.JsonStringBuilder.Step.TABS;
import static com.github.underscore.Json.JsonStringBuilder.Step.TWO_SPACES;
public class MyClass {
public static void main(String args[]) {
String json = "{\"Price\": {"
+ " \"LineItems\": {"
+ " \"LineItem\": {"
+ " \"UnitOfMeasure\": \"EACH\", \"Quantity\": 2, \"ItemID\": \"ItemID\""
+ " }"
+ " },"
+ " \"Currency\": \"USD\","
+ " \"EnterpriseCode\": \"EnterpriseCode\""
+ "}}";
System.out.println(U.formatJson(json, TWO_SPACES));
System.out.println(U.formatJson(json, TABS));
}
}
Output:
{
"Price": {
"LineItems": {
"LineItem": {
"UnitOfMeasure": "EACH",
"Quantity": 2,
"ItemID": "ItemID"
}
},
"Currency": "USD",
"EnterpriseCode": "EnterpriseCode"
}
}
{
"Price": {
"LineItems": {
"LineItem": {
"UnitOfMeasure": "EACH",
"Quantity": 2,
"ItemID": "ItemID"
}
},
"Currency": "USD",
"EnterpriseCode": "EnterpriseCode"
}
}

Categories

Resources