Deserialize json with known and unknown fields
An even easier option to tackling this problem would be to use the JsonExtensionDataAttribute from JSON .NET
public class MyClass
{
// known field
public decimal TaxRate { get; set; }
// extra fields
[JsonExtensionData]
private IDictionary<string, JToken> _extraStuff;
}
There's a sample of this on the project blog here
UPDATE Please note this requires JSON .NET v5 release 5 and above
Deserialize Json with unknown fields / properties
You can not deserialize an undefined structure into a defined structure. Obviously this is not possible as fixed classes cannot be amended with new properties at runtime.
Anonymous objects to the help, sample from JSON.NET's documentation:
var definition = new { Name = "" };
string json1 = @"{'Name':'James'}";
var customer1 = JsonConvert.DeserializeAnonymousType(json1, definition);
Console.WriteLine(customer1.Name);
// James
string json2 = @"{'Name':'Mike'}";
var customer2 = JsonConvert.DeserializeAnonymousType(json2, definition);
Console.WriteLine(customer2.Name);
// Mike
Link to JSON.NET samples
How can I deserialize a JSON to a Java class which has known mandatory fields, but can have several unknown fields?
You can use JsonAnySetter
annotation:
class PersonDTO {
@JsonProperty("first_name")
private String firstName;
@JsonProperty("last_name")
private String lastName;
private Map<String, String> extras = new HashMap<>();
@JsonAnySetter
public void setExtras(String name, String value) {
this.extras.put(name, value);
}
// No args constructor
// Getters
// Setters
}
See also:
- JSON Jackson deserialization multiple keys into same field
- Adding a dynamic json property as java pojo for jackson
- How to use dynamic property names for a Json object
Deserialise JSON with unknown fields
Yes, you will need a custom JsonConverter
to solve this. Basically what you need to do is this:
- Define your
QualitativeValue
andQuantitativeValue
classes to have a common base class (e.g.AbstractQValue
) or interface. - In your
Parts
class, make thespecs
property aDictionary<string, AbstractQValue>
. This will handle the changing attribute names. - Create a custom
JsonConverter
to handle the instantiation of the concreteQualitativeValue
orQuantitativeValue
based on the__class__
attribute in the JSON. See this answer for an example of how to implement this. - Lastly, when you do your deserialization, be sure to pass an instance of the custom
JsonConverter
into theJsonConvert.DeserializeObject
method.
Demo
I had a little time, so I threw together a working example. Here are the class definitions for the data (I cut out most of the extraneous stuff for brevity):
public class PartsMatchResponse
{
public List<PartsMatchResult> results { get; set; }
}
public class PartsMatchResult
{
public List<Part> items { get; set; }
}
public class Part
{
public Manufacturer manufacturer { get; set; }
public string mpn { get; set; }
public Dictionary<string, AbstractQValue> specs { get; set; }
}
public class Manufacturer
{
public string name { get; set; }
}
public abstract class AbstractQValue
{
public List<string> value { get; set; }
}
public class QualitativeValue : AbstractQValue
{
}
public class QuantitativeValue : AbstractQValue
{
public string unit { get; set; }
}
Here is the custom JsonConverter
class:
public class QValueJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(AbstractQValue).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader,
Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
if (jo["__class__"].ToString() == "QuantitativeValue")
{
return jo.ToObject<QuantitativeValue>();
}
return jo.ToObject<QualitativeValue>();
}
public override void WriteJson(JsonWriter writer,
object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Here is a demo program showing how to use the converter when deserializing:
class Program
{
static void Main(string[] args)
{
// (jsonString is defined as a constant below)
PartsMatchResponse response =
JsonConvert.DeserializeObject<PartsMatchResponse>(jsonString,
new QValueJsonConverter());
foreach (Part part in response.results[0].items)
{
Console.WriteLine("manufacturer: " + part.manufacturer.name);
Console.WriteLine("mfr. part no: " + part.mpn);
foreach (KeyValuePair<string, AbstractQValue> kvp in part.specs)
{
string unit = "";
if (kvp.Value is QuantitativeValue)
unit = ((QuantitativeValue)kvp.Value).unit;
Console.WriteLine(kvp.Key + ": " +
string.Join(", ", kvp.Value.value) + " " + unit);
}
Console.WriteLine();
}
}
// Note: this is the same as the example JSON in the question, except
// I added units for some of the QuantitativeValue specs for demo purposes.
const string jsonString = @"
{
""__class__"": ""PartsMatchResponse"",
""msec"": 183,
""request"": {
""__class__"": ""PartsMatchRequest"",
""exact_only"": false,
""queries"": [
{
""__class__"": ""PartsMatchQuery"",
""brand"": null,
""limit"": 10,
""mpn"": ""ERJ8BWFR010V"",
""mpn_or_sku"": null,
""q"": """",
""reference"": null,
""seller"": null,
""sku"": null,
""start"": 0
}
]
},
""results"": [
{
""__class__"": ""PartsMatchResult"",
""error"": null,
""hits"": 1,
""items"": [
{
""__class__"": ""Part"",
""brand"": {
""__class__"": ""Brand"",
""name"": ""Panasonic - ECG"",
""uid"": ""4c528d5878c09b95""
},
""category_uids"": [
""7542b8484461ae85"",
""cd01000bfc2916c6"",
""5c6a91606d4187ad""
],
""compliance_documents"": [],
""datasheets"": null,
""external_links"": {
""__class__"": ""ExternalLinks"",
""evalkit_url"": null,
""freesample_url"": null,
""product_url"": null
},
""imagesets"": null,
""manufacturer"": {
""__class__"": ""Manufacturer"",
""name"": ""Panasonic - ECG"",
""uid"": ""c20a0700af7c11cd""
},
""mpn"": ""ERJ8BWFR010V"",
""octopart_url"": ""http://octopart.com/erj8bwfr010v-panasonic+-+ecg-7979066"",
""offers"": null,
""specs"": {
""case_package"": {
""__class__"": ""QualitativeValue"",
""attribution"": {
""__class__"": ""Attribution"",
""first_acquired"": null,
""sources"": []
},
""value"": [
""1206""
]
},
""case_package_si"": {
""__class__"": ""QualitativeValue"",
""attribution"": {
""__class__"": ""Attribution"",
""first_acquired"": null,
""sources"": []
},
""value"": [
""3216""
]
},
""lead_free_status"": {
""__class__"": ""QualitativeValue"",
""attribution"": {
""__class__"": ""Attribution"",
""first_acquired"": null,
""sources"": [
{
""__class__"": ""Source"",
""name"": ""Future Electronics"",
""uid"": ""e4032109c4f337c4""
}
]
},
""value"": [
""Lead Free""
]
},
""lifecycle_status"": {
""__class__"": ""QualitativeValue"",
""attribution"": {
""__class__"": ""Attribution"",
""first_acquired"": null,
""sources"": []
},
""value"": [
""Not Listed by Manufacturer""
]
},
""pin_count"": {
""__class__"": ""QuantitativeValue"",
""attribution"": {
""__class__"": ""Attribution"",
""first_acquired"": null,
""sources"": [
{
""__class__"": ""Source"",
""name"": ""Farnell"",
""uid"": ""58989d9272cd8b5f""
}
]
},
""max_value"": null,
""min_value"": null,
""unit"": null,
""value"": [
""2""
]
},
""power_rating"": {
""__class__"": ""QuantitativeValue"",
""attribution"": {
""__class__"": ""Attribution"",
""first_acquired"": null,
""sources"": [
{
""__class__"": ""Source"",
""name"": ""Newark"",
""uid"": ""d294179ef2900153""
}
]
},
""max_value"": null,
""min_value"": null,
""unit"": ""Watt"",
""value"": [
""0.5""
]
},
""resistance"": {
""__class__"": ""QuantitativeValue"",
""attribution"": {
""__class__"": ""Attribution"",
""first_acquired"": null,
""sources"": [
{
""__class__"": ""Source"",
""name"": ""Farnell"",
""uid"": ""58989d9272cd8b5f""
}
]
},
""max_value"": null,
""min_value"": null,
""unit"": ""Ohm"",
""value"": [
""0.01""
]
},
""resistance_tolerance"": {
""__class__"": ""QualitativeValue"",
""attribution"": {
""__class__"": ""Attribution"",
""first_acquired"": null,
""sources"": []
},
""value"": [
""\u00b11%""
]
},
""rohs_status"": {
""__class__"": ""QualitativeValue"",
""attribution"": {
""__class__"": ""Attribution"",
""first_acquired"": null,
""sources"": [
{
""__class__"": ""Source"",
""name"": ""Newark"",
""uid"": ""d294179ef2900153""
}
]
},
""value"": [
""Compliant""
]
}
},
""uid"": ""69e8a09b8cb4b62f"",
""uid_v2"": 797906654705
}
],
""reference"": null
}
]
}";
}
And finally, here is the output of the above program:
manufacturer: Panasonic - ECG
mfr. part no: ERJ8BWFR010V
case_package: 1206
case_package_si: 3216
lead_free_status: Lead Free
lifecycle_status: Not Listed by Manufacturer
pin_count: 2
power_rating: 0.5 Watt
resistance: 0.01 Ohm
resistance_tolerance: ±1%
rohs_status: Compliant
spray json in scala: deserializing json with unknown fields without losing them
In order to do that, you need to write your own formatter for PersonalDataFormat
:
case class Person(first: String, last: String)
case class Address(line: String, city: String)
case class Contact(phone: String, address: Address)
case class PersonalData(person: Person, contact: Contact, extra: Map[String, JsValue])
case class Entity(personalData: PersonalData)
implicit val personFormat = jsonFormat2(Person)
implicit val addressFormat = jsonFormat2(Address)
implicit val contactFormat = jsonFormat2(Contact)
implicit object PersonalDataFormat extends RootJsonFormat[PersonalData] {
override def read(json: JsValue): PersonalData = {
val fields = json.asJsObject.fields
val person = fields.get("person").map(_.convertTo[Person]).getOrElse(???) // Do error handling instead of ???
val contact = fields.get("contact").map(_.convertTo[Contact]).getOrElse(???) // Do error handling instead of ???
PersonalData(person, contact, fields - "person" - "contact")
}
override def write(personalData: PersonalData): JsValue = {
JsObject(personalData.extra ++ ("person" -> personalData.person.toJson, "contact" -> personalData.contact.toJson))
}
}
implicit val entityFormat = jsonFormat1(Entity)
val jsonResult = jsonString.parseJson.convertTo[Entity]
The result is:
Entity(PersonalData(Person(first_name,last_name),Contact(1111111,Address(123 Main St,New York)),Map(xx -> "yy", zz -> {"aa":"aa","bb":"bb","cc":{}})))
(Assuming the json is not exactly the json above, but a valid similar one)
Code run in Scastie
Parse JSON with mixed known/unknown fields in JAVA
You can use POJO with @JsonAnySetter
method annotation. And you can actually even perform computations/optimisations in this method if you need them.
public class Simple {
private String A;
private String B;
private Map other = new HashMap<String,Object>();
// "any getter" needed for serialization
@JsonAnyGetter
public Map any() {
return other;
}
// "any setter" needed for deserialization
@JsonAnySetter
public void set(String name, Object value) {
other.put(name, value);
}
// getter and setter for A and B
}
Deserializing JSON with unknown fields
the JSON recieved seems to be a dictionnary..
did you try to deseserialize as a Dictionnary<string,Album>
?
Related Topics
Windows Like Services Development in Linux Using Mono
Why Doesn't .Net/C# Optimize for Tail-Call Recursion
In a "Using" Block Is a SQLconnection Closed on Return or Exception
Cannot Delete Directory with Directory.Delete(Path, True)
Allow Windows Service to Interact with Desktop
Entity Framework Stored Procedure Table Value Parameter
Make First Letter of a String Upper Case (With Maximum Performance)
How to Turn an Int into an Array of Ints of Each Digit
How to Bind a Tabcontrol to a Collection of Viewmodels
Difference Between Observablecollection and Bindinglist
Can You Develop Linux Applications with Xamarin
Why Are C# 3.0 Object Initializer Constructor Parentheses Optional
Compiling/Executing a C# Source File in Command Prompt
Entering Keys Manually with Entity Framework
Authenticate and Request a User's Timeline with Twitter API 1.1 Oauth
Simplest Way to Do a Fire and Forget Method in C#
How to Access a Variable from Another Script in Another Gameobject Through Getcomponent