Reputation: 1703
I have a json schemas in a project and want to add build step to generate classes from them, on of these schemas contains an array of objects and strings, simplified example below:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "testSchema",
"type": "object",
"properties": {
"array": {
"type": "array",
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "object",
"properties": {
"name": {
"type": "string"
}
}
}
]
}
}
}
}
I'm using NJsonSchema to generate C# code from this schema. As a result I'm getting the following output:
//----------------------
// <auto-generated>
// Generated using the NJsonSchema v8.32.6319.16936 (http://NJsonSchema.org)
// </auto-generated>
//----------------------
namespace TestSchema
{
#pragma warning disable // Disable all warnings
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "8.32.6319.16936")]
public partial class TestSchema : System.ComponentModel.INotifyPropertyChanged
{
private System.Collections.ObjectModel.ObservableCollection<Anonymous> _array = new System.Collections.ObjectModel.ObservableCollection<Anonymous>();
[Newtonsoft.Json.JsonProperty("array", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public System.Collections.ObjectModel.ObservableCollection<Anonymous> Array
{
get { return _array; }
set
{
if (_array != value)
{
_array = value;
RaisePropertyChanged();
}
}
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
public string ToJson()
{
return Newtonsoft.Json.JsonConvert.SerializeObject(this);
}
public static TestSchema FromJson(string data)
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<TestSchema>(data);
}
protected virtual void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "8.32.6319.16936")]
public partial class Anonymous : System.ComponentModel.INotifyPropertyChanged
{
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
public string ToJson()
{
return Newtonsoft.Json.JsonConvert.SerializeObject(this);
}
public static Anonymous FromJson(string data)
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<Anonymous>(data);
}
protected virtual void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
}
As a result I have this strange Anonymous
class and if I try to deserialise a json file below I get an error: string
can't be converted into Anonymous
. To deserialise I use the following generated method:
TestSchema.FromJson
Is that possible to adjust code generation to have as a result a collection of object
instead and to get deserialised objects with correct types in it?
{
"array": [
"stringItem1",
{
"name": "complexObj1"
}
]
}
Upvotes: 1
Views: 4299
Reputation: 1703
Finally I achieved what I needed.
The idea is to pass custom CSharpTypeResolver
into CSharpGenerator
:
new CSharpGenerator(jsonSchema4, settings, new CustomCSharpTypeResolver(settings, jsonSchema4), null);
Looks like it wasn't intended by NJsonSchema
author.
In CustomCSharpTypeResolver
I override Resolve
method to add the following behaviour:
if (schema.AnyOf.Count > 0)
return "object";
As a result for simplified example I have the following model:
//----------------------
// <auto-generated>
// Generated using the NJsonSchema v8.32.6319.16936 (http://NJsonSchema.org)
// </auto-generated>
//----------------------
namespace JsonSchemaClassGenerator.TestSchema
{
#pragma warning disable // Disable all warnings
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "8.32.6319.16936")]
public partial class TestSchema : System.ComponentModel.INotifyPropertyChanged
{
private System.Collections.ObjectModel.ObservableCollection<object> _array = new System.Collections.ObjectModel.ObservableCollection<object>();
[Newtonsoft.Json.JsonProperty("array", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public System.Collections.ObjectModel.ObservableCollection<object> Array
{
get { return _array; }
set
{
if (_array != value)
{
_array = value;
RaisePropertyChanged();
}
}
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
public string ToJson()
{
return Newtonsoft.Json.JsonConvert.SerializeObject(this);
}
public static TestSchema FromJson(string data)
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<TestSchema>(data);
}
protected virtual void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "8.32.6319.16936")]
public partial class Object : System.ComponentModel.INotifyPropertyChanged
{
private string _name;
[Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string Name
{
get { return _name; }
set
{
if (_name != value)
{
_name = value;
RaisePropertyChanged();
}
}
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
public string ToJson()
{
return Newtonsoft.Json.JsonConvert.SerializeObject(this);
}
public static Object FromJson(string data)
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<Object>(data);
}
protected virtual void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
}
Deserialisation works fine. I can cast objects as I want. There is only one problem: objects are being saved as JObject
instances so I need to implement explicit
or implicit
operator to convert it into generated model.
namespace JsonSchemaClassGenerator.TestSchema
{
public partial class Object
{
public static implicit operator Object(JObject json)
{
return FromJson(json.ToString());
}
}
}
After that it will be possible to convert JObject
into generated model (Object
is not a System.Object
it just was generated with such a name):
Object a = config.Entries[1] as JObject;
It is the simplest solution I found. I think it is also possible to implement custom CSharpTypeResolver
to have something more type-safe. But not sure if I will try since for me it looks like it would be better to make NJsonSchema
more flexible first.
Upvotes: 1