Unity JSONUtility to JSON list of base classes - json

I have a BaseClass and bunch of derived classes.
I also have List<BaseClass> that contains objects from those derived classes.
When I do JSONUtility.ToJson(List<BaseClass>) I get only properties of BaseClass and not derived classes.
And well... I guess it is logical, but can't I force it to use derived class if there's a one or JSONUtility isn't capable of it? So I need to write custom logic for that?
Thanks!

Very probably JSONUtility.ToJson(List<BaseClass>) gets the elements you need with reflection, so the object returned is based on the incoming type.
I would try to obtain the jsons one by one and combine them in the logic, pre casting each of the types. Not tested nor debugged, just an starting point idea to move on:
string jsons;
foreach (var baseClass in baseClassList) {
Type specificType = baseClass.GetType();
string jsonString = JsonUtility.ToJson((specificType)baseClass)
jsons = "[" + string.Join(",", jsonstring) + "]";
}

I faced the same issue, to be honest JsonUtility is not good option for working with List.
My recommendations:
Use array instead of list with this helper class
or Newtonsoft Json Unity Package

I also needed JSON serialization, to call a REST json API, and I suggest to avoid JSONUtility.
It doesn't handle lists or dictionaries, as you saw.
Also it cannot serialize properties defined with { get; set; }, only fields, which is not blocking but not very convenient.
I agree with the recommendation above, just use Newtonsoft. It can serialize anything, and you will also benefit of the Serialization Settings (you can for example setup the contract resolver to convert all property names to snake_case...). See https://www.newtonsoft.com/json/help/html/SerializationSettings.htm

Related

Typescript: undefined calculated property after deserializing in JSON

I'm new to Typescript and I encountered a JSON deserializing problem.
Consider this class:
class Product {
public id!: number;
public get calculatedProperty() : string {
return "Test";
};
};
As you can see calculatedProperty is a runtime calculated property.
Also, consider that I deserialize a JSON string into my object in this way:
var jsonData = '{ "id": 2 }';
let deserialized = JSON.parse(jsonData) as Product;
The problem comes now:
This call console.log(deserialized.id); returns correctly 1.
This call console.log(deserialized.calculatedProperty); returns undefined!
I really don't understand way. It seems that as Product doesn't really create a Product object, because If I directly invoke the constructor, new Product, the calculated property exists.
What am I doing wrong with the JSON deserialization?
Thanks!
TypeScript's job is only to perform type checking during development and make sure we don't make careless mistakes. At the end of the day, all it does is just compiling the script and transform it into good old JavaScript. Therefore, any TypeScript syntax are not applied in runtime.
In other words, type assertions are removed in runtime.
There are also several warnings in the documentation about this:
Like a type annotation, type assertions are removed by the compiler and won’t affect the runtime behavior of your code.
Reminder: Because type assertions are removed at compile-time, there is no runtime checking associated with a type assertion. There won’t be an exception or null generated if the type assertion is wrong.
Besides, the as keyword does not instantiate a constructor. It merely provides a type information (which will be removed during compile-time). The only way we can instantiate a constructor and access its instance properties/methods is through the new keyword.
The JSON.parse method isn't really for converting json into a class rather than an object.
To solve your issue you could potentially convert the json into an object like this:
let deserializedObject = JSON.parse(jsonData) as Object;
and after that you could assign the object to a class like that:
let deserialized = Object.assign(new Product(), deserializedObject);
Note that I have not tested this yet, but it should work.
Also this is fine for simple objects, but not for objects with complex hierarchy.
Look into class-transformer for more information. https://github.com/typestack/class-transformer

Serialize/deserialize a Dictionary with a comma-separated entry

I am developing a ASP.NET Core 3.1 website and I have data in a Dictionary<string, object> that I want to Serialize/Deserialize using Microsoft System.Text.Json (I am new to Json serialize/deserialize in fact). The data comes from a PostgreSQL DB query and one of the returned values is a comma-separated list of integers (converted to string) that results from the STRING_AGG function. The image below shows one of the entries of the Dictionary:
I serialize it using the following code. Please note that I have tried both Microsoft System.Text.Json and Newtonsoft.
jsonResult = Newtonsoft.Json.JsonConvert.SerializeObject(result);
//jsonResult = JsonSerializer.Serialize(result);
The data in the Dictionary should be deserialized according to the following class structure:
I use the following code:
//IEnumerable<SeccGralContenidoViewModel> seccGralContenido = JsonSerializer.Deserialize<IEnumerable<SeccGralContenidoViewModel>>(_seccGralContenidoRepository.Read());
IEnumerable<SeccGralContenidoViewModel> seccGralContenido = Newtonsoft.Json.JsonConvert.DeserializeObject <IEnumerable<SeccGralContenidoViewModel>>(_seccGralContenidoRepository.Read());
However, an exception is thrown when deserializing no matter if I use Newtonsoft or System.Text.Json:
I am originally using System.Text.Json namespace but I also tried using Newtonsoft. After analyzing a bit deeper, I see that the problem could be the way in which data is saved to the Dictionary but I have not found a workaround.
If you don't want to write a custom converter then the simplest solution is to introduce another property:
public string CategoriasContenidolds {get; set;}
private static char delimiter = ',';
[JsonIgnore]
public string[] CategoriasContenidolds_Collection
{
get => CategoriasContenidolds.Split(delimiter).Select(item => item.Trim()).ToArray();
set => CategoriasContenidolds = string.Join(delimiter, value);
}
The serializer will use the CategoriasContenidolds property during serialization and deserialization
You should use CategoriasContenidolds_Collection (or name whatever you want) in your business logic
By explicitly marking this property with JsonIgnore the serializer will ignore that
I could solve my issue by directly getting JSON formatted results from queries. PostgreSQL does an excellent job. This way I also avoid performing a 2-step process: first, getting the query result; second, serializing to JSON.

Custom augmentation of serialization/deserialization of types that have class annotation

I'd like to have a bunch of classes that structures something like this:
#Special("SpecialThing")
data class MyThing(
val myVal: String
)
The serialized format of this specific instance is this would be:
{
"special": "SpecialThing",
"params": {
"myVal": "myValValue"
}
}
I would like to be able to serialize to/from these kinds of annotated types.
A few of the things I was hoping to do:
Keep Jackson annotations out of these classes themselves (maybe using mixins?). I'd to keep the Jackson specific serialization separate from these types.
Avoid putting the "SpecialThing" as a field/property
Deserialize into the correct type by use of the "special" value
I might not be able to accomplish all of these at once, but I'm having difficulty finding the right pieces of Jackson to use to accomplish my goal. There are a few built-ins which do close to what I want (like JsonUnwrapped)
I could maybe use #JsonTypeInfo and polymorphic inheritance in some way, but I'm hoping there is a cleaner and more direct approach.
How do I handle serialization/deserialization of these kinds of types that need "wrapping"?
You can't quite do it because you have a your own fancy annotation that jackson just doesn't care about, but you could do the other stuff with #JsonWrapped and mixin.
You will need to write a custom JSON Serializer to handle your annotation
which is really easy.

How to modify spring/jackson JSON deserialisation

I'm trying to figure out how to adjust the way spring/jackson convert a JSON string (stored in a file) into various POJOs. For example, if I have this JSON:
{
"rates":{
"EURUSD":5.4321,
"USDHKD":1.2345
}
}
I actually want to get an instance of my 'Rates' class. Inside that I want a List containing each individual rate.
In my spring config file I created this entry:
#Bean
public ObjectMapper jsonObjectMapper() {
return new MappingJackson2HttpMessageConverter().getObjectMapper();
}
And in my service class I did this:
#Autowired
ObjectMapper jsonObjectMapper;
public Rates currentRates() {
Resource resource = this.ctx.getResource("classpath:stub/data/rates/Rates-01.json");
return this.jsonObjectMapper.readValue(resource.getURL(), Rates.class);
}
The problem is that I am trying to figure out how to take the Map containing the currencies as a single key, break those currencies in two and then create a RateEntry object containing the two currencies and the rate, before populating a list in the Rates class.
I've been looking at Spring's Conversion Service with the idea to define a converter that maps the Map to a list. i.e. this signature: Converter<Map<String, BigDecimal>, List<Rate>>. However this is based on the assumption that the JSON is first converted to standard types before the conversion service is called. An assumption I now think is incorrect.
So I'm now trying to figure out if I need to register some sort of custom ObjectMapper to handle reading directly from the JSON String data. But that sounds like over kill as I only want to adjust part of the object graph, and let the default converters handle the rest.
Any pointers appreciated. Thanks.
Ok, Jackson tries to stay away from structural transformations (since it's a quick-sand pit with unlimited number of general permutations). But it might be possible to use some existing features to do what you want.
First: to use Object key to indicate type, you will probably want to enable polymorphic type handling with "as object wrapper" inclusion.
So add something like:
#JsonTypeInfo(as=Include.WRAPPER_OBJECT)
for your Rates class declaration.
As to converting values into list; this might work by defining "any-setter" (see http://www.cowtowncoder.com/blog/archives/2011/07/entry_458.html), something like:
#JsonAnySetter
public void set(String key, Double value) // or "Object value")
{
list.add(new Rate(key, value));
}
I hope this helps.

one Jackson deserializer for multiple types (config by annotation)

I'm trying to change the (de)serialization of a list in one of my classes.
the objects in the list shall be serialised as int (their jpa id) and deserialised accordingly. serialization is simple.
for the deserialization i have a class that can translate the id into the object if id and class are known.
How do i get the necessary class from jackson? all default jackson serialisers have a constructor like this: protected StdDeserialiser(Class<?> vc) so the information is present somewhere.
is there a way to access it during deserialisation?
or before the deserialiser is constructed by jackson?
or inside the HandlerInstantiator?
I only want to overwrite the default deseriliser for certain references so i can't just write a provider or a custom module.
I made it work from inside the deserializer with the help of the ContextDeserializer interface as this supplies the deserializer with the target property.
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException {
Class<?> vc = null;
if (property.getType().isCollectionLikeType()) {
vc = property.getType().getContentType().getRawClass();
} else {
vc = property.getType().getRawClass();
}
return new ResourcePathDeserializer(vc, converter);
}
This solution is not perfect as I only get the raw class of the return type or the generic (which might be a parent class or an interface) but that is enough for my requirements.
It would be better if I could access the "real" class that was resolved by Jackson, but for me this works.
First of all, there is nothing fancy about writing a Module: it is just a way for plugging things in, like custom (de)serializers. So no need to avoid that. And you will most like need to write a module to do what you want.
In general it is not a good idea to try to create "universal" serializers or deserializers, and it will probably run into problem. But it depends on what exactly you are trying to do.
Type information will either be:
Implicit from context: you are writing a (de)serializer for type T, and register it for it, so that's your type
Passed by Jackson when (de)serializer is being constructed, via Module interface: modules are asked if they happen to have a (de)serializer for type T. SimpleModule will only use basic Class-to-impl mapping (that's where "simple" comes from); but full custom Module has access to incoming type.
But I don't know if above will work for your use case. Type information must be available from static type (declared content type for the list).