can I set json to be pretty print only in some attributes? - java

I have a json with many attributes.
I want some of them to be inline. Meaning with no new break lines.
Here is my code today:
private String serializeToJson(T item) {
String json;
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
try {
json = ow.writeValueAsString(item);
} catch (IOException e) {
e.printStackTrace();
json = "";
}
return json;
}
how can I set it to be not "pretty print" for attribute path like this { "path" : { "segmentId" : 31788674, "nodeId" : 26161441, "x" : -74.236605 ...

I serialized this specific property to inline json string separately.
public ResultUiShort(ResultLong result) {
this.path = stringUtils.toInlineJson(result.path);
...
}
and
public <T> String toInlineJson(T item) {
String json;
ObjectWriter ow = new ObjectMapper().writer();
try {
json = ow.writeValueAsString(item);
} catch (IOException e) {
e.printStackTrace();
json = "";
}
return json;
}

Related

Gson append object to json file

I am currently working on a todo web application using Spring Boot. The problem I'm facing is that whenever I add an item it is not stored in my json file. This is my current json file:
[
{
"id": 0,
"task": "some task"
},
{
"id": 1,
"task": "some other task"
},
{
"id": 2,
"task": "some different task"
}
]
When I add my todo item with the application, it gets added to my dataprovider;
TodoDataProvider.java:
public class TodoDataProvider {
private static TodoDataProvider instance;
private List<TodoItem> todoItems = new ArrayList<>();
public static TodoDataProvider getInstance() {
if (instance == null) {
instance = new TodoDataProvider();
}
//read data from json
Gson gson = new Gson();
try {
FileReader reader = new FileReader("src/main/java/com/example/servingwebcontent/todos.json");
TodoItem[] tempTodos = gson.fromJson(reader, TodoItem[].class);
for (TodoItem tempTodo : tempTodos) {
instance.addTodo(tempTodo);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return instance;
}
... getters and setters
After I try to add this todo my json file becomes empty. What is the best way to add this new json object to the existing json file using gson?
This is the code where I add this item:
TodoController.java
#Controller
public class TodoController {
TodoDataProvider dataProvider = TodoDataProvider.getInstance();
#GetMapping("/")
public String greeting(Model model) {
model.addAttribute("todos", dataProvider.getTodoItems());
return "todo";
}
#PostMapping("/")
public String addTodo(Model model, #RequestParam("todoTask") String todoTask) {
TodoItem todoItem = new TodoItem(4, todoTask);
dataProvider.addTodo(todoItem);
Gson gson = new Gson();
try {
// TODO: 14-7-2022 add to json instead of replace
gson.toJson(dataProvider.getTodoItems(), new FileWriter("src/main/java/com/example/servingwebcontent/todos.json"));
} catch (IOException e) {
System.out.println(e.getMessage());
}
model.addAttribute("todos", dataProvider.getTodoItems());
return "redirect:/";
}
}

Appending JSONObjects when writing to a file

I'm trying to append JSONObjects inside a JSONArray that is called Records .
The first time I save it it saves it this way that is ok
{
"Records": [
{
"travelTime": 2,
"totalDistance": 0,
"pace": 0,
"kCalBurned": 0,
"latlng": "[lat\/lng: (-32.1521234,-63.66412321)]"
}
]
}
But when I try to append again a new jsonobject inside Records, it creates a new JSONArray for it, and I just want to append a new object inside records
{
"Records": [
{
"travelTime": 2,
"totalDistance": 0,
"pace": 0,
"kCalBurned": 0,
"latlng": "[lat\/lng: (-31.6432292,-63.3667462)]"
}
]
}{
"Records": [
{
"travelTime": 1,
"totalDistance": 0,
"pace": 0,
"kCalBurned": 0,
"latlng": "[lat\/lng: (-31.9522431,-64.3461241)]"
}
]
}
This is the code I use to save the Records
private void writeJsonData(long travelTime,float totalDistance, float pace, float kCalBurned, LinkedList<LatLng> latlng){
String jsonStr = "";
JSONObject records = new JSONObject();
try {
records.put("travelTime", travelTime);
records.put("totalDistance", totalDistance);
records.put("pace", pace);
records.put("kCalBurned", kCalBurned);
records.put("latlng", latlng);
JSONArray jsonArray = new JSONArray();
jsonArray.put(records);
JSONObject recordsObj = new JSONObject();
recordsObj.put("Records", jsonArray);
jsonStr = recordsObj.toString();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String file_name = "records.json";
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(new File(mContext.getFilesDir(),file_name),true);
fileOutputStream.write(jsonStr.getBytes());
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
You need a JSON parser so that you can locate the "Records" array inside the file and place the new data there. I used the "json simple" library (jar can be found here: https://code.google.com/archive/p/json-simple/downloads).
First you parse the file:
JSONParser parser = new JSONParser();
JSONObject records = null;
try {
records = (JSONObject) parser.parse(new FileReader("records.json"));
} catch (ParseException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
Then you locate the Records JSONArray. In there you want to append the new record:
JSONArray r = (JSONArray) records.get("Records");
Create the new record:
JSONObject NewObj = new JSONObject();
NewObj.put("travelTime", travelTime);
NewObj.put("totalDistance", totalDistance);
NewObj.put("pace", pace);
NewObj.put("kCalBurned", kCalBurned);
NewObj.put("latlng", latlng);
Add the new record to the "Records" JSONArray:
r.add(NewObj);
Write to file:
try (FileWriter file = new FileWriter("records.json")) {
file.write(records.toJSONString());
} catch (IOException ex) {
ex.printStackTrace();
}
Passing 2nd parameter to true in FileOutputStream constructor will
append jsonObject at the end of file.
To append it with JSON array inside Records object, you've to read the file first, append the new JSON object and write it back to file.
Use GSON library for conversion between java class & jSON. So you don't have to create JSON object manually each time by putting each key-pair.
Create a Java class to hold whole Records object
public class Record
{
#SerializedName("Records")
private List<Object> recordsList;
public Record()
{
this. recordsList = new ArrayList<>();
}
public List<Object> getRecordsList()
{
return recordsList;
}
}
Now create JAVA Model class to hold travel info
public class Travel {
private Integer travelTime;
private Integer totalDistance;
private Integer pace;
private Integer kCalBurned;
private LinkedList<LatLng> latlng;
public Integer getTravelTime() {
return travelTime;
}
public void setTravelTime(Integer travelTime) {
this.travelTime = travelTime;
}
public Integer getTotalDistance() {
return totalDistance;
}
public void setTotalDistance(Integer totalDistance) {
this.totalDistance = totalDistance;
}
public Integer getPace() {
return pace;
}
public void setPace(Integer pace) {
this.pace = pace;
}
public Integer getKCalBurned() {
return kCalBurned;
}
public void setKCalBurned(Integer kCalBurned) {
this.kCalBurned = kCalBurned;
}
public LinkedList<LatLng> getLatlng() {
return latlng;
}
public void setLatlng(LinkedList<LatLng> latlng) {
this.latlng = latlng;
}
}
Here is utility class with a function to append new JSON inside Records object. It will check if directory & file are created otherwise will create both.If file exist, it will read the file, append the new JSON object to list and write it back into the same file. You can change the directory & file name with yours.
Note: This class is written in Kotlin. Here is reference how to setup Android Studio for Kotlin
class Logger {
companion object {
private const val LOG_FILE_FOLDER = "Logs"
private const val LOG_FILE_NAME = "transaction"
private const val DATE_FORMAT = "yyyy-MM-dd"
private val logFileName: String
#SuppressLint("SimpleDateFormat")
get() {
var fileName = LOG_FILE_NAME
val dateFormat = SimpleDateFormat(DATE_FORMAT)
fileName += "_" + dateFormat.format(Date()) + ".json"
return fileName
}
fun logFile(json: Any) {
try {
val directoryPath = Environment.getExternalStorageDirectory().path + "/" + LOG_FILE_FOLDER
val loggingDirectoryPath = File(directoryPath)
var loggingFile = File("$directoryPath/$logFileName")
if (loggingDirectoryPath.mkdirs() || loggingDirectoryPath.isDirectory) {
var isFileReady = true
var isNewFile = false
if (!loggingFile.exists()) {
isFileReady = false
try {
loggingFile.createNewFile()
isNewFile = true
isFileReady = true
} catch (e: Exception) {
e.printStackTrace()
}
} else {
val lastFile = getLastFile(loggingFile.name, directoryPath)
loggingFile = File("$directoryPath/$lastFile")
val fileSize = getFileSize(loggingFile)
}
if (isFileReady) {
var jsonString: String? = null
if (!isNewFile) {
//Get already stored JsonObject
val stream = FileInputStream(loggingFile)
try {
val fileChannel = stream.channel
val mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size())
jsonString = Charset.defaultCharset().decode(mappedByteBuffer).toString()
} catch (e: Exception) {
e.printStackTrace()
} finally {
stream.close()
}
}
//Create record object
val record = if (!jsonString.isNullOrEmpty()) {
Gson().fromJson(jsonString, Record::class.java)
} else {
Record()
}
//Append the current json
record.recordList.add(json)
//create json to save
val jsonToSave = Gson().toJson(record)
val bufferedOutputStream: BufferedOutputStream
try {
bufferedOutputStream = BufferedOutputStream(FileOutputStream(loggingFile))
bufferedOutputStream.write(jsonToSave.toByteArray())
bufferedOutputStream.flush()
bufferedOutputStream.close()
} catch (e4: FileNotFoundException) {
e4.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
} finally {
System.gc()
}
}
}
} catch (ex: Exception) {
ex.printStackTrace()
}
}
}
}
At the end, you can log the file withlogFile method
Logger.Companion.logFile(travel);
Cheers :)

withDefaultPrettyPrinter() doesn't make the output be formatted

I want to save some json to file
This is my serializtion code:
private String serializeToJson(T item) {
String json;
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
try {
json = ow.writeValueAsString(item);
} catch (IOException e) {
e.printStackTrace();
json = "";
}
return json;
}
and yet my json is save to file not formatted:
e.g. part of it is:
{"path":{"segmentId":69798169,"nodeId":18477384,"x":-71.12074,"y":42.33235},"street":1,"altStreets":null,"distance":59,"length":178,"crossTime":49,"crossTimeWithoutRealTime":49,"tiles":[0,1],"clientIds":[166,177],"instruction":
Tried Jackson pretty print mapper?assumed object has implemented toString method
ObjectMapper mapper = new ObjectMapper();
  try {
    System.out.println("Default output:"+mapper.writeValueAsString(object));
  System.out.println("Pretty printing:\n"+mapper.defaultPrettyPrintingWriter().writeValueAsString(object));    
 

How to modify values of JsonObject / JsonArray directly?

Once i have parsed a JSON String into a GSON provided JsonObject class, (assume that i do not wish to parse it into any meaningful data objects, but strictly want to use JsonObject), how am i able to modify a field / value of a key directly?
I don't see an API that may help me.
https://static.javadoc.io/com.google.code.gson/gson/2.6.2/com/google/gson/JsonObject.html
Strangely, the answer is to keep adding back the property. I was half expecting a setter method. :S
System.out.println("Before: " + obj.get("DebugLogId")); // original "02352"
obj.addProperty("DebugLogId", "YYY");
System.out.println("After: " + obj.get("DebugLogId")); // now "YYY"
This works for modifying childkey value using JSONObject.
import used is
import org.json.JSONObject;
ex json:(convert json file to string while giving as input)
{
"parentkey1": "name",
"parentkey2": {
"childkey": "test"
},
}
Code
JSONObject jObject = new JSONObject(String jsoninputfileasstring);
jObject.getJSONObject("parentkey2").put("childkey","data1");
System.out.println(jObject);
output:
{
"parentkey1": "name",
"parentkey2": {
"childkey": "data1"
},
}
Since 2.3 version of Gson library the JsonArray class have a 'set' method.
Here's an simple example:
JsonArray array = new JsonArray();
array.add(new JsonPrimitive("Red"));
array.add(new JsonPrimitive("Green"));
array.add(new JsonPrimitive("Blue"));
array.remove(2);
array.set(0, new JsonPrimitive("Yelow"));
Another approach would be to deserialize into a java.util.Map, and then just modify the Java Map as wanted. This separates the Java-side data handling from the data transport mechanism (JSON), which is how I prefer to organize my code: using JSON for data transport, not as a replacement data structure.
It's actually all in the documentation.
JSONObject and JSONArray can both be used to replace the standard data structure.
To implement a setter simply call a remove(String name) before a put(String name, Object value).
Here's an simple example:
public class BasicDB {
private JSONObject jData = new JSONObject;
public BasicDB(String username, String tagline) {
try {
jData.put("username", username);
jData.put("tagline" , tagline);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public String getUsername () {
String ret = null;
try {
ret = jData.getString("username");
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return ret;
}
public void setUsername (String username) {
try {
jData.remove("username");
jData.put("username" , username);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public String getTagline () {
String ret = null;
try {
ret = jData.getString("tagline");
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return ret;
}
public static JSONObject convertFileToJSON(String fileName, String username, List<String> list)
throws FileNotFoundException, IOException, org.json.simple.parser.ParseException {
JSONObject json = new JSONObject();
String jsonStr = new String(Files.readAllBytes(Paths.get(fileName)));
json = new JSONObject(jsonStr);
System.out.println(json);
JSONArray jsonArray = json.getJSONArray("users");
JSONArray finalJsonArray = new JSONArray();
/**
* Get User form setNewUser method
*/
//finalJsonArray.put(setNewUserPreference());
boolean has = true;
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
finalJsonArray.put(jsonObject);
String username2 = jsonObject.getString("userName");
if (username2.equals(username)) {
has = true;
}
System.out.println("user name are :" + username2);
JSONObject jsonObject2 = jsonObject.getJSONObject("languages");
String eng = jsonObject2.getString("Eng");
String fin = jsonObject2.getString("Fin");
String ger = jsonObject2.getString("Ger");
jsonObject2.put("Eng", "ChangeEnglishValueCheckForLongValue");
System.out.println(" Eng : " + eng + " Fin " + fin + " ger : " + ger);
}
System.out.println("Final JSON Array \n" + json);
jsonArray.put(setNewUserPreference());
return json;
}

Marshalling list of elements in REST

I have a problem with sending ArrayList from server to my client using JAX-rs. I've got 4 classes:
Demo - there is starting REST server
FileDetails - there are 3 fields storing data
ConfigFiles - it has few methods for files and there is a list of FileDetails objects
RestServer - there is method GET
I've got the following code:
#XmlRootElement(name="FileDetails")
#Path("/easy")
public class RestSerwer {
#GET
#Path("/temporary")
#Produces("text/temporary")
public String methodGet() {
ConfigFiles cf = ConfigFiles.getInstance();
List<FileDetails> files = cf.getList();
try {
JAXBContext ctx = JAXBContext.newInstance(ArrayList.class, FileDetails.class);
Marshaller m = ctx.createMarshaller();
StringWriter sw = new StringWriter();
m.marshal(files, sw);
return sw.toString();
} catch (JAXBException e) {
e.printStackTrace();
}
return null;
}
}
At client side I've got GetRest:
public class GetRest{
HttpClient client = null;
GetMethod method = null;
private String url = null;
public GetRest(String url) {
this.url = url;
}
public String getBody(String urlDetail){
client = new HttpClient();
method = new GetMethod(url + urlDetail);
method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
new DefaultHttpMethodRetryHandler(3, false));
try {
client.executeMethod(method);
} catch (HttpException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
byte[] responseBody = null;
try {
responseBody = method.getResponseBody();
} catch (IOException e) {
e.printStackTrace();
}finally{
method.releaseConnection();
}
String str = new String(responseBody);
return str;
}
public String getFiles(){
return getBody("/easy/temporary");
}
}
When I try:
GetRest getRestClass = new GetRest("http://localhost:8185");
//List<FileDetails> cf = new ArrayList<FileDetails>();
String xxxx = getRestClass.getFiles(); // TODO
It throws:
Caused by: com.sun.istack.internal.SAXException2: unable to marshal type "java.util.ArrayList" as an element because it is missing an #XmlRootElement annotation
At server side.
Anybody can help me?
Thanks
You basically have 2 possibilities: Create you own class which is a wrapper on top of the List or write your own provider and inject it in jersey so that it knows how to marshall/unmarshall the arraylist. Here is a simple code for the first solution:
#XmlRootElement
public class MyListWrapper {
#XmlElement(name = "List")
private List<String> list;
public MyListWrapper() {/*JAXB requires it */
}
public MyListWrapper(List<String> stringList) {
list = stringList;
}
public List<String> getStringList() {
return list;
}
}

Categories