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"));
}
}
}
Related
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();
}
}
I store all static data in the JSON file. This JSON file has up to 1000 rows. How to get the desired data without storing all rows as ArrayList?
My code, I'm using right now and I want to increase its efficiency.
List<Colors> colorsList = new ObjectMapper().readValue(resource.getFile(), new TypeReference<Colors>() {});
for(int i=0; i<colorsList.size(); i++){
if(colorsList.get(i).getColor.equals("Blue")){
return colorsList.get(i).getCode();
}
}
Is it possible? My goal is to increase efficiency without using ArrayList. Is there a way to make the code like this?
Colors colors = new ObjectMapper().readValue(..."Blue"...);
return colors.getCode();
Resource.json
[
...
{
"color":"Blue",
"code":["012","0324","15478","7412"]
},
{
"color":"Red",
"code":["145","001","1","7879","123984","89"]
},
{
"color":"White",
"code":["7","11","89","404"]
}
...
]
Colors.java
class Colors {
private String color;
private List<String> code;
public Colors() {
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public List<String> getCode() {
return code;
}
public void setCode(List<String> code) {
this.code = code;
}
#Override
public String toString() {
return "Colors{" +
"color='" + color + '\'' +
", code=" + code +
'}';
}
}
Creating POJO classes in this case is a wasting because we do not use the whole result List<Colors> but only one internal property. To avoid this we can use native JsonNode and ArrayNode data types. We can read JSON using readTree method, iterate over array, find given object and finally convert internal code array. It could look like below:
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class JsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
ObjectMapper mapper = new ObjectMapper();
ArrayNode rootArray = (ArrayNode) mapper.readTree(jsonFile);
int size = rootArray.size();
for (int i = 0; i < size; i++) {
JsonNode jsonNode = rootArray.get(i);
if (jsonNode.get("color").asText().equals("Blue")) {
Iterator<JsonNode> codesIterator = jsonNode.get("code").elements();
List<String> codes = new ArrayList<>();
codesIterator.forEachRemaining(n -> codes.add(n.asText()));
System.out.println(codes);
break;
}
}
}
}
Above code prints:
[012, 0324, 15478, 7412]
Downside of this solution is we load the whole JSON to memory which could be a problem for us. Let's try to use Streaming API to do that. It is a bit difficult to use and you must know how your JSON payload is constructed but it is the fastest way to get code array using Jackson. Below implementation is naive and does not handle all possibilities so you should not rely on it:
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class JsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
System.out.println(getBlueCodes(jsonFile));
}
private static List<String> getBlueCodes(File jsonFile) throws IOException {
try (JsonParser parser = new JsonFactory().createParser(jsonFile)) {
while (parser.nextToken() != JsonToken.END_OBJECT) {
String fieldName = parser.getCurrentName();
// Find color property
if ("color".equals(fieldName)) {
parser.nextToken();
// Find Blue color
if (parser.getText().equals("Blue")) {
// skip everything until start of the array
while (parser.nextToken() != JsonToken.START_ARRAY) ;
List<String> codes = new ArrayList<>();
while (parser.nextToken() != JsonToken.END_ARRAY) {
codes.add(parser.getText());
}
return codes;
} else {
// skip current object because it is not `Blue`
while (parser.nextToken() != JsonToken.END_OBJECT) ;
}
}
}
}
return Collections.emptyList();
}
}
Above code prints:
[012, 0324, 15478, 7412]
At the end I need to mention about JsonPath solution which also can be good if you can use other library:
import com.jayway.jsonpath.JsonPath;
import net.minidev.json.JSONArray;
import java.io.File;
import java.util.List;
import java.util.stream.Collectors;
public class JsonPathApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
JSONArray array = JsonPath.read(jsonFile, "$[?(#.color == 'Blue')].code");
JSONArray jsonCodes = (JSONArray)array.get(0);
List<String> codes = jsonCodes.stream()
.map(Object::toString).collect(Collectors.toList());
System.out.println(codes);
}
}
Above code prints:
[012, 0324, 15478, 7412]
You can use DSM stream parsing library for memory, CPU efficiency and fast development. DSM uses YAML based mapping file and reads the whole data only once.
Here is the solution of your question:
Mapping File:
params:
colorsToFilter: ['Blue','Red'] # parameteres can be passed programmatically
result:
type: array
path: /.*colors # path is regex
filter: params.colorsToFilter.contains(self.data.color) # select only color that exist in colorsToFilter list
fields:
color:
code:
type: array
Usage of DSM to parse json:
DSM dsm = new DSMBuilder(new File("path/maping.yaml")).create(Colors.class);
List<Colors> object = (List<Colors>) dsm.toObject(jsonData);
System.out.println(object);
Output:
[Colors{color='Blue', code=[012, 0324, 15478, 7412]}, Colors{color='Red', code=[145, 001, 1, 7879, 123984, 89]}]
my requirement is to read data from json file and create items in dynamoDB with the objects that are present in dynamoDB, for example consider this following file
{
"ISA": {
"isa01_name": "00",
"isa02": " ",
"isa03": "00",
"isa04": " ",
"isa05": "ZZ",
"isa06": "CLEARCUT ",
"isa07": "ZZ",
"isa08": "CMSENCOUNTERCTR",
"isa09": "120109",
"isa10": "1530",
"isa11": "U",
"isa12": "00501",
"isa13": "012412627",
"isa14": "0",
"isa15": "T",
"isa16": ":"
},
"GS": {
"gs02": "352091331",
"gs04": "20170109",
"gs06": "146823",
"gs03": "00580",
"gs05": "1530",
"gs01": "HC",
"gs08": "005010X222A1",
"gs07": "X"
},
"ST": {
"ST03_1705_Implementation Convention Reference": "005010X222A1",
"ST01_143_Transaction Set Identifier Code": "837",
"ST02_329_Transaction Set Control Number": "50138"
}
}
when i read this file it have to create ISA , GS , ST items in dynamodb database. Again if read another file having different objects , then items have to be created for them as well.
following is the code that i am having right now.
`import java.io.File;
import java.util.Iterator;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
public class LoadData {
public static void main(String ards[]) throws Exception {
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard()
.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration("http://localhost:8000", "us-west-2"))
.build();
DynamoDB dynamoDB = new DynamoDB(client);
Table table = dynamoDB.getTable("NewTable");
JsonParser parser = new JsonFactory().createParser(new File("C:\\Users\\Nikhil yadav\\Downloads\\healthclaims\\healthclaims\\src\\main\\resources\\output\\ValidJson.json"));
JsonNode rootNode = new ObjectMapper().readTree(parser);
Iterator<JsonNode> iter = rootNode.iterator();
ObjectNode currentNode;
while (iter.hasNext()) {
currentNode = (ObjectNode) iter.next();
try {
table.putItem(new Item().withPrimaryKey("ISA", currentNode.path("ISA").toString().replaceAll("[^:a-zA-Z0-9_-|]", " "))
.withString("GS",currentNode.path("GS").toString().replaceAll("[^:a-zA-Z0-9_-|]", " "))
.withString("ST", currentNode.path("ST").toString().replaceAll("[^:a-zA-Z0-9_-|]", " "))
);
System.out.println("PutItem succeeded: ");
}
catch (Exception e) {
System.err.println("Unable to add : ");
System.err.println(e.getMessage());
break;
}
}
parser.close();
}
}
`
it will only accept file having ISA , GS and ST objects, but i want program which accepts all types objects of json files.
i hope my question is clear. i am new in posting questions please ignore if it is not clear.
I have a inter-related Maps representing the below data .
{
"Soft Drinks": {
"Tin": [
{
"Lean Apple": [
{
"name": "1 Litre"
},
{
"name": "2 Litre"
}
]
},
{
"Clear": [
{
"name": "7 Litre"
},
{
"name": "10 Litre"
}
]
}
],
"Bottled": [
]
}
}
This is my code representing above json data in form of Java code
package test;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import org.json.JSONException;
import org.json.JSONObject;
public class Post {
public static void main(String args[]) throws JSONException
{
LinkedList<String> forTinItemsList = new LinkedList<String>();
LinkedList<String> forBottleItemsList = new LinkedList<String>();
JSONObject jsonobj = new JSONObject();
Map<String,LinkedList<String>> categoryitemsMap = new LinkedHashMap<String,LinkedList<String>>();
forTinItemsList.add("Lean Apple");
forTinItemsList.add("Clear");
forBottleItemsList.add("Lemon");
forBottleItemsList.add("Clear");
categoryitemsMap.put("Tin", forTinItemsList);
categoryitemsMap.put("Bottled", forBottleItemsList);
// completion of Categories.
Map<String,LinkedList<String>> subcategory = new LinkedHashMap<String,LinkedList<String>>();
LinkedList<String> forLemonItems = new LinkedList<String>();
forLemonItems.add("1 Litre");
forLemonItems.add("2 Litre");
subcategory.put("Lemon", forLemonItems);
LinkedList<String> forClearItems = new LinkedList<String>();
forClearItems.add("7 Litre");
forClearItems.add("10 Litre");
subcategory.put("Clear", forClearItems);
for (Map.Entry<String, LinkedList<String>> entry : categoryitemsMap.entrySet())
{
String key = entry.getKey();
LinkedList<String> list = entry.getValue();
for(String value : list)
{
System.out.println(key+"\t"+value);
}
//jsonobj.put(entry, arg1);
}
}
}
Could anybody please tell me how can i build the above JSON Structure ??
I was trying with different things m, but i was unsuccessful , the problem i was facing is that i am getting the Bottled Array is also filling up with the same Tin Array items .
To give you an idea of the unholy abomination things would become if you did it this way: here's the data structure that you would have to create to capture the JSON you propose.
Map<String, Map<String, List<Map<String, List<Map<String, String>>>>>> items;
So, feel free to implement this, but if it was me, I would build a data model and then map it with Jackson.
there are libraries that do this for you GSON and Jackson
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