Backward compatibility with JSON - java

I have a java application which saves the fields of an object to a file and load them later again.
I used so far a modified version of java.util.properties.Properties file (the properties were written in the order they were put in the properties object). I defined for each field a property-key and use the following function to set the property in the properties object
properties.setProperty(PROPERTY_KEY_FIELD_X, field_x);
and used the following function if I want to read back from the properties file
field_x = properties.getProperty(PROPERTY_KEY_FIELD_X, ""));
where I can add a default value which will be choosed, when there is no property with the specified key. As I maybe add some fields in the future in the class from which the fields were saved in the file, I used this option with the default value to set a field to some defined value for the case I load a properties file which was written with an older version of this class.
So far it works but with some obvious disadvantage, for example I can't use the same property key more than once, I have to add some kind of indices like 1_PROPERTY_KEY, 2_PROPERTY_KEY. Thats why I came across JSON.
I'm not very familiar with JSON and all the things we can achieve with it. But I know I could use it to save the fields of an object to the JSON notation and read it back for example with Gson
//Object to JSON
Gson gson = new Gson();
String json = gson.toJson(object);
//JSON to Object
object = gson.fromJson(json);
But I assume this will fail, if the class is a newer version (i.e. some new fields) when try to read back from the JSON. How can I treat this? Do I have to take care of every seperate field similar to the the current implementation with properties? For example like this (with com.google.gson), assuming jsonString is the string read from the file:
//try/catch block omitted
JSONParser parser = new JSONParser();
JSONElement json = parser.parse(jsonString);
field_x = json.getAsString("field_x");
and take care if something failed to set default values to the fields?
Or is there a completely different approach without JSON or is JSON in general suitable for my use-case?

I'm not an expert of JSON too. But I used it sometimes with Jackson and I think Gson is very similar. If you want to use versioned objects just assure in your object constructor that fields are given with a default value (outside correct values range). Jackson will match only those json fields where it finds a correspondent filed in th Java object. Otherwise the default value is kept.

With GSON, you get to define your model as an object. As an example:
public class Configuration
{
private String x;
private String y;
}
Later, you may adjust Configuration to have an additional field, z:
public class Configuration
{
private String x;
private String y;
private String z;
}
When you use GSON to deserialise your JSON file that does not contain a value for z, it will be left null (or whatever the Java default value for that type is).
Since you have an object, you can define getters that substitute a default value if one is not specified:
public String getZ()
{
if (this.z == null)
{
return "the default z value";
}
return this.z;
}

If you're not goind to send data across network, I think you don't need Json but use native Java classes (ie properties). It's reduntant object creation

Related

Is there some way for a Jackson Delegate-based Creator to access the raw Json String?

Is there some way for a Jackson Delegate-based creator to access the raw Json String?
#JsonCreator
private static MyClass createFromJson(Map<String, Object> jsonProperties) {
return new MyClass(rawJson);
}
I am able to get the raw input as a Map of Strings to Objects in the code above, but I want to be able to access the json as a string. I tried the code below (based off of http://www.cowtowncoder.com/blog/archives/2011/07/entry_457.html) but that code as written is never invoked.
#JsonCreator
private static MyClass createFromJson(String rawJson) {
return new MyClass(rawJson);
}
Note: This is a spring boot application (1.3.1.RELEASE) that uses Jackson 2.6.4.
Looks like this type of functionality would not make sense in this context. In fact, it appears to me now that requesting the JSON string in this instance defeats the purpose of using jackson in the first place. However if anyone finds themselves here, then the comments from Sotirios Delimanolis may be useful:
"Hack: you can receive a JsonNode as the parameter type and use its toString method to get the corresponding JSON."
"It looks like you want a JsonDeserializer"

Is case important while parsing JSON using GSON

I am parsing JSON data, and storing the results in a Java object using GSON. My question is, should the fields in the JSON String match the instance variables in the class? Including the class names? For eg,
If this is my JSON string -
"telephone":
{
"landline":"1-818-502 8310"
}
Should I have a class as below?
public class Telephone
{
private String landline;
}
The reason why I am asking this is, when I use gson's fromJson(obj), the object doesn't contain any values. It shows all records as null. I am wondering if it is throwing the error due to this.
Please note - This is not the entire code. My JSON data is quite huge, so I can't paste it here. The above telephone string is just one of the many embedded strings within my json string.
This is wrong JSON:
"telephone":{"landline":"1-818-502 8310"}
The JSON objects start with a { and end with a }. SO, it should be something like
{"name": "somename", "telephone":{"landline":"1-818-502 8310"}, ...}
Yes. Attributes in class should have exact same case and character as in the JSON String in case you are using default Gson instance as correctly mentioned by Eliran. Please note that you must have attributes just having getter/setter and not attribute wouldn't work.
You mentioned you are using inner class. It may not work with default Gson instance. You may need to use registerTypeAdapter like this:
gson.registerTypeAdapter(MyType.class, new MyInstanceCreator());
refer: https://sites.google.com/site/gson/gson-user-guide#TOC-Custom-Serialization-and-Deserialization

Javascript Object to Java List

I have the following type of JSON I want to send to Java (I'm using Jersey and the default JSON Parser it comes with)
{ "something" : "1", "someOtherThing" : "2" , ... }
But instead of creating an Object with all these properties in Java, I would like to have a Single HashMap (or whatever) that will allow me to still have access to the Key and the Value
Is such a thing possible?
I don't really have any code that does the transformation, I use Jersey like this
#POST
#Path("/purchase")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public StatusResult purchase(UserPurchaseRequest upr) {
}
If i put properties something and someOtherThing as Strings in my UserPurchaseRequest object, everything will come in fine, but I want to have everything in one structure (because I don't know how many values I will get, and I need their names as well)
Yes, it is possible. But still, it depends on what JSON java API you are using. For example using Jackson JSON you can create HashMap json string like this
ObjectMapper obj = new ObjectMapper();
String json = pbj.writeValue(<HashMap object>);
or vice-versa
HashMap obj = obj.readValue(json, HashMap.class);
Note - org.codehaus.jackson.map.ObjectMapper
You just need to add a Property to your Object like this
private HashMap<String,String> purchaseValues;
Jersey takes care of the rest, for some reason while you are debugging, most of the entries appear as null in the HashMap

How to marshall POJO to JSON using JETTISON?

I have done the marshalling of a JaxB java object to Json using JETTISON. But I can not marshall a simple java object (which has no annotations in it) to Json using JETTISON. I know it is possible to do it by using GSON or MOXy or some other providers.
But I like to get clear "Can we do it using JETTISON?"., If we can, How to do it?
Thanks in Advance.
Don't waste your time, this is simply not what Jettison was designed to do. Conceivably, it would have been possible to instantiate a JSONObject with your POJO and serialize it that way, but there are some issues with its code that make this next to impossible:
It requires passing in the names of the fields that will be included in the JSON.
It can only process public properties of the supplied object.
Not to mention it cannot handle nesting of any kind. Take a look at this lovely code:
Class c = object.getClass();
for (int i = 0; i < names.length; i += 1) {
try {
String name = names[i];
Field field = c.getField(name);
Object value = field.get(object);
this.put(name, value);
} catch (Exception e) {
/* forget about it */
}
}
Yep, thats the code in the constructor JSONObject(Object, String[]). I'm sure you will see the problems with it (raw access to generic objects, can only access public fields, sloppy exception handling). All in all - very bad 'serialization' code.
I know its probably not what you want to hear, but if you want to convert regular Java objects to JSON then you might want to stick with one of the more general-purpose libraries.
JAXB (JSR-222) is configuration by exception and only requires annotations where you need to override the default XML representation (Jettison converts XML StAX events to/from JSON). Instead of #XmlRootElement you can wrap your object in an instance of JAXBElement.
http://blog.bdoughan.com/2012/07/jaxb-no-annotations-required.html

Is there a way to create the bean class from a json response

Converting JSON to Java
The above question is with reference to what has been described on the above thread. There are so many API(s) which provide the flexibility to return responses either in XML or JSON. **I would like to know if there is a way to automatically construct the java bean corresponding to a JSON response. **
lets say you get an object like
[
{
"name":"Java 6 Greatest Hits",
"Author":"Jim Bob Jones",
"price":10.25
},
{
"name":"How to raise a goat",
"Author":"Sir Paxton",
"price":55.97
},
{
"name":"Snow - It is cold",
"Author":"Dr. White",
"price":9.99
}
]
And you want a class like
public class Book{
private String author;
private String name;
private Number price
}
with getters and setters
One option is to use a service like JSONGen, which will create that class. You need to use it first, and include the generated code in your project.
Another option could be dynamically generate the class using javassist or CGLib, but that class would be useless unless you use reflection to access its members, so even if it would be a class, it will behave like a really annoying Map. In no way will be better that simple using JSONObject
seems a simple Message Type Entity not meet you requirement ?
if you want convert a json to an existed and known java bean class,
many lib can do so, like
http://json-lib.sourceforge.net/apidocs/net/sf/json/class-use/JSONObject.html
JSONObject.toBean(JSONObject jsonObject, Class beanClass)
Creates a bean from a JSONObject, with a specific target class.
btw, if you are communicating with restful webservice, org.springframework.web.client.RestTemplate will help you get direct bean result
insteadof json.
if class does not exists, you need program with java reflect mechanism.
try use CGLIB ,http://cglib.sourceforge.net/, dynamic create some class like BeanMap. i wrote a simple sample,
but be ware, opearting class byte is hard and you may meet strange trouble with JVM . Strongly not encourage to do so.
public static BeanMap generateBean(JSONObject json) {
BeanGenerator generator = new BeanGenerator();
Iterator keys = json.keys();
while (keys.hasNext()) {
Object key = keys.next();
Object value = json.get(key);
Class keyClass = guessValueClass(value);
generator.addProperty(key.toString(), keyClass);
}
Object result = generator.create();
BeanMap bean = BeanMap.create(result);
keys = json.keys();
while (keys.hasNext()) {
Object key = keys.next();
Object value = json.get(key);
bean.put(key, value);
}
return bean;
}
/**
* TODO fix guess
*/
static Class guessValueClass(Object value) {
try {
Integer.parseInt(value.toString());
return Integer.class;
} catch (NumberFormatException e1) {
}
try {
Double.parseDouble(value.toString());
return Double.class;
} catch (NumberFormatException e1) {
}
return String.class;
}
I believe the main issue here is that the JSON response lacks type information and last time I checked :-) in Java you need to declare the type of a class property. So some heuristics will be needed to infer the type form the value in the JSON response.
For a related question here in SO have a look at: Generate Java class from JSON?
Yes check out http://flexjson.sourceforge.net
If you're wanting to generate Java classes from JSON, perhaps you could try Jackson. It provides a lot of JSON-related functionality, including the ability to generate bytecode from arbitrary JSON. See this blog post for details.
If you're using Jackson (the most popular library there), try
https://bitbucket.org/astav/jsontojava/wiki/Home
Its open source and anyone should be able to contribute.
Summary
A JsonToJava source class file generator that deduces the schema based on supplied sample json data and generates the necessary java data structures.
It encourages teams to think in Json first, before writing actual code.
Features
Can generate classes for an arbitrarily complex hierarchy (recursively)
Can read your existing Java classes and if it can deserialize into those structures, will do so
Will prompt for user input when ambiguous cases exist

Categories