Parsing relaxed JSON without quotes Java - java

This source Google Finance option Chain Data returns the relaxed JSON, I wasn't able to Parse this JSON through PDI (Pentaho Data Integratio) (originally required) So thought of Parsing it in Java Code.
I tried using ObjectMapper and its Feature to allow unquoted field names but the json returned from above source is totally relaxed and can miss quotes anywhere.
String json = "{name:\"ankit\"}";
Map<String,String> map = new HashMap<String,String>();
ObjectMapper mapper = new ObjectMapper();
mapper.configure(org.codehaus.jackson.JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
map = mapper.readValue(json,new TypeReference<HashMap<String,String>>(){});
System.out.println(map);
It works fine if the keys in JSON are unquoted but fails if the same goes with values.
Is there any way out doing it with Pentaho Data integration or in Java Class.

Related

Serialized JSON String as Value in JSON

I want a serialized JSON string to be treated simply as a string in my JSON when reading it using Jackson. When I simply escape the serialized JSON string and use it as a value, the serialized string gets treated as part of the JSON and parsed. Any ideas as to how to go about doing this?
For example:
"{\"payload\":\"{id:\"some-random-id\",version:554471325}\"}"
I would like this to be read in memory something like the following:
{ payload: "{id:\"some-random-id\",version:554471325}" }
However, the parser is trying to read the serialized string as JSON and turn it into the following:
{ payload: {id:"some-random-id", version:554471325} }
Note the difference between the two outputs. In one case, the value associated with payload is a string, in the other it's a JSON object. I'm trying to get the former, what I'm getting instead is an attempt at the latter.
Valid JSON is "set of name/value pairs", so what are you missing is the name field, and it's the reason why it's beiing parsed.
For example if the JSON is:
{"data": "{\"payload\":\"{id:\"some-random-id\",version:554471325}\"}"}
the value of data is not going to be parsed.
Btw. the JSON in payload contains key names without quotes (should probably be {"id": 123, "version": 456})
UPDATE: Answer replaced because question changed.
The examples in the question are not valid JSON. To see what it should be, let's generate it as nested JSON strings:
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> payloadObj = Map.of("id", "some-random-id", "version", 554471325);
String payloadJson = objectMapper.writeValueAsString(payloadObj);
System.out.println(payloadJson);
Map<String, Object> rootObj = Map.of("payload", payloadJson);
String rootJson = objectMapper.writeValueAsString(rootObj);
System.out.println(rootJson);
String rootString = objectMapper.writeValueAsString(rootJson);
System.out.println(rootString);
Output
{"id":"some-random-id","version":554471325}
{"payload":"{\"id\":\"some-random-id\",\"version\":554471325}"}
"{\"payload\":\"{\\\"id\\\":\\\"some-random-id\\\",\\\"version\\\":554471325}\"}"
The third line of output is what should have been the text of the first block in the question.
"{\"payload\":\"{id:\"some-random-id\",version:554471325}\"}"
But as you can see, that text is lacking many double-quotes and backslashes, so it is not valid nested JSON strings, so you can't expect a JSON parser to parse it.
JSON parsers are often lenient, and will do its best to parse it anyway, but don't blame the parser if it gets it wrong. Blame the original text and fix that, rather than trying to parse bad JSON.
Original Answer
Keys are supposed to be names, or numbers, not entire complex objects, but if you want a JSON as the key in another JSON, just invoke the JSON serializer twice.
Example
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> data1 = Map.of("foo", 42, "bar", List.of(1, 1, 2, 3, 5, 8));
String json1 = objectMapper.writeValueAsString(data1);
System.out.println(json1);
Map<String, Object> data2 = Map.of("Test", "Hello World", json1, 3.14, "End", "Now!");
String json2 = objectMapper.writeValueAsString(data2);
System.out.println(json2);
Note: Map.of() and List.of() are Java 9+
Output
{"foo":42,"bar":[1,1,2,3,5,8]}
{"{\"foo\":42,\"bar\":[1,1,2,3,5,8]}":3.14,"Test":"Hello World","End":"Now!"}
I know this is a terribly worded question, and I apologize for that. However, I can't come up with a better way of wording it and I'm unable to supply code. For anyone who stumbles on this and understands what I'm asking, I found a workaround.
I encoded the serialized JSON string to base64 so it was detected by Jackson as a string rather than a JSON object.
The example in the question above becomes:
"{\"payload\":\"e2lkOiJhbnktZXhlY3V...\"}"
where e2lkOiJhbnktZXhlY3V... is a base64 encoded representation of the string "{id:\"some-random-id\",version:554471325}"

Retain line number after parsing YAML to JSON

I receive a YAML file which I parse using snakeyaml-engine(for YAML 1.2).
LoadSettings settings = new LoadSettingsBuilder().build();
Load load = new Load(settings);
Map<String, Object> yamlMap = (Map<String, Object>) load.loadFromString(new String(<yaml_contents_as_byte_array>));
I then use GSON to convert this into a JsonObject.
Gson gson = new GsonBuilder().setPrettyPrinting().create();
JsonParser parser = new JsonParser();
JsonObject obj = parser.parse(gson.toJson(yamlMap)).getAsJsonObject();
The goal is to run through this YAML, checking it against a known data model. If fields differ, required fields are missing, etc. I must return an error for each one. The goal is to find some way to include the line number of the problem field from the original YAML, but as I am doing my validations via JSON, I do not know the original line number when I run into an error. I am curious if there is some straightforward way to persist the line number of the YAML, perhaps by adding a lineNumber/columnNumber value to each field as it is parsed and inserted into the map?
A distinct non-answer: I am not aware of any build in mechanism that you could use here. So you probably have to write code yourself to achieve to do both things:
keep track of yaml properties together with line numbers
enhance the corresponding Json beans with line number fields
But honestly, the real answer (imho): have distinct validation code that can work on either yaml or Json input "directly". That additional conversion for the purpose of validation, I find that highly doubtful.

How to store JSON array variable and printing specific value. (JAVA)

To print the neccesary details we used the following command
System.out.println(msgFromServer.data);
Now the following details are fetched from server
[{id={name=XDA Studio, color=red}, angle=-0.24456912236854822, piecePosition={pieceIndex=39.0, inPieceDistance=35.797426838065036, lane={startLaneIndex=1.0, endLaneIndex=1.0}, lap=2.0}}]
How to store these above server messages in json array variable and print value of angle alone.
msgFromServer.data seems to return a List. Your List is something like
List<Map<String,Object>>
If you use Jackson parser, you could probably convert it to a Json String using the following code:
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(list);
I have provided code for Jackson library, you could use any other with library specific implementation and code

Parsing json response using play libs

I need to parse json response in a play application and get all the fields/values in a list.
I'm getting the response as below:
WSRequestHolder request = WS.url("someurl");
request.setQueryParameter("somekey", "somevalue");
Promise<Response> promise = request.get();
Response response = promise.get();
JsonNode json = response.asJson();
The response comes like below:
{"results":{"key1":value1,"key2":value2,"key3":value3},"errorMessage":"","statusCode":2000,"success":true,"version":"1.01"}
I need to get all the feilds/values from "results" list. How can i do this using play json libraries / apis available? I'm using play 2.1.1.
Thanks.
Since the result is a JsonNode, you have all the niceties of JsonNode available to you.
For instance, if you want to access "results", do:
JsonNode results = json.get("results");
You also have methods such as .has(), .path(), .entries(), etc etc. One JsonNode can represent any JSON value, including null.
To test the type you can use the .is*() methods: .isObject(), .isNumber(), .isMissing() (note: the latter requires the use of .path() instead of .get()).
Example:
json.path("foo").isMissing(); // true
json.path("errorMessage").getTextValue(); // ""
json.get("results").get("key2"); // value2
json.get("success").getBooleanValue(); // true
Etc etc. See the javadoc for JsonNode.
Another solution would be to deserialize that JSON into a POJO. But that means creating the POJO in the first place, and then use an ObjectMapper to .read*() the value.
(side note: it is surprising that Play uses Jackson 1.9.x whereas 2.0+ has been available for many years...)

Java XStream with HashMap

I want to use XStream to convert a java hash to a json hash. I feel like this should be easier than it seems. What I'm looking for is a way to make:
Map<String, String> map = new HashMap<String, String>();
map.put("first", "value1");
map.put("second", "value2");
become
{'first' : 'value1', 'second' : 'value2' }
The closes I have converts it into a series of arrays.
XStream xstream = new XStream(new JettisonMappedXmlDriver() {
public HierarchicalStreamWriter createWriter(Writer writer) {
return new JsonWriter(writer, JsonWriter.DROP_ROOT_MODE);
}
});
xstream.toXML(map);
which becomes
[["first", "value1"], ["second", "value2"]]
I feel like converting a java hash to json hash should be straight forward. Am I missing something?
The thing is that XStream is first and foremost designed to marshal and unmarshal Java objects to XML, JSON being just an afterthought, it most certainly has the least elegant support.
The technical problem being that as XStream must support both - XML and JSON formats, JSON map representation suffers, as there is no native way to represent a map-like structures in XML.
You can try to use the "official" json lib for java from json.org.
Calling:
JSONObject jsobj = new JSONObject(map);
String strJson = jsobj.toString();
I had similar issues when converting to jSon. My solution to this problem was to have the string already formatted to JSon before dropping into the file (in my case a database). The most efficient process I have come up with so far was to create a toJson function inside my classes to work just like toString.
Example:
Converts the objects data output string into Json format
public JsonObject toJson()
{
JsonObject temp = new JsonObject();
temp.addProperty(tagName,floatData);
return temp;
}
So for you, implement a similar process while populating your map.

Categories