Serialize List of subclasses not working in JsonUtility in Unity - json

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

Related

Angular casting http get response but not nested property

I am returning a list of products of type ListProd in my Spring Boot controller, and such object has a nested property of type List<Product> ... something like this:
public class Product implements Serializable {
int codProdct;
String dsc;
public Product(){};
// plus getters and setters (omitted for simplicity)
}
public class ListProd implements Serializable {
int codList;
List<Product> products;
public ListProd(){};
// also here getters and setters
}
and in my angular project I have the next analogoust entities:
export class Product {
public codProduct:number;
public dsc:string;
constructor(){
codProduct=null; //just for completness
dsc='';
}
}
export class ListProd {
public codList:number;
public products:Product[];
constructor(){
this.codList=null; //just for completness
this.products=null;
}
}
I'm sending a ListProd object through my Spring controller and Angular gets such an object correctly and assigns the type also correctly:
return this.http.get<ListProd>(this.apiUrl + "/getListProds", httpOptions);
but ... it is only casting correctly the parent object, when I check the type of the 'products' object (which is recived correctly, only untyped) y get type: Object
I tried to make it a Products[] in my ListProd class in java, but i get the same result. I don't know much about the 'magic' Angular does to assign those types properly, am I missing something important here? Is there a chance to force the casting on the Angular side?
Thanks in advance.
Well, if ListProd is supposed to hold array of Product[] there is a typo here.
public products:Product[];
Not knowing full extent why you use class over an interface I would advise you also to go over this. Maybe there is a reason but for being able to strong type simple interface would be better. https://www.javatpoint.com/typescript-class-vs-interface

newtonsoft json deserialize with subclassed collection

I have a series of classes MyConcreteClass : MyBaseClass and a series of collection classes MyConcreteCollection : MyBaseCollection.
Where the fun part is that
public abstract class MyBaseCollection
{
public List<MyBaseClass> MyItems :get; set;}
}
It serializes fine, and the objects inside MyItems do show up as the right items (lookin in the JSON with { TypeNameHandling = TypeNameHandling.All }; set
My problem is when I go to deserialize - obviously we can't create an object of List<MyBaseClass> (It is abstract) - I need to deserialize to List<MyConcreteClass>
The good news? The List<MyConcreteClass> is ALWAYS the same for each type of MyConcreteCollection, aka
MyFirstCollectionType: MyBaseCollection the MyItems will always be of type FistConcreteType : MyBaseClass and MySecondCollectionType: MyBaseCollection will always be of type SecondConcreteType : MyBaseClass
I THINK it might be just a custom Converter, but I just don't get it.

Unexpected duplicate key error using #JsonTypeInfo property

I have a simple hierarchy of data objects, which have to be converted to JSON format. Like this:
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "documentType")
#JsonSubTypes({#Type(TranscriptionDocument.class), #Type(ArchiveDocument.class)})
public class Document{
private String documentType;
//other fields, getters/setters
}
#JsonTypeName("ARCHIVE")
public class ArchiveDocument extends Document { ... }
#JsonTypeName("TRANSCRIPTIONS")
public class TranscriptionDocument extends Document { ... }
Upon JSON parsing I encounter errors like this one:
Unexpected duplicate key:documentType at position 339. , because in the generated JSON there are actually two documentType fields.
What should be changed to make JsonTypeName value appear in documentType field, without an error (eg replacing the other value)?
Jackson version is 2.2
Your code doesn't show it, but I bet you have a getter in your Document class for the documentType property. You should annotate this getter with #JsonIgnore like so:
#JsonIgnore
public String getDocumentType() {
return documentType;
}
There is an implicit documentType property associated with each subclass, so having the same property in the parent class causes it to be serialized twice.
Another option would be to remove the getter altogether, but I assume you might need it for some business logic, so the #JsonIgnore annotation might be the best option.

Is #XmlElement necessary for Jaxb

My question is, whether it is necessary to add #XmlElement before each element in your pojo to be picked up by jaxb, when making a JSON response. I am using jersey-json 1.17 . The reason I ask this is because, the example given on Jersey site does not use the annotation.
I get an out put as {}, but when I add #XmlElement before the attributes, I get the expected JSON output. Am I doing something wrong, because of which my JSON string is empty ?
My code :
The vertices list is populated in the constructor.
This produces the wrong output of {}
#XmlRootElement
public class SquareModel {
List<Float> vertices = new ArrayList<Float>();
....
}
Whereas this produces the a correct JSON string :
#XmlRootElement
public class SquareModel {
#XmlElement(name="vertices")
List<Float> vertices = new ArrayList<Float>();
....
}
My resource class which returns the JSON
#GET
#Produces(MediaType.APPLICATION_JSON)
public SquareModel getJsonString() {
return new SquareModel();
}
Thanks :)
No, by default a JAXB (JSR-22#) implementation will treat all public fields and properties (get/set combinations) as mapped (not requiring the #XmlElement annotation).
http://blog.bdoughan.com/2012/07/jaxb-no-annotations-required.html
If you wish to annotate a field I would recommend annotating your class with #XmlAccessorType(XmlAccessType.FIELD)
http://blog.bdoughan.com/2011/06/using-jaxbs-xmlaccessortype-to.html
According to this http://jersey.java.net/nonav/documentation/latest/json.html#json.jaxb.approach.section
You should have this annotation (I'm also using it in my code, even though it XML oriented, but it gives me cool JSON also)
Taking this approach will save you a lot of time, if you want to
easily produce/consume both JSON and XML data format. Because even
then you will still be able to use a unified Java model. Another
advantage is simplicity of working with such a model, as JAXB
leverages annotated POJOs and these could be handled as simple Java
beans.
A disadvantage of JAXB based approach could be if you need to work
with a very specific JSON format. Then it could be difficult to find a
proper way to get such a format produced and consumed. This is a
reason why a lot of configuration options are provided, so that you
can control how things get serialized out and deserialized back.
Following is a very simple example of how a JAXB bean could look like.
Example 5.3. Simple JAXB bean implementation
#XmlRootElement
public class MyJaxbBean {
public String name;
public int age;
public MyJaxbBean() {} // JAXB needs this
public MyJaxbBean(String name, int age) {
this.name = name;
this.age = age;
}
}

Jackson 1.9.0: JsonTypeInfo for abstract class not working with Lists

Using this abstract class:
#JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "type")
#JsonSubTypes({ #JsonSubTypes.Type(value = PostingTaskInstanceDto.class, name = "TI") })
public abstract class BasePostingDto {}
and this inherited class:
public class PostingTaskInstanceDto extends BasePostingDto {}
I get correct serialization for a single object. This works, using Spring-MVC:
#RequestMapping("/{id}")
#ResponseBody
public BasePostingDto findById(#PathVariable("id") Long id) {
return createDto(postingService.findById(id));
}
But if I retrieve a List of BasePostingDto from the remote controller, the type property is missing:
#RequestMapping("/by-user/all")
#ResponseBody
public List<BasePostingDto> findByUser() {
return createDtoList(postingService.findByUser(AuthUtils.getUser()));
}
Why is this and how can I force the type property?
Update: the type property is also included if I change List<BasePostingDto> to BasePostingDto[], however I would prefer to go with the List.
It sounds like the framework you are using (and which uses Jackson under the hood) is not passing full generics-aware type information.
I don't know how that can be fixed (it is problem with integration by framework, and not something Jackson can address), but the usual work around is for you to use sub-class of List:
public class PostingDtoList extends List<BasePostingDto> { }
and use that in signature, instead of generic type. This solves the issue because then the generic type signature is retained (since it is stored in super type declaration, and accessible via type-erased PostingDtoList class!).
In generally I think it is best to avoid using generic List and Map types as root type (and instead use POJO); partly because of problems issued (there are bigger problems when using XML for example). But it can be made to work if need be.