Converting Strings to booleans when converting XML to JSON - java

This block of code essentially takes a JAXB Object and turns it into a JSONObject
StringWriter stringWriter = new StringWriter();
marshaller.marshal(jaxbObj, stringWriter);
try {
JSONObject jsonObject = XML.toJSONObject(stringWriter.toString());
resp.getOutputStream().write(jsonObject.toString(2).getBytes());
} catch (JSONException e) {
throw new ServletException("Could not parse JSON",e);
}
Unfortunately, this transformation doesn't turn, say, a String like "true" into a boolean, leaving the poor front end guy to do it.
I would think that I want to somehow map over the values in the JSONObject, calling stringToValue on each. I have a feeling there is a better way. Any ideas?

Well, JAXB itself won't even produce JSON to begin with, so you are using something else in addition (maybe use it via Jersey). So maybe package in question has something.
But why try to do this with org.json objects? Just use regular Java bean with expected type, create that from whatever input bean you have. No need for magic, just explicit code.

Related

Processing a string formatted as a JSONArray

We have some code where we read a JSON file into a string and then use Json-lib to process it as follows:
// ...
JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(jsonStr);
// ...
We now have a situation where the file is actually a JSONArray (i.e. starts with [ and ends with ]). The file passes all JSON validation tests but our code raises the following exception:
java.lang.ClassCastException: net.sf.json.JSONArray cannot be cast to net.sf.json.JSONObject
We are able to get past the problem by resorting to the following hack:
// ...
JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON("{" + jsonStr + "}");
// ...
Question: Is there a way to process the file, without resorting to the hack?
Question: Is there a way to process the file, without resorting to the hack?
I am assuming that you are using JSON-lib as implied by the [json-lib] tag.
I am also assuming that you have encountered this problem in writing the unit tests for your code. (If not ... why not?)
In the JSON-lib APIs, JSONObject and JSONArray have a common supertype JSON, so you should be able to assign a JSONObject or JSONArray to a variable of type JSON. (The JSON interface has methods isObject and isArray that allow you to test if a JSON is an object or an array ... but no asObject or asArray methods.)
However, if your tests actually require a JSONObject ... you have a problem. In JSON, the "object" and "array" data structures are fundamentally different. Neither is a conceptual subtype of the other. What your "hack" is doing is wrapping the JSON array inside a JSON object. This may or may not be the correct thing to do. (I suspect it isn't. But if it is the correct thing to do, then the "hack" is a reasonable way to do it. You could also construct a JSONObject and add the parsed JSONArray to it programatically.)
If the code under test is designed / specified to work with a JSON object and not with a JSON array, then the CORRECT solution is to reject the input file as bad input, at some point.
If your code under test is designed to do the parsing, then it should throw an exception (or whatever) to reject the bad input file. Your unit test should check that it does that.
If your code under test is designed to take a (parsed) JSONObject, then the testcase (the input file containing a JSON array) is a bad testcase. Remove it ... for the purposes of this unit test.
In short, the correct solution to your problem is going to depend on what the code you are testing is supposed to do.
You can read jsonStr as JSON Object, then convert it to Java Object:
net.sf.json.JSON json = JSONSerializer.toJSON(jsonStr);
YourJavaObject jObj = null;
List<YourJavaObject> list = null;
if(json instanceof JSONObject){
jObj = (YourJavaObject)JSONObject.toBean(JSONObject.fromObject(json), YourJavaObject.class);
}else if(json instanceof JSONArray){
list = JSONArray.toList(JSONArray.fromObject(json), new YourJavaObject(), new JsonConfig());
}

Deserialize Avro to Map

Does anybody know the way to deserialize Avro without using any Pojo and Schemas?
The problem:
I have a data stream of different Avro files.
The goal is to group that data depending on the presence of some attributes (e.g. user.role, another.really.deep.attribute.with.specific.value and so on).
Each avro entry might contain any number of matching attributes - from zero to all listed).
So, there is no need to do anything with data. Just to peek at some elements.
The question is, is there any way to convert that data to Map or Node? Like I can do it with JSON using Jackson or GSON.
I've tried to use GenericDatumReader, but it requires a Schema. So maybe all I need is to read the schema from avro (how?).
Also, I've tried to use something like this, but this approach doesn't work.
public Map deserialize(byte[] data) {
DatumReader<LinkedHashMap> reader
= new SpecificDatumReader<>(LinkedHashMap.class);
Decoder decoder = null;
try {
decoder = DecoderFactory.get().binaryDecoder(data, null);
return reader.read(null, decoder);
} catch (IOException e) {
logger.error("Deserialization error:" + e.getMessage());
}
}
Since I have time to 'play' with the problem, I have created a utility class that generates schemas depending on keys. It works, but looks like a big overhead.
A reader schema is required to deserialize any message.
If you have the writer schema available, you can simply use that. Note that if you have Avro files, these include the schema they were written with and you can use avro-tools.jar -getschema to extract it
Without these options, then you'll need to figure out the schema on your own (maybe using a hexdump and knowing how Avro data gets encoded)

Does the StringBuffer change the order of JSON?

I'm using StringBuffer to get JSON from a URL.
This is the original JSON
[{"name":"Italy","topLevelDomain":[".it"],"alpha2Code":"IT","alpha3Code":"ITA","callingCodes":["39"],"capital":"Rome","altSpellings":["IT","Italian Republic","Repubblica italiana"],"region":"Europe","subregion":"Southern Europe","population":60665551,"latlng":[42.83333333,12.83333333],"demonym":"Italian","area":301336.0,"gini":36.0,"timezones":["UTC+01:00"],"borders":["AUT","FRA","SMR","SVN","CHE","VAT"],"nativeName":"Italia","numericCode":"380","currencies":[{"code":"EUR","name":"Euro","symbol":"€"}],"languages":[{"iso639_1":"it","iso639_2":"ita","name":"Italian","nativeName":"Italiano"}],"translations":{"de":"Italien","es":"Italia","fr":"Italie","ja":"イタリア","it":"Italia","br":"Itália","pt":"Itália","nl":"Italië","hr":"Italija","fa":"ایتالیا"},"flag":"https://restcountries.eu/data/ita.svg","regionalBlocs":[{"acronym":"EU","name":"European Union","otherAcronyms":[],"otherNames":[]}],"cioc":"ITA"}]
This is the JSON That I end up with once I convert it to a string from the response
[{"area":301336,"nativeName":"Italia","capital":"Rome","demonym":"Italian","flag":"https://restcountries.eu/data/ita.svg","alpha2Code":"IT","languages":[{"nativeName":"Italiano","iso639_2":"ita","name":"Italian","iso639_1":"it"}],"borders":["AUT","FRA","SMR","SVN","CHE","VAT"],"subregion":"Southern Europe","callingCodes":["39"],"regionalBlocs":[{"otherNames":[],"acronym":"EU","name":"European Union","otherAcronyms":[]}],"gini":36,"population":60665551,"numericCode":"380","alpha3Code":"ITA","topLevelDomain":[".it"],"timezones":["UTC+01:00"],"cioc":"ITA","translations":{"br":"Itália","de":"Italien","pt":"Itália","ja":"イタリア","hr":"Italija","it":"Italia","fa":"ایتالیا","fr":"Italie","es":"Italia","nl":"Italië"},"name":"Italy","altSpellings":["IT","Italian Republic","Repubblica italiana"],"region":"Europe","latlng":[42.83333333,12.83333333],"currencies":[{"symbol":"\u20ac","code":"EUR","name":"Euro"}]}]
This is my code for getting the JSON + Converting it.
JSONArray JSON = null;
//Reading Variables
BufferedReader r = new BufferedReader(new InputStreamReader(con.getInputStream()));
String input;
StringBuffer response = new StringBuffer();
//Adding response to StringBuffer
while((input = r.readLine()) != null) {
response.append(input);
}
//Stopping the reader
r.close();
System.out.println(response);
//Convert StringBuffer to JSON
JSON = new JSONArray(response.toString());
System.out.println(JSON);
return JSON;
Is there a way of preventing it from doing this?
It's not the StringBuffer but the JSONArray.
The order of elements in an array [] is maintained like the list ["AUT","FRA","SMR","SVN","CHE","VAT"] in both examples.
Anything as a name value pair surrounded by {} can be reordered like {"code":"EUR","name":"Euro","symbol":"€"} and {"symbol":"\u20ac","code":"EUR","name":"Euro"}.
To prevent this, you can keep it as a String or create your own object and define the toString method.
Your question is similar to Keep the order of the JSON keys during JSON conversion to CSV.
It is not StringBuffer doing this. It is the JSON implementation itself.
For a start, according to all of the JSON specifications that I have seen, the order of the attributes of a JSON object are not significant. A JSON parser is not expected to preserve the attribute order, and neither is the in memory representation of a JSON object. So, for example, a typical in-memory representation of a JSON object uses a HashMap to hold the attribute names and values.
So my first piece of advice to you would be to change your application so that the order of the JSON attributes doesn't matter. If you design a JSON API where attribute order matters, then your API will be problematic.
(If this is in a testcase, it is not difficult to compare JSON properly. For example, parse the JSON and compare objects attribute by attribute.)
If you are lumbered with a (so-called) JSON API where the order of attributes has some meaning, my advice is:
Complain. Submit a bug report. This is not a proper JSON API.
Look for a JSON library that provides a way to work around the bad design. For example, some libraries allow you to provide a Map class to be used when constructing a JSONObject. The default is usually HashMap, but you could use LinkedHashMap instead.

Interpolate JSON values into a string

I am writing an application/class that will take in a template text file and a JSON value and return interpolated text back to the caller.
The format of the input template text file needs to be determined. For example: my name is ${fullName}
Example of the JSON:
{"fullName": "Elon Musk"}
Expected output:
"my name is Elon Musk"
I am looking for a widely used library/formats that can accomplish this.
What format should the template text file be?
What library would support the template text file format defined above and accept JSON values?
Its easy to build my own parser but there are many edge cases that needs to be taken care of and I do not want to reinvent the wheel.
For example, if we have a slightly complex JSON object with lists, nested values etc. then I will have to think about those as well and implement it.
I have always used org.json library. Found at http://www.json.org/.
It makes it really easy to go through JSON Objects.
For example if you want to make a new object:
JSONObject person = new JSONObject();
person.put("fullName", "Elon Musk");
person.put("phoneNumber", 3811111111);
The JSON Object would look like:
{
"fullName": "Elon Musk",
"phoneNumber": 3811111111
}
It's similar to retrieving from the Object
String name = person.getString("fullName");
You can read out the file with BufferedReader and parse it as you wish.
Hopefully I helped out. :)
This is how we do it.
Map inputMap = ["fullName": "Elon Musk"]
String finalText = StrSubstitutor.replace("my name is \${fullName}", inputMap)
You can try this:
https://github.com/alibaba/fastjson
Fastjson is a Java library that can be used to convert Java Objects into their JSON representation. It can also be used to convert a JSON string to an equivalent Java object. Fastjson can work with arbitrary Java objects including pre-existing objects that you do not have source-code of.

Is startDocument() with Androids XMLSerializer required?

For a certain application (serializing and deserializing an object for transport via XMPP PubSub item payload), I need to create XML fragments - this is I have to omit the document declaration.
I'm using the org.xmlpull.v1.XmlSerializer class; unfortunately there doesn't seem to be much documentation available on the correct usage of it. At least all documentation I've found on its startDocument() method leaves it unclear whether I can or cannot skip calling this method. At least all examples I've found call this method (but all of them explained just how to create complete XML documents, no fragments).
To give a code example:
XmlSerializer xmlSerializer = Xml.newSerializer();
StringWriter xmlStringWriter = new StringWriter();
try {
xmlSerializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
xmlSerializer.setOutput(xmlStringWriter);
// xmlSerializer.startDocument("UTF-8", true);
xmlSerializer.startTag(null, "tag-name");
// ...
xmlSerializer.endTag(null, "tag-name";
// xmlSerializer.endDocument();
xmlSerializer.flush();
} catch (IOException e) {
// Hanle exception
}
String xmlOutputString = xmlStringWriter.toString();
Is this allowed? And if not, is there any other way to generate fragments with XMLSerializer without parsing the output string in order to manually remove the document declaration (e.g. calling startDocument only with null parameters)?
Here comes the answer in short terms: No, calling startDocument() is not required and will skip generating the document declaration.

Categories

Resources