When using JsonUtility to serialize in Unity, List of a class will be serialized as empty string if it's filled with subclasses of ExampleObjtype.
[Serializable]
public class SerializableGameEntityDebugSubclass : SerializableGameEntityDebug {
public SerializableGameEntityDebugSubclass() : base() {}
}
[Serializable]
public abstract class SerializableGameEntityDebug {
public string uuid = null;
public SerializableGameEntityDebug() {
this.uuid = "debuggin";
}
}
public class GameSaveData
{
public List<GameEntity.SerializableGameEntityDebugSubclass> serializableGameEntitiesDebug1 = new List<GameEntity.SerializableGameEntityDebugSubclass>{ new SerializableGameEntityDebugSubclass() };
public List<GameEntity.SerializableGameEntityDebug> serializableGameEntitiesDebug2 = new List<GameEntity.SerializableGameEntityDebug>{ new SerializableGameEntityDebugSubclass() };
}
serializableGameEntitiesDebug1 DOES get subclassed and serializableGameEntitiesDebug1 does NOT get subclassed. I find this very odd because even if I print out individually the serialized elements of the list, it works correctly in both cases.
There are two separate issues at play.
It seems JsonUtility won't serialize List of any abstract class no matter what. So the thing the list contains must not be an abstract class
When I change the abstract class to a regular class, it will serialize it, but it will only contain fields in the base class rather than child classes.
Therefore it seems the only workaround is to have many lists to serialize (one for each child class)
Update: A slightly more elegant solution was to switch from using JsonUtility to Json.net JsonConverter. This caused serialization to work perfectly, but not yet deserialization. I still had to write a converter class so the deserializer knows which class to instantiate. I followed this answer and it worked. Last but not least it seems that each serializable class needs to have a default empty constructor for the deserializer to call when trying to instantiate it before hydrating it, or else it might try to call other constructors with null args
In my REST application I am using fasterxml to serialize and deserialize POJOs to JSON. I run into problems with collections such as List in a case like this.
public class JsonRequest {
public int anumber;
public String astring;
public List<XyzClass> data;
}
The properties anumber and astring convert back and forth just fine without any annotations. For **data*, although the compiler can see that the List elements are (should be) XyzClass that information is not available to the jackson framework, so it doesn't know what class to use when deserializing the elements.
For some reason I can't make sense of the documentation as to which annotation to use to fix this. The #JsonDeserialize annotation doesn't help this. Can anyone point me in the right direction?
After some research I finally found out how to make this work.
public class JsonRequest {
public int anumber;
public String astring;
#JsonDeserialize(contentAs = XyzClass.class) // <-- Added
public List<XyzClass> data;
}
To answer the questions in comments above, the code for XyzClass is just a trivial POJO like:
public class XyzClass {
public String name;
public int age;
}
What was tripping me up is that I was looking for an annotation to the effect of #JsonDeserializeContentAs(class = XyzClass.class) which doesn't exist because I missed the fact that #JsonDeserilize had a contentAs option.
Hopefully this posting will save someone else the same trouble.
My class is as below:
class A
{
private B b;
private String id;
//setter and getter
}
class B
{
private String name;
//setter and getter
}
class C extends B
{
private String email;
//setter and getter
}
My Json is as below:
{
"name":"Sample",
"id":2,
"email":"support#abd.com"
}
Now when I try to deserialise my json into a java object, I get:
org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Unrecognized field "email"
Please let me know how I could solve this.
You need to make sure that you are handling deserializing the shared nodes in the base class, and the nodes specific to your class b/c in their own respective classes. If you are handling deserialization in your top level class, it won't recognize a unique property in an inheriting class.
It's difficult to see where you are going wrong without seeing your individual classes.
Question regarding combination of Jackson/JPA
If there are about 20 entities in current application and I have add Jackson dependency in POM, does it mean all entities are by default ready to convert to JSON object? I saw a sample project seems only class annotated as #JsonIgnored is skipped by JSON. If so, then how can this happen, what is behind such mechanism? how JACKSON handle those entities which don't have any Jackson annotation, by default ignored or not? I've been looking for resources online but not much luck.
If only one of the 20 entities need to be mapped to JSON object, does it mean I have to add #JsonIgnore to all other 19 entities? If not, how Jackson differentiate with entity to work on?
Thanks.
Jackson and JPA don't have anything to do with each other. Jackson is a JSON parsing library and JPA is a persistence framework. Jackson can serialize almost any object - the only requirement being that the object have some kind of recognizable properties (Javabean type properties, or bare fields annotated with #JsonProperty. There is an additional requirement for deserialization, that the target type have a default (no-arg) constructor. So, for example, this is an object that Jackson can serialize:
// Class with a single Javabean property, "name"
class Person {
private String name;
public String getName() { return name ; }
public String setName(String name) { this.name = name ; }
}
And here is another:
// Class with a single field annotated with #JsonProperty
class Account {
#JsonProperty("accountNumber")
private String accountNumber;
}
And here is yet another:
#Entity
public class User {
#Id
private Long id;
#Basic
private String userName;
#Basic
#JsonIgnore
private String password;
#Basic
#JsonIgnore
private Address address;
// Constructors, getters, setters
}
The last example shows a JPA entity class - as far as Jackson is concerned it can be serialized just like any other type. But, take note of its fields: when this object is serialized into JSON two of the fields will not be included - 'password' and 'address'. This is because they have been annotated with #JsonIgnore. The #JsonIgnore annotation allows a developer to say 'Hey, its ok to serialize this object, but when you do so don't include these fields in the output'. This exclusion only occurs for the fields of this object, so for example, if you included an Address field in another class, but did not mark the field as ignorable, it would be serialized.
To prevent serialization of a type in all cases, regardless of context, use the #JsonIgnoreType annotation. When used on a type it basically means 'I dont care where this type is used, never serialize it'.
No, you don't need to add #JsonIgnore on every class and if you had tried you would have gotten a compile error, since you can't put it there. Jackson will only work on objects you give to it, it's no magic.
The Jackson documentation is easily found online, such at its project page on github or on the codehaus website.
I have bi-directional relationship like this...
Person.java
public class Person{
#JsonIgnore
#OneToMany(targetEntity=PersonOrganization.class, cascade=CascadeType.ALL,
fetch=FetchType.EAGER, mappedBy="person")
private Set<PeopleOrg> organization;
.....
}
PersonOrganization.java
public class PersonOrganization{
#JsonIgnore
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="PERSONID", nullable=false)
private Person person;
}
Even with #JsonIgnore annotation I am getting infinite recursion error when trying to retrieve Person records. I have tried new annotations in 1.6 version. #JsonBackReference and #JsonManagedReference. Even then I am getting infinite recursion..
With #JsonBackReference("person-organization") on Person and #JsonManagedReference("person-organization") on PersonOrganization
org.codehaus.jackson.map.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: com.entity.Person["organization"]->org.hibernate.collection.PersistentSet[0]->com.entity.PersonOrganization["person"]->com.entity.Person["organization"]->org.hibernate.collection.PersistentSet[0]...
Even If I interchange the annotations, I am still getting this exception.. Please let me know if there is something wrong with the mappings or the way I am using JSON annotations. Thanks
I've run into this before. But after moving #JsonIgnore from private field to getter of the field, infinite recursion is gone. So my wild guess is that #JsonIgnore might no work on private field. However, javadoc or tutorial of Jackson Java JSON-processor do not mention about this, so I cannot be 100% sure. Just for your information.
The following link says you should annotate the method used by JSON tool to traverse the object graph, to instruct the it to ignore the traversal.
http://jackson.codehaus.org/1.0.1/javadoc/org/codehaus/jackson/annotate/JsonIgnore.html
In my case I have two objects related like this Product <-> ProductImage. So JSON parser went into an infinite loop with out #JsonIgnore annotation on the following to get methods
#JsonIgnore
public Product getImageOfProduct() {
return imageOfProduct;
}
in ProductImage and
#JsonIgnore
public Set<ProductImage> getProductImages() {
return productImages;
}
in Product.
With the annotation, things are working fine.
I know this question isn't specifically about Spring Data REST, but I ran into this exception in the context of Spring Data REST, and wanted to share what the problem was. I had a bidirectional relationship involving an entity with no repository. Creating the repository made the loop disappear.
Since Jackson 1.6 you can use two annotations to solve the infinite recursion problem without ignoring the getters/setters during serialization: #JsonManagedReference and #JsonBackReference.
For more details refer https://stackoverflow.com/a/18288939/286588
Apparently since Jackson 1.6 you can use #JsonManagedReference and #JsonBackReference to effectively solve the infinite recursion problem.
I won't go into the details but this changing you classes to the below format should solve the problem.
public class Person{
#OneToMany(targetEntity=PersonOrganization.class, cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="person")
#Column(nullable = true)
#JsonManagedReference
private Set<PeopleOrg> organization;
.....
}
public class PersonOrganization{
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name="PERSONID")
#JsonBackReference
private Person person;
}
Basically Jackson converts Set<PeopleOrg> organization, the forward part of the reference a to json-like format using the marshalling process, it then looks for Person person, the back part of the reference and does not serialize it.
Credits - Kurt Bourbaki & More info - http://keenformatics.blogspot.co.ke/2013/08/how-to-solve-json-infinite-recursion.html
If A has B & B has A.
This is one to one relationship, but forming a circular relation.
In any of the class, use JustIgnore annotation.
class A
{
B b;
}
class B
{
#JsonIgnore
A a;
}
This applies for other relationships also like one to many.
This might be little old but you can add #JsonIgnore at class level with all properties it should ignore. e.g
#JsonIgnore("productImaes","...")
public class Product{ ...
}
Sometimes the member field may have inner reference to the same class type of itself, which could cause infinite recursion when toJson.
E.g.: you have a member field Klass a, while the class definition of that Klass is as below.
class Klass {
Klass mySibling;
public toString() {
return "something" + mySibling.whateverMethod;
}
}
Solution: refactor the member field, eliminate the inner reference.
This exception is because, your constructor field are not proper, please check your constructors properties once again in your classes, and check mapping give properly or not,
Keep the two Constructors, first is zero construction and second constructor is with fields and both should be contain the super
for me, i have tried #JsonIgnore, #JsonManagedReference/#JsonBackReference but nothing worked, till i read this Exception thrown ["hibernateLazyInitializer"] solution 1 and this Exception thrown ["hibernateLazyInitializer"] solution 2
solution 1 is to change from fetch.LAZY to fetch.EAGER, and solution 2 is using #JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}), and of course use #JsonIgnore in both solutions
Jackson works on Reflection by calling getters. I too had such a situation where I had a getter of the same Object inside its class. Jackson went into infinite recursion eating up stack by repeatedly calling its own getter. Removed getter, then it got fixed.
My Advice :
If you want to use jackson for conversion of an object, never keep getters which references the same object, like in case of singletons.