I have such structure of object:
class A {
List<B> bees;
}
class B {
String с;
}
I'm using Gson parser which serializes such object into this string:
{"a":{"bees":[{"с":"text"}]}}
(with adding a root element "a")
API's format is a little bit different:
{"a":{"bees":[{"b":{"с":"text"}}]}}
I need to be able to parse such strings into A objects correctly.
By default B object (as a part of A) becomes not null, but empty (all fields are null) which is understandable, cause parser doesn't find any field "b" in it (when it is actually a class name).
I'm looking for a general solution for that, I have a lot of such complex objects and I don't want to implement many custom deserializers for each of them.
Gson is not obligatory, I can use another lib if it's necessary.
Thanks.
I prefer Jackson Tree Model and JDK 8 Stream to parse such json string, the core idea is to map the bees array element {"b":{"с":"text"}} to {"с":"text"} by the functional map() API.
ObjectMapper mapper = new ObjectMapper();
JsonNode beesNode = mapper.readTree(jsonString).get("a").get("bees");
List<JsonNode> bs = StreamSupport.stream(beesNode.spliterator(), false)
.map(bee -> bee.get("b")).collect(Collectors.toList());
If it is possible for you to change the class structure then change the class structure so as to match the API's format. For example,
class A {
List<B> bees;
}
class B {
MyTypeObjB B;
}
class MyTypeObjB {
String c;
}
EDIT As per the comments, you can also try to customize deserialize method by implementing JsonDeserializer interface on your custom class.
You can find detail information how it can be performed on,
custom-json-deserializer
gson-deserialiser-example
Related
Consider we are having the following classes
//following classes are present in external lib, we can not modify them.
class A{
private Map mapOfListOfB; // this should have been properly typed Map<String,List<B>>
}
class B{
private int val1;
private String val2;
private C val3; // Class C can be anything but the point here is the same object of C can be used in multiple B objects
//which means we can reuse the reference using #JsonIdentityInfo
}
now, when we use Jackson's objectMapper to serialize and deserialize this Class A,
we would not be able to deserialize because we are not giving any typed info to Jackson so it ends up creating List<LinkedHashMap>
here is one solution that I know, works for class having a collection with a specific class type
eg:
class D{
private Map mapOfB // which should have been Map<String,B>
}
// this can be typed by using jackson's mixin
abstract class DmixIn{
#JsonDeserialize(contentAs = B.class)
Map mapOfB
}
but how we can tell the type which is present in class A to Jackson as we can not pass ParameterizedType to contentAs, it just takes class instance.
I know we can write a custom deserializer to achieve the end result but I am looking for a more readable solution here, like any Jackson annotation or any simple config which we can be set on the property level.
and another issue(which can be because of my awareness) is I even need to maintain deserialization context while writing custom deserializers by using #JsonDeserialize(contentUsing = CustomDeserializer.class) because Class C references are reused and I may need to resolve IDs for this POJO while deserializing
I'm using jackson's ObjectMapper to convert JSON files into Java objects.
How do I convert a JSON object that has an array as one of its fields? Example below:
{
"list":[
{
"value":"example"
},
{
"value":"example2"
}
]
}
ObjectMapper converts this into a LinkedHashMap with lines as the key and the value is an ArrayList with LinkedHashMaps, which have valueand example and so on.
Is there a way to read this json as an Object with a field list that is a List/Array containing objects which would fit (in this case, a simple object with String value as a field)?
Found a way to do this. This solution is based around Gson instead of ObjectMapper.
Basically Gson manages to convert arrays into the fields as I wanted it to happen here, instead of generating a lot of LinkedHashMaps.
You can achieve this with Jackson in a straight-forward way.
For this you need to model the JSON structure by some Java classes.
First, you need a class for modeling the whole JSON content
(let us call it Root) with a list property.
public class Root {
private List<Item> list;
// public getter and setter (omitted here for brevity)
}
Next, you need a class for modeling the list items
(let us call it Item) with a value property.
public class Item {
private String value;
// public getter and setter (omitted here for brevity)
}
Then you are able to read JSON content into a Java Root object by using
one of ObjectMapper's readValue(..., Class<T>) methods.
For example reading from a File:
ObjectMapper objectMapper = new ObjectMapper();
Root root = objectMapper.readValue(new File("example.json"), Root.class);
I am currently developing a web application and I would like to make java objects persistent at the server so that they can be retrieved at any time. Since a database is an overkill for my application, I choose the easiest way of persisting java objects: serialization to xml or to bytes. Unfortunately a big part of the code I use are java classes which I cannot modify and these classes do not implement the interface 'serializable'. What are my options regarding to serializing objects of these classes, as well as other interacting objects of my own classes?
As I said in my comments, I'd go for a SerializationService which would find the proper Serializer<T> for every object you want to save.
Something like :
public interface Serializer<T> {
Serializable toSerializable(T objectToSerialize);
//to build a factory/service around it
boolean canDeserialize(Serializable serializedObject);
T fromSerializable(Serializable serializedObject);
}
And if you want a basic, concrete example : with the quite-common Path :
public class PathSerializer implements Serializer<Path> {
#Override
public Serializable toSerializable(Path objectToSerialize) {
return objectToSerialize.toString();
}
#Override
public Path fromSerializable(Serializable serializedObject) {
if(!canDeserialize(serializedObject)){
throw new IllegalArgumentException("Cannot deserialize this");
}
return Paths.get((String)serializedObject);
}
#Override
public boolean canDeserialize(Serializable serializedObject) {
return serializedObject != null && serializedObject instanceof String;
}
}
You could also very well store POJO containing the name your original object class and the list of parameters needed in its constructor an/or a map of its fields to be able to regenerate your objects by reflection.
It's all up to you and the complexity of your application.
I think JSON would be the go-to solution here. Take Googles GSON library for example. You don't need to annotate your classes, simply write
Gson gson = new Gson();
MyObj obj = gson.fromJson(jsonString);
String json = gson.toJson(obj);
For more general information about the JSON format see the official JSON documentation.
One option would be to extend the classes that you don't have access to, in order to save their internal state, and implement Serializable on those.
More info on this SO question:
Serializing a class variable which does not implement serializable
Besides this, I don't think there is any other option except building some wrappers and serializing the classes manually to XML or JSON.
For example, given JSON:
[
{"id":"3", "location":"NewYork", "date":"yesterday"},
{"id":"4", "location":"Moscow", "date":"today"}
]
resulting HashMap:
<"3", POJOLocation("NewYork", "yesterday")>
<"4", POJOLocation("Moscow", "today")>
where POJOLocation is a Java object:
class POJOLocation {
private String location;
private String date;
// etc
}
I've tried using custom deserializer, but it was really bloated with generic's tokens and hackish typeOfs. Perhaps there is a simple efficient solution?
Maybe create a POJOLocationId class:
class POJOLocationId {
private int id;
private String location;
private String date;
// etc
}
Then deserialize & loop over the resulting List populating your HashMap as you go?
Gson is designed to make serializing Java objects to their JSON equivalent painless. If you're trying to represent a Java data structure as a different type of JSON structure you're not going to have a lot of fun writing serializers and deserializers. At that point you might consider a lower-level JSON parser and simply implement the parsing you want yourself. Rather than representing your data one way in JSON and another way in Java (and thus running into the hassle of transforming between them) you might consider refactoring either your data structure or your data so they're more similar.
That said the easiest thing to do with Gson (which is really not that bad, memory and time-wise) is to use a wrapper type and then transform the input/output before using it. Something like so (borrowing from Tom Mac's type name):
private static final Type LIST_TYPE =
new TypeToken<List<POJOLocationId>>() {}.getType();
public String serialize(Map<Integer, POJOLocation> locations) {
List<POJOLocationId> locationsList = original.entrySet().stream()
.map(e -> new POJOLocationId(e.getKey(), e.getValue()).collect(toList());
return gson.toJson(locationsList);
}
public Map<Integer, POJOLocation> deserialize(String json) {
List<POJOLocationId> locationsList = gson.fromJson(json, LIST_TYPE);
return locationsList.stream()
.collect(toMap(l -> l.getId(), new POJOLocation(l)));
}
You certainly can get this same behavior with a custom deserializer, but this works, it's clean, and it's easy to read. The garbage collector should have no trouble cleaning up these temporary wrappers as soon as these methods return.
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