I'm trying to deserialize some JSON with Jersey/Jackson in Java.
Here is an example of my JSON
{
"text":"toto",
"link":"titi",
"items":[{
"text":"toutou",
"link":"tata",
"items":[{
"text":"toto2",
"link":"toutou2",
"data":"tonti",
]}
]}
}
So what my Java model parts looks like this
public IItem {
...
}
public Item implements IItem {
List<IItem> items;
String text;
String link;
...
}
public ItemData extends Item {
String data;
...
}
Now, when i try to deserialize my JSON, object mapper doesnt know what concrete class to Use.
How do I tell him this ? The thing is that I want an Item (with a list of Item (with a list of ItemData)).
I've though of only using one object containing all fields (text, link, data), but i'd prefer this type of design which appears better me. Do you think it's worth it ?
In reality I have more than one field that would replicate because JSON structure is a bit more complex, I've simplified it for sake of clarity.
Question2 : After that i need to serialise my objects again in JSON (first part is only for temporary development, I'll be filling objects from a JDBC driver later on), how can I tell jersey to only display one level at the time ?
i.e i request / I want the first level only, answer should be :
{
"text":"toto",
"link":"titi",
"items":[{
"text":"toutou",
"link":"tata",
]}
}
and if i request /tata answer should be :
{
"text":"toutou",
"link":"tata",
"items":[{
"text":"toto2",
"link":"toutou2",
"data":"tonti"
]}
}
(Question is more about how hiding the second level in my first request, I do understand how to handle the second request).
Thanks,
If your using Jackson, it has a feature that allows for proper deserialization in these kind of cases (polymorphic list of items). You can use the #JsonTypeInfo annotation to indicate you want the object type to be included in the JSON, which will then be used to deserialize the correct instances. Here's an example:
#JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="#class")
public IItem {
// ...
}
This will add an attribute to each serialized representation of IItem, called #class, which Jackson will detect and use later on to deserialize the correct object instance.
Related
We are trying to create a Java client for an API created with Spring Data.
Some endpoints return hal+json responses containing _embedded and _links attributes.
Our main problem at the moment is trying to wrap our heads around the following structure:
{
"_embedded": {
"plans": [
{
...
}
]
},
...
}
When you hit the plans endpoint you get a paginated response the content of which is within the _embedded object. So the logic is that you call plans and you get back a response containing an _embedded object that contains a plans attribute that holds an array of plan objects.
The content of the _embedded object can vary as well, and trying a solution using generics, like the example following, ended up returning us a List of LinkedHashMap Objects instead of the expected type.
class PaginatedResponse<T> {
#JsonProperty("_embedded")
Embedded<T> embedded;
....
}
class Embedded<T> {
#JsonAlias({"plans", "projects"})
List<T> content; // This instead of type T ends up deserialising as a List of LinkedHashMap objects
....
}
I am not sure if the above issue is relevant to this Jackson bug report dating from 2015.
The only solution we have so far is to either create a paginated response for each type of content, with explicitly defined types, or to include a List<type_here> for each type of object we expect to receive and make sure that we only read from the populated list and not the null ones.
So our main question to this quite spread out issue is, how one is supposed to navigate such an API without the use of Spring?
We do not consider using Spring in any form as an acceptable solution. At the same time, and I may be quite wrong here, but it looks like in the java world Spring is the only framework actively supporting/promoting HAL/HATEOAS?
I'm sorry if there are wrongly expressed concepts, assumptions and terminology in this question but we are trying to wrap our heads around the philosophy of such an implementation and how to deal with it from a Java point of view.
You can try consuming HATEOS API using super type tokens. A kind of generic way to handle all kind of hateos response.
For example
Below generic class to handle response
public class Resource<T> {
protected Resource() {
this.content = null;
}
public Resource(T content, Link... links) {
this(content, Arrays.asList(links));
}
}
Below code to read the response for various objects
ObjectMapper objectMapper = new ObjectMapper();
Resource<ObjectA> objectA = objectMapper.readValue(response, new TypeReference<Resource<ObjectA>>() {});
Resource<ObjectB> objectB = objectMapper.readValue(response, new TypeReference<Resource<ObjectB>>() {});
You can refer below
http://www.java-allandsundry.com/2012/12/json-deserialization-with-jackson-and.html
http://www.java-allandsundry.com/2014/01/consuming-spring-hateoas-rest-service.html
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.
We have a class containing multiple Sets of Longs. We want them serialized as arrays, and most clients do so.
However, we have a PHP client that creates sets such that they serialize in an odd way. A set with the number 4 comes in like this:
"setOfNumbers": {
"4": 0
},
Naturally, Jackson complains about this being an object and not an array. What I would like is to have a custom deserializer that is only invoked if Jackson detects an object where a Set<Long> should be (and ideally only if they are contained in specific classes.)
I've tried this:
this.addDeserializer(Set.class, new StdDelegatingDeserializer<>(new StdConverter<Map<String, Long>, Set<Long>>() {
#Override
public Set<Long> convert(Map<String, Long> set) {
return parseLongs(set);
}
}));
The problem with this is that now it expects an object instead of an array for all Set fields. The class being deserialized is generated, so I can't add any annotations or make other changes.
If the generated class has always the same name you can try with Json Jackson Mix-in annotations as shown in this example
I have a JSON string looking like that (simplified):
[
{ "id":1, "friends":[2] },
{ "id":2, "friends":[1,3] },
{ "id":3, "friends":[] }
]
The content of friends are ids of other users in the list.
Is it possible somehow to create a Java class like the one below from the JSON just with Data Binding using Jackson or do I need an intermediate step for that?
public class User {
private long userid;
private List<User> friends;
// ... getters/setters
Thanks for your help.
There is no fully annotative way to do this, so you would need custom JsonSerializer / JsonDeserializer. Jackson 1.9 adds two new features that might help:
ValueInstantiators, so you can add constructors for deserializer to convert from basic integer into POJO
Value injection so you could pass additional context object (which you would need to find ids of already deserializer objects, to map then from integer to instance)
However I am not 100% sure how to combine these two features for specific use case...
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