I just want to convert a string that contains a yaml into another string that contains the corrseponding converted json using Java.
For example supose that I have the content of this yaml
---
paper:
uuid: 8a8cbf60-e067-11e3-8b68-0800200c9a66
name: On formally undecidable propositions of Principia Mathematica and related systems I.
author: Kurt Gödel.
tags:
- tag:
uuid: 98fb0d90-e067-11e3-8b68-0800200c9a66
name: Mathematics
- tag:
uuid: 3f25f680-e068-11e3-8b68-0800200c9a66
name: Logic
in a String called yamlDoc:
String yamlDoc = "---\npaper:\n uuid: 8a... etc...";
I want some method that can convert the yaml String into another String with the corresponding json, i.e. the following code
String yamlDoc = "---\npaper:\n uuid: 8a... etc...";
String json = convertToJson(yamlDoc); // I want this method
System.out.println(json);
should print:
{
"paper": {
"uuid": "8a8cbf60-e067-11e3-8b68-0800200c9a66",
"name": "On formally undecidable propositions of Principia Mathematica and related systems I.",
"author": "Kurt Gödel."
},
"tags": [
{
"tag": {
"uuid": "98fb0d90-e067-11e3-8b68-0800200c9a66",
"name": "Mathematics"
}
},
{
"tag": {
"uuid": "3f25f680-e068-11e3-8b68-0800200c9a66",
"name": "Logic"
}
}
]
}
I want to know if exists something similar to the convertToJson() method in this example.
I tried to achieve this using SnakeYAML, so this code
Yaml yaml = new Yaml();
Map<String,Object> map = (Map<String, Object>) yaml.load(yamlDoc);
constructs a map that contain the parsed YAML structure (using nested Maps). Then if there is a parser that can convert a map into a json String it will solve my problem, but I didn't find something like that neither.
Any response will be greatly appreciated.
Here is an implementation that uses Jackson:
String convertYamlToJson(String yaml) {
ObjectMapper yamlReader = new ObjectMapper(new YAMLFactory());
Object obj = yamlReader.readValue(yaml, Object.class);
ObjectMapper jsonWriter = new ObjectMapper();
return jsonWriter.writeValueAsString(obj);
}
Requires:
compile('com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.7.4')
Thanks to HotLicks tip (in the question comments) I finally achieve the conversion using the libraries org.json and SnakeYAML in this way:
private static String convertToJson(String yamlString) {
Yaml yaml= new Yaml();
Map<String,Object> map= (Map<String, Object>) yaml.load(yamlString);
JSONObject jsonObject=new JSONObject(map);
return jsonObject.toString();
}
I don't know if it's the best way to do it, but it works for me.
Big thanks to Miguel A. Carrasco he infact has solved the issue. But his version is restrictive. His code fails if root is list or primitive value. Most general solution is:
private static String convertToJson(String yamlString) {
Yaml yaml= new Yaml();
Object obj = yaml.load(yamlString);
return JSONValue.toJSONString(obj);
}
I found the example did not produce correct values when converting Swagger (OpenAPI) YAML to JSON. I wrote the following routine:
private static Object _convertToJson(Object o) throws JSONException {
if (o instanceof Map) {
Map<Object, Object> map = (Map<Object, Object>) o;
JSONObject result = new JSONObject();
for (Map.Entry<Object, Object> stringObjectEntry : map.entrySet()) {
String key = stringObjectEntry.getKey().toString();
result.put(key, _convertToJson(stringObjectEntry.getValue()));
}
return result;
} else if (o instanceof ArrayList) {
ArrayList arrayList = (ArrayList) o;
JSONArray result = new JSONArray();
for (Object arrayObject : arrayList) {
result.put(_convertToJson(arrayObject));
}
return result;
} else if (o instanceof String) {
return o;
} else if (o instanceof Boolean) {
return o;
} else {
log.error("Unsupported class [{0}]", o.getClass().getName());
return o;
}
}
Then I could use SnakeYAML to load and output the JSON with the following:
Yaml yaml= new Yaml();
Map<String,Object> map= (Map<String, Object>) yaml.load(yamlString);
JSONObject jsonObject = (JSONObject) _convertToJson(map);
System.out.println(jsonObject.toString(2));
I was directed to this question when searching for a solution to the same issue.
I also stumbled upon the following article https://dzone.com/articles/read-yaml-in-java-with-jackson
It seems Jackson JSON library has a YAML extension based upon SnakeYAML.
As Jackson is one of the de facto libraries for JSON I thought that I should link this here.
Thanks, Miguel! Your example helped a lot. I didn't want to use the 'JSON-java' library. I prefer GSON. But it wasn't hard to translate the logic from JSON-java over to GSON's domain model. A single function can do the trick:
/**
* Wraps the object returned by the Snake YAML parser into a GSON JsonElement
* representation. This is similar to the logic in the wrap() function of:
*
* https://github.com/stleary/JSON-java/blob/master/JSONObject.java
*/
public static JsonElement wrapSnakeObject(Object o) {
//NULL => JsonNull
if (o == null)
return JsonNull.INSTANCE;
// Collection => JsonArray
if (o instanceof Collection) {
JsonArray array = new JsonArray();
for (Object childObj : (Collection<?>)o)
array.add(wrapSnakeObject(childObj));
return array;
}
// Array => JsonArray
if (o.getClass().isArray()) {
JsonArray array = new JsonArray();
int length = Array.getLength(array);
for (int i=0; i<length; i++)
array.add(wrapSnakeObject(Array.get(array, i)));
return array;
}
// Map => JsonObject
if (o instanceof Map) {
Map<?, ?> map = (Map<?, ?>)o;
JsonObject jsonObject = new JsonObject();
for (final Map.Entry<?, ?> entry : map.entrySet()) {
final String name = String.valueOf(entry.getKey());
final Object value = entry.getValue();
jsonObject.add(name, wrapSnakeObject(value));
}
return jsonObject;
}
// everything else => JsonPrimitive
if (o instanceof String)
return new JsonPrimitive((String)o);
if (o instanceof Number)
return new JsonPrimitive((Number)o);
if (o instanceof Character)
return new JsonPrimitive((Character)o);
if (o instanceof Boolean)
return new JsonPrimitive((Boolean)o);
// otherwise.. string is a good guess
return new JsonPrimitive(String.valueOf(o));
}
Then you can parse a JsonElement from a YAML String with:
Yaml yaml = new Yaml();
Map<String, Object> yamlMap = yaml.load(yamlString);
JsonElement jsonElem = wrapSnakeObject(yamlMap);
and print it out with:
Gson gson = new GsonBuilder().setPrettyPrinting().create();
System.out.println(gson.toJson(jsonElem));
Using Gson:
var yaml = new YAML();
var gson = new Gson();
var reader = new FileReader(path.toFile());
var obj = yaml.load(reader);
var writer = new StringWriter();
gson.toJson(obj, writer);
String result = writer.toString();
Spring boot with kotlin to return a yaml file content as json data
package br.com.sportplace.controller
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import java.io.InputStream
#RestController
#RequestMapping(value = ["resources/docs"])
class DocsController {
#GetMapping(produces = ["application/json"])
fun load(): ResponseEntity<Any> {
return getResourceFileAsString()
}
fun getResourceFileAsString(): ResponseEntity<Any> {
val inputStream = getResourceFileAsInputStream("openapi/api.yaml")
return if (inputStream != null) {
val objectMapper = ObjectMapper(YAMLFactory())
ResponseEntity.ok(objectMapper.readValue(inputStream, Any::class.java))
} else {
ResponseEntity(ErrorResponse(), HttpStatus.INTERNAL_SERVER_ERROR)
}
}
fun getResourceFileAsInputStream(fileName: String?): InputStream? {
val classLoader = DocsController::class.java.classLoader
return classLoader.getResourceAsStream(fileName)
}
private data class ErrorResponse(
val message: String = "Failed to load resource file",
val success: Boolean = false,
val timestamp: Long = System.currentTimeMillis()
)
}
Related
I have this JSON response, from a remote server and i really hope i can get help.
{
"data": {
"6111": {
"prereq": "0",
"mast": "The Master Tree"
},
"6112": {
"prereq": "1",
"mast": "Another Master Tree"
}
}
}
I use GSON to parse JSON, using the #SerializedName and #Exposeto obtain the value into a custom Model. But i do not understand how to get past the
"6111"
"6112"
I have checked other questions via the gson tag, to no avail.
try this
Iterator<String> iter = json.keys();
while (iter.hasNext()) {
String key = iter.next();
try {
Object value = json.get(key);
} catch (JSONException e) {
// Something went wrong!
}
}
///////////////////update////////////////////
JSONObject issueObj = new JSONObject(jsonContent);
Iterator iterator = issueObj.keys();
while(iterator.hasNext()){
String key = (String)iterator.next();
JSONObject issue = issueObj.getJSONObject(key);
// get id from issue
String _pubKey = issue.optString("id");
}
If you're using Gson, any time you have an object with keys you don't know ahead of time, you can just use Map instead of a custom object.
In this case, each element of the Map will be some "known" data structure, so you would use Map<String, MyObject>.
Your top-level class:
public class MyResponse {
#SerializedName("data")
#Expose
private Map<String, MyObject> data;
...
}
And your map's value class:
public class MyObject {
#SerializedName("prereq")
#Expose
private String prereq;
#SerializedName("mast")
#Expose
private String mast;
...
}
In the specific case of the json text you posted, you would then be able to use these objects like this:
response.getData().get("6111").getMast();
But you can also do anything you could normally do with a Map:
Map<String, MyObject> data = response.getData();
for (String key: data.keySet() {
...
}
for (MyObject obj : data.values()) {
...
}
I have an enhanced question regarding Flatten a JSON string to Map using Gson or Jackson.
My scenario included duplicated keys, so the solution in the above question will cause some duplicated keys overwritten. So I am thinking to construct keys by combining each level's key together.
So how to achieve that?
For example:
{
"id" : "123",
"name" : "Tom",
"class" : {
"subject" : "Math",
"teacher" : "Jack"
}
}
I want to get the Map:
"id" : "123",
"name" : "Tom",
"class.subject" : "Math",
"class.teacher" : "Jack"
************************Update Solution*************************************
Based on #Manos Nikolaidis's answer, I am able to achieve the following solution by considering ArrayNode.
public void processJsonString(String jsonString) throws Exception {
ObjectMapper mapper = new ObjectMapper();
ArrayNode arrayNode = (ArrayNode) mapper.readTree(jsonString);
processArrayNode(arrayNode);
}
private void processObjectNode(JsonNode jsonNode) {
Map<String, String> result = new HashMap<>();
Iterator<Map.Entry<String, JsonNode>> iterator = jsonNode.fields();
iterator.forEachRemaining(node -> mapAppender(result, node, new ArrayList<String>()));
}
private void processArrayNode(ArrayNode arrayNode) {
for (JsonNode jsonNode : arrayNode) {
processObjectNode(jsonNode);
}
}
private void mapAppender(Map<String, String> result, Map.Entry<String, JsonNode> node, List<String> names) {
names.add(node.getKey());
if (node.getValue().isTextual()) {
String name = names.stream().collect(Collectors.joining("."));
result.put(name, node.getValue().asText());
} else if (node.getValue().isArray()) {
processArrayNode((ArrayNode) node.getValue());
} else if (node.getValue().isNull()) {
String name = names.stream().collect(Collectors.joining("."));
result.put(name, null);
} else {
node.getValue().fields()
.forEachRemaining(nested -> mapAppender(result, nested, new ArrayList<>(names)));
}
}
You can get the JSON as JsonNode and go through all fields recursively and add key and value field to a Map. When a value is an object instead of string you can add the field name to List to be joined with periods when a string is finally encountered. First create (for readability) a separate method that add Json fields to a Map:
void mapAppender(Map<String, String> result, Entry<String, JsonNode> node, List<String> names) {
names.add(node.getKey());
if (node.getValue().isTextual()) {
String name = names.stream().collect(joining("."));
result.put(name, node.getValue().asText());
} else {
node.getValue().fields()
.forEachRemaining(nested -> mapAppender(result, nested, new ArrayList<>(names)));
}
}
and use it like this:
ObjectMapper mapper = new ObjectMapper();
Map<String, String> result = new HashMap<>();
mapper.readTree(json).fields()
.forEachRemaining(node -> mapAppender(result, node, new ArrayList<String>()));
Where fields() returns an Iterator. Beware of StackOverflowErrors and perhaps low performance for deeply nested JSON.
I resolved this using below simple code, Only think is need to download jettison and flattener.JsonFlattener library
import java.util.Map;
import org.codehaus.jettison.json.JSONObject;
import com.github.wnameless.json.flattener.JsonFlattener;
public class test {
public static void main(String[] args) {
String jsonString = "{\"id\" : \"123\",\"name\" : \"Tom\",\"class\" : {\"subject\" : \"Math\",\"teacher\" : \"Jack\"}}";
JSONObject jsonObject = new JSONObject();
String flattenedJson = JsonFlattener.flatten(jsonString);
Map<String, Object> flattenedJsonMap = JsonFlattener.flattenAsMap(jsonString);
System.out.println(flattenedJsonMap);
}
}
Reference link : https://github.com/wnameless/json-flattener
I've a Dynamodb table with streaming enabled. Also I've created a trigger for this table which calls an AWS Lambda function. Within this lambda function, I'm trying read the new image (Dynamodb item after the modification) from the Dynamodb stream and trying to get the pure json string out of it. My Question is how can i get the pure json string of the DynamoDB item that's been sent over the stream? I'm using the code snippet given below to get the new Image, but I've no clue how to get the json string out of it. Appreciate your help.
public class LambdaFunctionHandler implements RequestHandler<DynamodbEvent, Object> {
#Override
public Object handleRequest(DynamodbEvent input, Context context) {
context.getLogger().log("Input: " + input);
for (DynamodbStreamRecord record : input.getRecords()){
context.getLogger().log(record.getEventID());
context.getLogger().log(record.getEventName());
context.getLogger().log(record.getDynamodb().toString());
Map<String,AttributeValue> currentRecord = record.getDynamodb().getNewImage();
//how to get the pure json string of the new image
//..............................................
}
return "Successfully processed " + input.getRecords().size() + " records.";
}
}
Below is the complete code for converting from Dynamo JSON to Standard JSON:
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.internal.InternalUtils;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.DynamodbEvent;
import com.amazonaws.services.lambda.runtime.events.DynamodbEvent.DynamodbStreamRecord;
import com.google.gson.Gson;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Main Lambda class to receive event stream, parse it to Survey
* and process them.
*/
public class SurveyEventProcessor implements
RequestHandler<DynamodbEvent, String> {
private static final String INSERT = "INSERT";
private static final String MODIFY = "MODIFY";
public String handleRequest(DynamodbEvent ddbEvent, Context context) {
List<Item> listOfItem = new ArrayList<>();
List<Map<String, AttributeValue>> listOfMaps = null;
for (DynamodbStreamRecord record : ddbEvent.getRecords()) {
if (INSERT.equals(record.getEventName()) || MODIFY.equals(record.getEventName())) {
listOfMaps = new ArrayList<Map<String, AttributeValue>>();
listOfMaps.add(record.getDynamodb().getNewImage());
listOfItem = InternalUtils.toItemList(listOfMaps);
}
System.out.println(listOfItem);
try {
// String json = new ObjectMapper().writeValueAsString(listOfItem.get(0));
Gson gson = new Gson();
Item item = listOfItem.get(0);
String json = gson.toJson(item.asMap());
System.out.println("JSON is ");
System.out.println(json);
}catch (Exception e){
e.printStackTrace();
}
}
return "Successfully processed " + ddbEvent.getRecords().size() + " records.";
}
}
In c# you can convert newImage to pure json by use of DynamoDB Document class
using Amazon.DynamoDBv2.DocumentModel;
var streamRecord = dynamoEvent.Records.First();
var jsonResult=Document.FromAttributeMap(streamRecord.Dynamodb.NewImage).ToJson();
and if you want to go further ahead to convert json to object you can use Newtonsoft
using Newtonsoft.Json;
TModel model = JsonConvert.DeserializeObject(jsonResult);
Found a way of doing it cleanly. Using InternalUtils from aws-java-sdk-dynamodb-1.11.15.jar
com.amazonaws.services.dynamodbv2.model.Record streamRecord = ((RecordAdapter) record).getInternalObject();
// get order ready //
OrderFinal order = Utils.mapO2Object(
InternalUtils.toSimpleMapValue(streamRecord.getDynamodb().getNewImage().get("document").getM()),
OrderFinal.class );
Just summarizing the answer of Himanshu Parmar:
Map<String, AttributeValue> newImage = record.getDynamodb().getNewImage();
List<Map<String, AttributeValue>> listOfMaps = new ArrayList<Map<String, AttributeValue>>();
listOfMaps.add(newImage);
List<Item> itemList = ItemUtils.toItemList(listOfMaps);
for (Item item : itemList) {
String json = item.toJSON();
}
For those stuck with a Map<String, ?> where objects are plain Map, but not Attributes value, you can do the following:
Map<String, AttributeValue> dynamoDbAttributes =
objectMapper.convertValue(dynamoDbMap, new TypeReference<Map<String, AttributeValue>>() {});
and then convert this DynamoDB Map into a plain Map (equivalent to the json originally pushed into DynamoDb):
asMap = InternalUtils.toSimpleMapValue(dynamoDbAttributes);
For the ones facing issues with AttributeValue conversion refer the below code:
https://github.com/aws/aws-lambda-java-libs/blob/master/aws-lambda-java-events-sdk-transformer/README.md
Map<String, AttributeValue> stringAttributeValueMap = DynamodbAttributeValueTransformer.toAttributeValueMapV1(dynamodb.getNewImage());
List stringAttributeValueMapList = new ArrayList();
stringAttributeValueMapList.add(stringAttributeValueMap);
List<Item> listOfItem = InternalUtils.toItemList(stringAttributeValueMapList);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String updatedJSON = gson.toJson(listOfItem.get(0).asMap());
Below is the Method which converts DynamoDB JSON to normal JSON
/**
* Converts DynamoDB JSON to normal JSON.
*
* #param map Input map of String to AttributeValue.
* #return Returns an ObjectNode containing the normal JSON.
*/
public JsonObject toJsonObject(final Map<String, AttributeValue> map) {
final JsonNode result = mapToJsonObject(map);
final ObjectNode objectNode = (ObjectNode) result;
final ObjectMapper objectMapper = new ObjectMapper();
String recordObjectString;
try {
recordObjectString = objectMapper.writeValueAsString(objectNode);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
final JsonParser jsonParser = new JsonParser();
final JsonObject jsonObject = jsonParser.parse(recordObjectString)
.getAsJsonObject();
return jsonObject;
}
So in your Case simple call below method like this
// here record is of type DynamodbStreamRecord
toJsonObject(record.getDynamodb().getNewImage());
This library do the job: dynamoDb-marshaler
var unmarshalJson = require('dynamodb-marshaler').unmarshalJson;
console.log('jsonItem Record: %j', unmarshalJson(record.dynamodb.NewImage));
I would like to know how to parse the following JSON using jackson library in java to construct the URI like http://api.statdns.com/google.com/cname
{
"status": {
"status": 200,
"msg": "SUCCESS"
},
"apicalls": [
{
"API": {
"method": "get",
"success": "200",
"baseURL": "http://api.statdns.com/",
"param1": "google.com/",
"param2": "cname",
"continue_on_fail": "1",
"add_header2": "'Accept', 'application/json'",
"add_header1": "'Content-Type', 'application/json'",
"client_id": "101"
},
"id": 1385
}
]
}
I have written bad code to parse the above json array. Following is the code i used,
public void parseJSON(String json) {
try{
JsonFactory factory = new JsonFactory();
JsonParser parser;
parser = factory.createJsonParser(json);
parser.setCodec(new ObjectMapper()); // to avoid IllegalStateException
JsonToken current;
current = parser.nextToken();
if (current != JsonToken.START_OBJECT) {
System.out.println("Error: root should be object: quiting.");
return;
}
while (parser.nextToken() != JsonToken.END_OBJECT) {
String fieldName = parser.getCurrentName();
// Move from field name to field value
current = parser.nextToken();
if (fieldName.equals("APIcalls")) {
JsonNode node = parser.readValueAsTree();
JsonNode currentJson = node.findValue("API");
System.out.println("Current JSON :: " + currentJson);
JsonNode url = currentJson.get("baseURL");
JsonNode param1 = currentJson.get("param1");
JsonNode param2 = currentJson.get("param2");
String baseURL = url.asText();
String params1 = param1.asText();
String params2 = param2.asText();
String uri = baseURL + params1 + params2;
System.out.println("URL :: " + uri);
initiateRESTCall(uri);
}
}
} catch (JsonParseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Could anyone help me to know parsing the JSON using jackson? Help is highly appreciated.
If you are using jackson library, then you should go something like this:
I am using response from http://api.statdns.com/google.com/cname
public void parseJSON(String json) {
JSONObject parse = new JSONObject(data);
if(parse.get("question") instanceof JSONObject){
JSONObject questionJson = (JSONObject) parse.get("question");
System.out.println("Name"+questionJson.getString("name"));
System.out.println("Type"+questionJson.getString("type"));
System.out.println("Class"+questionJson.getString("class"));
}
else if(parse.get("question") instanceof JSONArray){
JSONArray questionJson = (JSONArray) parse.get("question");
String[] nameAttrib=new String[questionJson.length()];
String[] typeAttrib=new String[questionJson.length()];
String[] classAttrib=new String[questionJson.length()];
for(int i=0;i<questionJson.length();i++){
JSONObject questionJsonData=(JSONObject)questionJson.get(i);
nameAttrib[i]=questionJsonData.getString("name");
typeAttrib[i]=questionJsonData.getString("type");
classAttrib[i]=questionJsonData.getString("class");
System.out.println("Name: "+nameAttrib[i]);
System.out.println("Type: "+typeAttrib[i]);
System.out.println("Class: "+classAttrib[i]);
}
}
else if (parse.get("question").equals(null)){
System.out.println("question"+null);
}
}
Here I am doing for "question" only, similarly you can do other as well say "answer", "authority" in case url you have mentioned http://api.statdns.com/google.com/cname.
Hopefully it helps you with your problem..!!!!
If you are confident in the JSON not changing, a quick and dirty way to simplify your code is to use JSON Pointers.
// prefer injecting your project's ObjectMapper
private static final ObjectMapper om = new ObjectMapper();
public void parseJSON(String json) throws IOException {
JsonNode jsonNode = om.readTree(json);
String uri = new StringBuilder(jsonNode.findValue("baseURL").asText())
.append(jsonNode.findValue("param1").asText())
.append(jsonNode.findValue("param2").asText())
.toString();
initiateRESTCall(uri);
}
This becomes vulnerable if multiple apicalls entries are returned.
I don't know JACKSON library but I think it is similar to GSON. You just have to make some POJO and the library will take care of filling the fields for you.
For instance to convert your string to MyJSONClass use the following classes :
class Status {
int status;
String msg;
}
class APIClass {
String method;
String success;
String baseURL;
String param1;
String param2;
String continue_on_fail;
String add_header2;
String add_header1;
String client_id;
}
class APICall {
APIClass API;
int id;
}
class MyJSONClass {
Status status;
List<APICall> apicalls;
}
This set of classes could be transformed to JSON with JACKSON library (thanks to this stackoverflow answer) like that:
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
String json = ow.writeValueAsString(object);
I am new to stackoverflow.
I am creating an Java application which it will get data from a web server. The data is in json format. Example"
[
{
"item_name": "Adame",
"item_type": "Special",
"item": "Chestplate",
"item_min_lvl": "50",
"enchantment": {
"health": "0.3",
"dam": "24%",
"life": "0.1",
"xp": "24%",
"loot": "22%"
},
"def": "73"
},
{
"item_name": "Sticks'",
"item_type": "Unique",
"item": "Stick",
"item_min_lvl": "4",
"enchantment": {
"health": "0.6",
"mana": "1",
"dam": "12%",
"life": "0.3",
"xp": "17%",
"loot": "17%"
},
"min_dam": "39",
"max_dam": "34"
}
]
I know how to deserialize json using Gson. As you can see, it's started with [. I never deserialize this case before. Also, the json data is not the same(e.g. enchantment). I also searched in Google but I can't find any similar case. Can anyone help me with the code?
Try with this code. You will get the answer of your question. It's an List with 2 items.
StringBuilder builder = new StringBuilder();
BufferedReader reader = new BufferedReader(new FileReader(new File("resources/json1.txt")));
String line = null;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
reader.close();
Gson gson = new Gson();
Type listType = new TypeToken<ArrayList<MyJSON>>() {
}.getType();
List<MyJSON> list = gson.fromJson(builder.toString(), listType);
// you can try this form as well
// MyJSON[] list = gson.fromJson(builder.toString(), MyJSON[].class);
for (MyJSON json : list) {
System.out.println(json.toString());
}
...
class MyJSON {
String item_name;
String item_type;
String item;
String item_min_lvl;
Enchantment enchantment;
#Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("\nitem_name:").append(item_name);
builder.append("\nitem_type:").append(item_type);
builder.append("\nitem:").append(item);
builder.append("\nitem_min_lvl:").append(item_min_lvl);
builder.append("\n\nEnchantment Details:");
builder.append("\nhealth:").append(enchantment.health);
builder.append("\ndam:").append(enchantment.dam);
builder.append("\nlife:").append(enchantment.life);
builder.append("\nxp:").append(enchantment.xp);
builder.append("\nloot:").append(enchantment.loot);
return builder.toString();
}
}
class Enchantment {
String health;
String dam;
String life;
String xp;
String loot;
}
output:
item_name:Adame
item_type:Special
item:Chestplate
item_min_lvl:50
Enchantment Details:
health:0.3
dam:24%
life:0.1
xp:24%
loot:22%
item_name:Sticks'
item_type:Unique
item:Stick
item_min_lvl:4
Enchantment Details:
health:0.6
dam:12%
life:0.3
xp:17%
loot:17%
EDIT
The structure of each entry is not same hence you can't use POJO for this type of JSON.
Simply use ArrayList<Map<String, Object>> and access the value based on key from the map.
Gson gson = new Gson();
Type listType = new TypeToken<ArrayList<Map<String, Object>>>() {
}.getType();
ArrayList<Map<String, Object>> list = gson.fromJson(builder.toString(), listType);
for (Map<String, Object> json : list) {
for (String key : json.keySet()) {
System.out.println(key + ":" + json.get(key));
}
System.out.println("===========");
}
output:
item_name:Adame
item_type:Special
item:Chestplate
item_min_lvl:50
enchantment:{health=0.3, dam=24%, life=0.1, xp=24%, loot=22%}
def:73
===========
item_name:Sticks'
item_type:Unique
item:Stick
item_min_lvl:4
enchantment:{health=0.6, mana=1, dam=12%, life=0.3, xp=17%, loot=17%}
min_dam:39
max_dam:34
===========
This is actually valid in Java and with GSON:
YourObject[] locs = gson.fromJson (someJsonString, YourObject[].class);
It'll parse and return an array of YourObject. Just create Java Classes that represent your JSON objects, and replace the placeholders as necessary.
EDIT:
As Braj said before, you can create a fully formed POJO, including the other, (non-symmetrical) attributes (I'm borrowing the code from from Braj's answer here):
//... snip ...
class MyJSON
{
String item_name;
String item_type;
String item;
String item_min_lvl;
Enchantment enchantment;
// Heres the other attributes
String min_dam;
String max_dam;
}
//... snip ...
GSON will parse it and set the values to null if they aren't provided in the original JSON.
However, from the other question, it seems that the JSON (Java - JSON Parser Error) for enchantment is provided inconsistently, so this will cause issues. I would recommend sending JSON for enchantment as an array for consistency, then you could structure your POJO as:
//... snip ...
class MyJSON
{
String item_name;
String item_type;
String item;
String item_min_lvl;
Enchantment[] enchantment;
// Heres the other attributes
String min_dam;
String max_dam;
}
//... snip ...