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.
Related
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
I want to create an arraylist of type Adapter from a JSON. But since the JSON is not in arraylist format, I'm unable to use gson.fromJson() method.
Is there any way by which I can create a list of my custom object by parsing the following JSON?
JSON data:
"source":{"adapter-config.adapter[0].name":"testAdapter1",
"adapter-config.adapter[0].resolverName":"serviceResolver",
"adapter-config.adapter[0].parameters[0].key":"serviceId",
"adapter-config.adapter[0].parameters[0].value":"serviceIdPathInEvent",
"adapter-config.adapter[0].parameters[1].key":"appId",
"adapter-config.adapter[0].parameters[1].value":"appIdPathEvent",
"adapter-config.adapter[0].parameters[2].key":"env",
"adapter-config.adapter[0].parameters[2].value":"envPathInEvnet"}
My Adapter Object:
public class Adapter {
private String name;
private String resolverName;
private List<KeyValuePair<String, String>> attributeList;
}
Gson does not provide such functionality out of the box. However you can achieve this by manually reading the JSON data from a JsonReader, consuming the JSON property names with nextName() and then parsing them to determine which data they represent. You could either directly read from a JsonReader, or in case the shown JSON data is only an extract from a larger JSON document, you can implement a TypeAdapter for your List<Adapter>. That TypeAdapter could then either be registered with a GsonBuilder by providing new TypeToken<List<Adapter>>() {}.getType() as type, or you could annotate the field holding the List<Adapter> with #JsonAdapter.
For the actual parsing of List<Adapter>, I would recommend storing a current adapter (and its index in the list) in a local variable. Whenever you parse a JSON property name, you could then check if the index encoded in the name is equal to the index of the current adapter, then you are going to modify the existing instance, otherwise if the encoded index is equal to the index of the current adapter + 1 you create a new Adapter instance, add it to the list of adapters and reassign the current adapter variable and its index variable. Then you continue with parsing the remainder of the property name to find out which Adapter field values to set.
(In case you get stuck there, feel free to let me know in the comments and I can try to provide some concrete code; but it would probably be best if you tried it yourself first.)
I'm using the C# Elastic Nest client to retrieve the data from the Elasticsearch. I have created a POCO class named IndexModel which corresponds to the index mapping of my "testing-index" index. I get all the data from the index using this search method:
var result = client.Search<IndexModel>(s => s
.Index("testing-index")
.MatchAll());
However, I would like to be able to gather also the json data that didn't succeed to be mapped into any of the POCO properties, e.g. when the index mapping changes. I know that Nest uses Utf8Json as a Json serializer, but I couldn't find out if there is a possibility like in System.Text.Json.Serialization to add a data annotation above some dictionary that would catch all the overflow json data. Something like this?
[JsonExtensionData]
public Dictionary<string, object> ExtensionData { get; set; }
Or is there a possibility that the elastic client handles it and informs me somehow that some data didn't match any POCO properties?
There's no feature for this in the client.
The options are defining a POCO to represent the document, or using a type that can handle arbitrary JSON structures such as using JsonNetSerializer along with JObject to represent documents.
I try to realize database access decorator based on Expression types. So, I've already tried many different json serializing libraries, started from Newtonsoft Json till DataContractJsonSerializator and etc.
1) Most of serializators crash on Expression type serialization (including System.Text.Json.Serialization).
2) Newtonsoft.JsonSerializer successfully serialize Expression<Func<User, bool>> test = e => e.Id == sameUser.Id, where User is the class like:
public class User
{
public Guid Id { get; set; }
public string Fullname { get; set; }
}
and sameUser is an object of User class.
But Newtonsoft.JsonSerializer produces string of ~169-200 millions symbols. I don't know does Newtonsoft.JsonSerializer correctly deserialize this json of the other side becauseof the size. Ofcourse, I've tried to use different serializing options.
3) ServiceStack.Text.JsonSerializer successfully serialize Expression<Func<User, bool>> test = e => e.Id == sameUser.Id with normal json size (approx 2-3 thousands symbols), but on the deserialization Expression.Body always null after deserialization (and this really strange - serialized json has it well-serialized).
4) Serialize.Linq successfully passed the test.
I want to understand, what the reason of this strange behavior of main serializers like Newtonsoft, ServiceStack, Microsoft, etc?
P.S. I'ven't tested protobuf-net and MessagePack yet, I'll do this soon,but think they have the same troubles with Expression class object serialization/deserialization.
Expression has cyclical dependencies an non serializable references that is not suitable for serialization. If you want to serialize the debug string representation of an Expression do that in your code and serialize the string, don’t expect serialization libraries to attempt to serialize a non-serializable class that’s impossible to deserialize.
If you want to serialize code, send raw source code and use Roslyn or Code DOM to execute the source code received, you’ll need to validate any untrusted user code for potential security vulnerabilities or unwanted behavior before evaluating it.
In this question How can I serialize a RealmObject to JSON in Realm for Java? The realm representative said that one can serialize realm object through GSON. Can you please explain it how?
I tried this.
RealmResults<Dog> myDogs=realm.where(Dog.class).findAll();
new Gson().toJson(myDogs);
But StackOverflowError occurred.
To make GSON serialization work with Realm you will need to write a custom JsonSerializer for each object that can be serialized and register it as a TypeAdapter.
You can see an example in this gist: https://gist.github.com/cmelchior/ddac8efd018123a1e53a
You get StackOverflow becouse of Gson based on reflection but managed object (RealmObjectProxy) have no real fields and fields of parent is nulls also some of proxy fields produses recursion in field type recognition of Gson it happens in $GsonTypes class.
To serialize RealmObject you can use one of this options:
Write your own adapter for every RealmObject childs which will takes data using getters.
Call realm.copyFromRealm(realmObject) before serialisation. It will looks like new Gson().toJson(realm.copyFromRealm(realmObject))
Use library based on 2nd option RealmSupportForGson
Hope it helps
The easier way is create a List<Dog> with RLMResult<Dog>, and then serialise this List with Gson.
After two days of bug resolve, I found this simple solution:
YourRealmObject realmObj = realm.where(YourRealmObject.class).findFirst();
if(realmObj != null) {
realmObj = realm.copyFromRealm(realmObj); //detach from Realm, copy values to fields
String json = gson.toJson(realmObj);
}