Remove JSON node from json object (a json file) in Java - java

I'm trying to remove few nodes from JSON file. But I'm getting class cast exception when I try to remove node.
java.lang.ClassCastException: class com.fasterxml.jackson.databind.node.TextNode cannot be cast to class com.fasterxml.jackson.databind.node.ObjectNode (com.fasterxml.jackson.databind.node.TextNode and com.fasterxml.jackson.databind.node.ObjectNode are in unnamed module of loader 'app')
I tried other stackoverflow useful links, but not working for me. Here is the code that I have written.
public static void removeNodes(String filePath, String... nodeNames) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNodes = objectMapper.readTree(new File(filePath));
for (JsonNode node : jsonNodes) {
((ObjectNode) node).remove(Arrays.asList(nodeNames));
}
objectMapper
.writerWithDefaultPrettyPrinter()
.writeValue(new File(filePath.split("\\.")[0] + "_modified.json"), jsonNodes);
}
This is the json file I'm reading.
{
"boolean_key": "--- true\n",
"empty_string_translation": "",
"key_with_description": "Check it out! This key has a description! (At least in some formats)",
"key_with_line-break": "This translations contains\na line-break.",
"nested": {
"deeply": {
"key": "Wow, this key is nested even deeper."
},
"key": "This key is nested inside a namespace."
},
"null_translation": null,
"pluralized_key": {
"one": "Only one pluralization found.",
"other": "Wow, you have %s pluralizations!",
"zero": "You have no pluralization."
},
"Dog_key": {
"nest": "Only one pluralization found.",
"sample_collection": [
"first item",
"second item",
"third item"
],
"Pest": "Only two pluralization found."
},
"simple_key": "Just a simple key with a simple message.",
"unverified_key": "This translation is not yet verified and waits for it. (In some formats we also export this status)"
}
Caller:
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.io.IOException;
// import static org.junit.jupiter.api.Assertions.*;
#RunWith(SpringRunner.class)
#SpringBootTest
class JSONUtilTest {
#Test
void removeNodes() throws IOException {
JSONUtil.removeNodes("D:\\data\\JSON_A.json", "pluralized_key", "Dog_key", "simple_key");
}
}
Can you help me to figure out what is causing the problem?

As mentioned in the comment, you need to first parse the JSON then do operations on it.
Read file.
Parse and convert it to JSONObject using JSONParser's parse() method.
Remove the nodes you want.
Using ObjectMapper's writerWithDefaultPrettyPrinter() method you get proper indentation and write that to output file.
Here is the code:
public static void removeNodes(String filePath, String... nodeNames) {
try (FileReader fileReader = new FileReader(filePath)) {
JSONParser jsonParser = new JSONParser();
JSONObject jsonObject = (JSONObject) jsonParser.parse(fileReader);
Stream<String> nodeStream = Stream.of(nodeNames);
nodeStream.forEach(jsonObject::remove);
ObjectMapper objectMapper = new ObjectMapper();
String jsonObjectPrettified = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObject);
FileWriter fileWriter = new FileWriter(filePath.split("\\.")[0] + "_modified.json");
fileWriter.write(jsonObjectPrettified);
fileWriter.close();
} catch (IOException | ParseException e) {
e.printStackTrace();
}
}

Related

JSON validation returns different results

I have created a minimal application in order to debug the following problem:
The application is creating a Java object which includes a GeoJsonPoint. When the object gets validated against an automatically created json schema, I receive different results when starting the application multiple times. For example, I am starting the application for 5 times and the result is "Json not valid!". When I start the application another time, I receive the result "Json successfully validated".
The error message when the json is not valid tells me:
/geoPosition/coordinates: instance type (array) does not match any allowed primitive type (allowed: [object])
The following line is randomly returning a different json schema:
JsonNode fstabSchema = schemaFactory.createSchema(inputObj.getClass());
I do not understand that this happens randomly. Has someone seen this behavior before?
To exclude dependency problems during runtime, I have created a jar with all dependencies (jar-with-dependencies)
Below are my files:
pom.xml dependencies:
<dependencies>
<dependency>
<groupId>com.github.reinert</groupId>
<artifactId>jjschema</artifactId>
<version>1.16</version>
</dependency>
<dependency>
<groupId>com.github.java-json-tools</groupId>
<artifactId>json-schema-validator</artifactId>
<version>2.2.12</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
<version>1.18.16</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>3.2.2</version>
</dependency>
</dependencies>
App.java:
package de.s2.json.test;
import java.util.ArrayList;
import com.github.fge.jsonschema.core.exceptions.ProcessingException;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
public class App
{
public static void main( String[] args )
{
Address address = new Address();
address.setCountry("Deutschland");
GeoJsonPoint geoPoint = new GeoJsonPoint(12, 23);
address.setGeoPosition(geoPoint);
ArrayList<String> ret = null;
try {
ret = Toolbox.validateJson(address);
} catch (ProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(ret != null) {
System.out.println("Json not valid!");
for (int i = 0; i < ret.size(); i++) {
System.out.println(ret.get(i));
}
} else {
System.out.println("Json successfully validated");
}
}
}
Toolbox.java:
package de.s2.json.test;
import java.util.ArrayList;
import java.util.Iterator;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.reinert.jjschema.v1.JsonSchemaV4Factory;
import com.github.fge.jsonschema.core.exceptions.ProcessingException;
import com.github.fge.jsonschema.core.report.ProcessingMessage;
import com.github.fge.jsonschema.core.report.ProcessingReport;
import com.github.fge.jsonschema.main.JsonSchema;
import com.github.fge.jsonschema.main.JsonSchemaFactory;
public class Toolbox {
public static <T> ArrayList<String> validateJson(T inputObj) throws ProcessingException {
com.github.reinert.jjschema.v1.JsonSchemaFactory schemaFactory = new JsonSchemaV4Factory();
schemaFactory.setAutoPutDollarSchema(true);
JsonNode fstabSchema = schemaFactory.createSchema(inputObj.getClass()); // <= here I get different results
final JsonSchemaFactory factory = JsonSchemaFactory.byDefault();
final JsonSchema schema = factory.getJsonSchema(fstabSchema);
ObjectMapper objectMapper = new ObjectMapper();
JsonNode baseReceiptJson = objectMapper.convertValue(inputObj, JsonNode.class);
ProcessingReport report;
report = schema.validate(baseReceiptJson);
ArrayList<String> validationErrorDetails = new ArrayList<String>();
if (!report.isSuccess()) {
StringBuilder builder = new StringBuilder();
builder.append("Not all required fields are filled with data");
builder.append(System.getProperty("line.separator"));
for (Iterator<ProcessingMessage> i = report.iterator(); i.hasNext();) {
ProcessingMessage msg = i.next();
builder.append(msg.asJson().findValue("instance").findValue("pointer").toString());
builder.append(": ");
builder.append(msg.getMessage());
String detail = msg.asJson().findValue("instance").findValue("pointer").toString() + ": " + msg.getMessage();
detail = detail.replace("\"", "");
validationErrorDetails.add(detail);
builder.append("\n");
}
return validationErrorDetails;
}
return null;
}
}
Address.java:
package de.s2.json.test;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.github.reinert.jjschema.Attributes;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
public class Address
{
#JsonProperty("country")
private String country = "";
#JsonProperty("geoPosition")
#Attributes(required=false, description="longitude and latitude (it is initialized with 0,0)")
private GeoJsonPoint geoPosition = new GeoJsonPoint(0, 0);
}
Thank you very much for your support!
Update 1:
Answer to Hiran Chaudhuri
If the validation fails, then the schema looks like this:
{
"type": "object",
"properties": {
"country": {
"type": "string"
},
"geoPosition": {
"type": "object",
"properties": {
"coordinates": {
"type": "object"
},
"TYPE": {
"type": "string"
},
"x": {
"type": "number"
},
"y": {
"type": "number"
}
},
"description": "longitude and latitude (it is initialized with 0,0 which is inside the ocean)"
}
},
"$schema": "http://json-schema.org/draft-04/schema#"
}
If it is successful, then it looks like this:
{
"type": "object",
"properties": {
"country": {
"type": "string"
},
"geoPosition": {
"type": "object",
"properties": {
"coordinates": {
"type": "array",
"items": {
"type": "number"
}
},
"TYPE": {
"type": "string"
},
"x": {
"type": "number"
},
"y": {
"type": "number"
}
},
"description": "longitude and latitude (it is initialized with 0,0 which is inside the ocean)"
}
},
"$schema": "http://json-schema.org/draft-04/schema#"
}
As already in the error message indicated, one time the coordinates are an 'object' the other time an 'array'
Update 2
As this issue is blocking me to continue with my project, I have added an "ugly hack" to check in the schema if it contains a GeoJsonPoint. If it is included, it will patch it with the correct values.
package de.s2.json.test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.github.reinert.jjschema.v1.JsonSchemaV4Factory;
import com.github.fge.jsonschema.core.exceptions.ProcessingException;
import com.github.fge.jsonschema.core.report.ProcessingMessage;
import com.github.fge.jsonschema.core.report.ProcessingReport;
import com.github.fge.jsonschema.main.JsonSchema;
import com.github.fge.jsonschema.main.JsonSchemaFactory;
public class Toolbox {
public static <T> ArrayList<String> validateJson(T inputObj) throws ProcessingException {
com.github.reinert.jjschema.v1.JsonSchemaFactory schemaFactory = new JsonSchemaV4Factory();
schemaFactory.setAutoPutDollarSchema(true);
JsonNode fstabSchema = schemaFactory.createSchema(inputObj.getClass());
ArrayList<String> validationErrorDetails = new ArrayList<String>();
// *****************************************************************************************
// /!\ this is an ugly hack /!\
// Randomly the function createSchema() returns an 'array' or 'object' type for coordinates
// of the geoJsonPoint. The correct value should be array. The following code checks if a
// geoJsonPoint is inside the schema and overwrites it with the correct value.
// TODO: fix this issue correctly
// *****************************************************************************************
try {
String jsonCoordinate = "{\"type\": \"array\",\"items\": {\"type\": \"number\"}}";
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNodeCoordinate = mapper.readTree(jsonCoordinate);
JsonNode coordJsonNode = fstabSchema.findValue("geoPosition").get("properties");
ObjectNode coordObjNode = (ObjectNode) coordJsonNode;
coordObjNode.set("coordinates", jsonNodeCoordinate);
} catch (JsonProcessingException e) {
validationErrorDetails.add("Could not patch geoPosition");
return validationErrorDetails;
} catch (IOException e) {
validationErrorDetails.add("Could not patch geoPosition");
return validationErrorDetails;
} catch (NullPointerException e) {
// this means that geoPosition could not be found
// we do nothing ...
}
// ******************
final JsonSchemaFactory factory = JsonSchemaFactory.byDefault();
final JsonSchema schema = factory.getJsonSchema(fstabSchema);
ObjectMapper objectMapper = new ObjectMapper();
JsonNode baseReceiptJson = objectMapper.convertValue(inputObj, JsonNode.class);
ProcessingReport report;
report = schema.validate(baseReceiptJson);
if (!report.isSuccess()) {
StringBuilder builder = new StringBuilder();
builder.append("Not all required fields are filled with data");
builder.append(System.getProperty("line.separator"));
for (Iterator<ProcessingMessage> i = report.iterator(); i.hasNext();) {
ProcessingMessage msg = i.next();
builder.append(msg.asJson().findValue("instance").findValue("pointer").toString());
builder.append(": ");
builder.append(msg.getMessage());
String detail = msg.asJson().findValue("instance").findValue("pointer").toString() + ": " + msg.getMessage();
detail = detail.replace("\"", "");
validationErrorDetails.add(detail);
builder.append("\n");
}
return validationErrorDetails;
}
return null;
}
}
By serializing the JSON Schema you generated we are able now to compare whether they are the same or how much they actually differ. Take into account that the method to generate a schema requires some input parameter.
I was never a friend of generating a schema based on actual data.
Why do you not strictly define the schema you want and let your code measure whether you really meet that structure? This way you can use the schema as a contract between application components since it is documented and not generated on the fly.
This is still no answer to the question why this happens randomly. But it is maybe a better practice to follow for you and others reading along.

Manipulate a JSON file and parse it into an Object after manipulation is done - in memory

My main goal is to get the information out of a JSON file and manipulate it in memory (trying to solve syntax issues in memory). Afterward, parse the manipulated value into an Object with com.google.gson.JsonParser and leave the old File as it was in the beginning (with the syntax errors included).
I managed to manipulate the File with RandomAccessFile and Parse it afterward while using "new FileReader". But after running through the code I noticed that the "old" file was modified and that shouldn't be the case. I don't want to change the file itself but the content and parse it into an Object with JsonParser or whatever Parser there is available for this.
import com.google.gson.JsonArray;
import com.google.gson.JsonParser;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.RandomAccessFile;
public class JsonLoggingParser {
public static final void main(String[] args) {
String path = "C:\\CEC\\Dev\\logs\\BIMBO\\2019-04-12asdf.json";
parseJsonLogFile(path);
}
public static void parseJsonLogFile(String filePath){
try {
File f = new File(filePath);
RandomAccessFile randomAccessFile = new RandomAccessFile(f, "rw");
randomAccessFile.seek(0);
randomAccessFile.write("[{".getBytes());
randomAccessFile.seek(f.length());
randomAccessFile.write("]".getBytes());
randomAccessFile.close();
JsonParser jsonParser = new JsonParser();
Object object = jsonParser.parse(new FileReader(f));
JsonArray jsonArray = (JsonArray)object;
System.out.println(jsonArray.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
This is how my JSON file looks like:
{
"788ad1bc-e9c8-4be5-b5b6-26ba011dc40e-request": {
"date": "2019-04-15 10:28:58.943",
"url": "/BIMBO/credit",
"handleType": "request",
"status": "200",
"request": "Hello There",
"response": "",
"performanceDuration": "",
"principalID": "123456789"
}
},{
"788ad1bc-e9c8-4be5-b5b6-26ba011dc40e-response": {
"date": "2019-04-15 10:28:59.125",
"url": "/BIMBO/credit",
"handleType": "response",
"status": "422",
"request": "",
"response": "Hello Back",
"performanceDuration": "218.696979ms",
"principalID": ""
}
}
Basically I need to add a "[" and "]" at the beginning/end of the file to solve the syntax issue.
The json is not melformed in any way, its just a map like Map<String, Objekt> a TypeToken might help solve youre problem:
gson.fromJson(reader, new TypeToken<HashMap<String, class>>() {}.getType());
if you have a fileWriter it will overright data
example data:
Hello world
if you write a K at 0 it will look like this
Kello world

Parse Json with Children Parameters

I'm a little clueless on this subject, but I'm trying to parse some Json into variables using GSON.
Here's an example of part of the Json I'm trying to parse. The goal is to get an array of objects containing the .ogg path(i.e. "minecraft/sounds/mob/stray/death2.ogg") as well as its corresponding hash variable.
{
"objects": {
"minecraft/sounds/mob/stray/death2.ogg": {
"hash": "d48940aeab2d4068bd157e6810406c882503a813",
"size": 18817
},
"minecraft/sounds/mob/husk/step4.ogg": {
"hash": "70a1c99c314a134027988106a3b61b15389d5f2f",
"size": 9398
}
}
Any help or suggestions on how to get that sort of result with GSON would be appreciated.
Xeyeler , the following is a solution that will work. A better way is to look at how GSON can convert this to an object directly. I have not tried it though
import java.util.Map;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
public class MainProgram {
public static void main(String[] args) {
String mineCraft = "{ \"objects\": { \"minecraft/sounds/mob/stray/death2.ogg\": { \"hash\": \"d48940aeab2d4068bd157e6810406c882503a813\", \"size\": 18817 }, \"minecraft/sounds/mob/husk/step4.ogg\": { \"hash\": \"70a1c99c314a134027988106a3b61b15389d5f2f\", \"size\": 9398 }}}";
JsonParser parser = new JsonParser();
JsonObject objects = parser.parse(mineCraft).getAsJsonObject().get("objects").getAsJsonObject();
for (Map.Entry<String, JsonElement> entry : objects.entrySet()) {
String oggFileName = entry.getKey();
JsonElement attributes = entry.getValue();
System.out.println(
"Key is " + oggFileName + " and the hash value is " + attributes.getAsJsonObject().get("hash"));
}
}
}

How to read multiple JSON docs in single JSON file using Java?

I am new on JSON, I want to read the JSON document using device id, I have many document on single file, just like as a database:
{
"deviceType":"AccessPoint",
"transactionType":"response",
"messageType":"set_config",
"classes":[
{
"deviceType":"AccessPoint",
"classId":1,
"ipv4":"192.168.100.100",
"netmask":"192.168.100.100",
"ipv6":"192.168.100.100",
"className":"Interface",
"interfaceName":"wlan0",
"state":"UP",
"type":"wireless",
"deviceId":"1234",
"status":"waiting"
}
],
"deviceId":"1234",
"transactionId":"201675"
}
Sometimes, classes array contain multiple arrays like indexes [{},{},..].
So, how can I read the doc using search criteria with java web application.
Just out of curiosity , did something on Jackson (streaming parser , since there is mention of large number of elements). I am just doing an output as name : value , this can be logically enhanced to suit your tastes. This is not even close to production , but is a good start.
import java.io.FileInputStream;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
public class TestClass {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("yourpath/transactions.json")) {
JsonFactory jf = new JsonFactory();
JsonParser jp = jf.createParser(fis);
//System.out.println(JsonToken.START_ARRAY);
// jp.setCodec(new ObjectMapper());
jp.nextToken();
while (jp.hasCurrentToken()) {
if (jp.getCurrentToken().equals(JsonToken.START_OBJECT)
|| jp.getCurrentToken().equals(JsonToken.START_ARRAY)
|| jp.getCurrentToken().equals(JsonToken.END_ARRAY)
|| jp.getCurrentToken().equals(JsonToken.END_OBJECT)) {
} else {
System.out.print(jp.getText());
jp.nextToken();
System.out.print(":");
System.out.print(jp.getText());
System.out.println();
}
jp.nextToken();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

Creating array list of java objects from JSON URL with Gson

I am able to parse the following data into a java object:
{
"name": "testname",
"address": "1337 455 ftw",
"type": "sometype",
"notes": "cheers mate"
}
using this code:
public class Test
{
public static void main (String[] args) throws Exception
{
URL objectGet = new URL("http://10.0.0.4/file.json");
URLConnection yc = objectGet.openConnection();
BufferedReader in = new BufferedReader(
new InputStreamReader(
yc.getInputStream()));
Gson gson = new Gson();
try {
DataO data = new Gson().fromJson(in, DataO.class);
System.out.println(data.getName());
}catch (Exception e) {
e.printStackTrace();
}
}
}
But now I want to store a list of these objects out of the following JSON String:
[
{
"name": "testname",
"address": "1337 455 ftw",
"type": "sometype",
"notes": "cheers mate"
},
{
"name": "SumYumStuff",
"address": "no need",
"type": "clunkdroid",
"notes": "Very inefficient but high specs so no problem."
}
]
Could someone help me modify my code to do this?
You could specify the type to deserialize into as an array or as a collection.
As Array:
import java.io.FileReader;
import com.google.gson.Gson;
public class GsonFoo
{
public static void main(String[] args) throws Exception
{
Data0[] data = new Gson().fromJson(new FileReader("input.json"), Data0[].class);
System.out.println(new Gson().toJson(data));
}
}
class Data0
{
String name;
String address;
String type;
String notes;
}
As List:
import java.io.FileReader;
import java.util.List;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
public class GsonFoo
{
public static void main(String[] args) throws Exception
{
List<Data0> data = new Gson().fromJson(new FileReader("input.json"), new TypeToken<List<Data0>>(){}.getType());
System.out.println(new Gson().toJson(data));
}
}
A quick look in the Gson User Guide indicates that this might not be possible since the deserializer doesn't know the type of the elements since you could have elements of different types in the array.
Collections Limitations
Can serialize collection of arbitrary objects but can not deserialize
from it Because there is no way for the user to indicate the type of
the resulting object While deserializing, Collection must be of a
specific generic type

Categories

Resources