diff --git a/Assets/VRM/UniGLTF/Editor/UniGLTFTests.cs b/Assets/VRM/UniGLTF/Editor/UniGLTFTests.cs index 8fea2ae6d..0b97c7620 100644 --- a/Assets/VRM/UniGLTF/Editor/UniGLTFTests.cs +++ b/Assets/VRM/UniGLTF/Editor/UniGLTFTests.cs @@ -150,7 +150,7 @@ namespace UniGLTF [Test] public void MeshTest() { - var mesh = new glTFMesh("mesh") + var model = new glTFMesh("mesh") { primitives = new List { @@ -164,25 +164,22 @@ namespace UniGLTF }, }; - var f = new JsonFormatter(); - f.Serialize(mesh); - - var json = new Utf8String(f.GetStoreBytes()).ToString(); - Assert.AreEqual(@"{""name"":""mesh"",""primitives"":[{""mode"":0,""attributes"":{""POSITION"":0},""material"":0,""extensions"":{}}]}", json); + var json = model.ToJson(); + Assert.AreEqual(@"{""name"":""mesh"",""primitives"":[{""mode"":0,""indices"":-1,""attributes"":{""POSITION"":0},""material"":0}]}", json); Debug.Log(json); var c = new JsonSchemaValidationContext("") { EnableDiagnosisForNotRequiredFields = true, }; - var json2 = JsonSchema.FromType().Serialize(mesh, c); - Assert.AreEqual(json, json2); + var json2 = JsonSchema.FromType().Serialize(model, c); + Assert.AreEqual(@"{""name"":""mesh"",""primitives"":[{""mode"":0,""attributes"":{""POSITION"":0},""material"":0,""extensions"":{}}]}", json2); } [Test] public void PrimitiveTest() { - var prim = new glTFPrimitives + var model = new glTFPrimitives { attributes = new glTFAttributes { @@ -197,33 +194,27 @@ namespace UniGLTF } }; - var f = new JsonFormatter(); - f.Serialize(prim); - - var json = new Utf8String(f.GetStoreBytes()).ToString(); - Assert.AreEqual(@"{""mode"":0,""attributes"":{""POSITION"":0},""material"":0,""extras"":{""targetNames"":[""aaa""]},""extensions"":{}}", json); + var json = model.ToJson(); + Assert.AreEqual(@"{""mode"":0,""indices"":-1,""attributes"":{""POSITION"":0},""material"":0,""extras"":{""targetNames"":[""aaa""]}}", json); Debug.Log(json); var c = new JsonSchemaValidationContext("") { EnableDiagnosisForNotRequiredFields = true, }; - var json2 = JsonSchema.FromType().Serialize(prim, c); - Assert.AreEqual(json, json2); + var json2 = JsonSchema.FromType().Serialize(model, c); + Assert.AreEqual(@"{""mode"":0,""attributes"":{""POSITION"":0},""material"":0,""extras"":{""targetNames"":[""aaa""]},""extensions"":{}}", json2); } [Test] public void AttributesTest() { - var attrs = new glTFAttributes + var model = new glTFAttributes { POSITION = 0, }; - var f = new JsonFormatter(); - f.Serialize(attrs); - - var json = new Utf8String(f.GetStoreBytes()).ToString(); + var json = model.ToJson(); Assert.AreEqual(@"{""POSITION"":0}", json); Debug.Log(json); @@ -231,22 +222,19 @@ namespace UniGLTF { EnableDiagnosisForNotRequiredFields = true, }; - var json2 = JsonSchema.FromType().Serialize(attrs, c); + var json2 = JsonSchema.FromType().Serialize(model, c); Assert.AreEqual(json, json2); } [Test] public void TextureInfoTest() { - var texi = new glTFMaterialBaseColorTextureInfo() + var model = new glTFMaterialBaseColorTextureInfo() { index = 1, }; - var f = new JsonFormatter(); - f.Serialize(texi); - - var json = new Utf8String(f.GetStoreBytes()).ToString(); + var json = model.ToJson(); Assert.AreEqual(@"{""index"":1,""texCoord"":0}", json); Debug.Log(json); @@ -254,21 +242,21 @@ namespace UniGLTF { EnableDiagnosisForNotRequiredFields = true, }; - var json2 = JsonSchema.FromType().Serialize(texi, c); + var json2 = JsonSchema.FromType().Serialize(model, c); Assert.AreEqual(json, json2); } [Test] public void TextureInfoTestError() { - var texi = new glTFMaterialBaseColorTextureInfo(); + var model = new glTFMaterialBaseColorTextureInfo(); var c = new JsonSchemaValidationContext("") { EnableDiagnosisForNotRequiredFields = true, }; var ex = Assert.Throws( - () => JsonSchema.FromType().Serialize(texi, c) + () => JsonSchema.FromType().Serialize(model, c) ); Assert.AreEqual("[index.String] minimum: ! -1>=0", ex.Message); } @@ -276,25 +264,40 @@ namespace UniGLTF [Test] public void MaterialTest() { - var texi = new glTFMaterial() + var model = new glTFMaterial() { name = "a", emissiveFactor = new float[] { 0.5f, 0.5f, 0.5f }, }; - var f = new JsonFormatter(); - f.Serialize(texi); - - var json = new Utf8String(f.GetStoreBytes()).ToString(); - Assert.AreEqual(@"{""name"":""a"",""emissiveFactor"":[0.5,0.5,0.5],""alphaCutoff"":0.5,""doubleSided"":false}", json); + var json = model.ToJson(); + Assert.AreEqual(@"{""name"":""a"",""emissiveFactor"":[0.5,0.5,0.5],""doubleSided"":false}", json); Debug.Log(json); var c = new JsonSchemaValidationContext("") { EnableDiagnosisForNotRequiredFields = true, }; - var json2 = JsonSchema.FromType().Serialize(texi, c); - Assert.AreEqual(json, json2); + var json2 = JsonSchema.FromType().Serialize(model, c); + Assert.AreEqual(@"{""name"":""a"",""emissiveFactor"":[0.5,0.5,0.5],""doubleSided"":false}", json2); + } + + [Test] + public void MaterialAlphaTest() + { + var model = new glTFMaterial() + { + name = "a", + emissiveFactor = new float[] { 0.5f, 0.5f, 0.5f }, + alphaMode = "MASK", + }; + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var json = JsonSchema.FromType().Serialize(model, c); + Assert.AreEqual(@"{""name"":""a"",""emissiveFactor"":[0.5,0.5,0.5],""alphaMode"":""MASK"",""alphaCutoff"":0.5,""doubleSided"":false}", json); } [Test] @@ -376,7 +379,7 @@ namespace UniGLTF public void MaterialTestError() { - var texi = new glTFMaterial() + var model = new glTFMaterial() { name = "b", emissiveFactor = new float[] { 1.5f, 0.5f, 0.5f }, @@ -387,7 +390,7 @@ namespace UniGLTF EnableDiagnosisForNotRequiredFields = true, }; var ex = Assert.Throws( - () => JsonSchema.FromType().Serialize(texi, c) + () => JsonSchema.FromType().Serialize(model, c) ); Assert.AreEqual("[emissiveFactor.String] maximum: ! 1.5<=1", ex.Message); } @@ -395,32 +398,48 @@ namespace UniGLTF [Test] public void NodeTest() { - var texi = new glTFNode() + var model = new glTFNode() { name = "a", skin = 0, camera = -1, }; - var f = new JsonFormatter(); - f.Serialize(texi); - - var json = new Utf8String(f.GetStoreBytes()).ToString(); - Assert.AreEqual(@"{""name"":""a"",""skin"":0,""extras"":{}}", json); + var json = model.ToJson(); + Assert.AreEqual(@"{""name"":""a"",""skin"":0}", json); Debug.Log(json); var c = new JsonSchemaValidationContext("") { EnableDiagnosisForNotRequiredFields = true, }; - var json2 = JsonSchema.FromType().Serialize(texi, c); - Assert.AreEqual(json, json2); + var json2 = JsonSchema.FromType().Serialize(model, c); + Assert.AreEqual(@"{""name"":""a"",""extras"":{}}", json2); + } + + [Test] + public void NodeMeshTest() + { + var model = new glTFNode() + { + name = "a", + mesh = 2, + skin = 0, + camera = -1, + }; + + var c = new JsonSchemaValidationContext("") + { + EnableDiagnosisForNotRequiredFields = true, + }; + var json = JsonSchema.FromType().Serialize(model, c); + Assert.AreEqual(@"{""name"":""a"",""mesh"":2,""skin"":0,""extras"":{}}", json); } [Test] public void NodeTestError() { - var texi = new glTFNode() + var model = new glTFNode() { name = "a", camera = -2, @@ -431,7 +450,7 @@ namespace UniGLTF EnableDiagnosisForNotRequiredFields = true, }; var ex = Assert.Throws( - () => JsonSchema.FromType().Serialize(texi, c) + () => JsonSchema.FromType().Serialize(model, c) ); Assert.AreEqual("[camera.String] minimum: ! -2>=0", ex.Message); } @@ -439,56 +458,50 @@ namespace UniGLTF [Test] public void SkinTest() { - var texi = new glTFSkin() + var model = new glTFSkin() { name = "b", joints = new int[] {1}, }; - var f = new JsonFormatter(); - f.Serialize(texi); - - var json = new Utf8String(f.GetStoreBytes()).ToString(); - Assert.AreEqual(@"{""joints"":[1],""name"":""b""}", json); + var json = model.ToJson(); + Assert.AreEqual(@"{""inverseBindMatrices"":-1,""joints"":[1]}", json); Debug.Log(json); var c = new JsonSchemaValidationContext("") { EnableDiagnosisForNotRequiredFields = true, }; - var json2 = JsonSchema.FromType().Serialize(texi, c); - Assert.AreEqual(json, json2); + var json2 = JsonSchema.FromType().Serialize(model, c); + Assert.AreEqual(@"{""joints"":[1],""name"":""b""}", json2); } [Test] public void SkinTestEmptyName() { - var texi = new glTFSkin() + var model = new glTFSkin() { name = "", joints = new int[] {1}, }; - var f = new JsonFormatter(); - f.Serialize(texi); - - var json = new Utf8String(f.GetStoreBytes()).ToString(); + var json = model.ToJson(); // "name" = "", not excluded - Assert.AreEqual(@"{""joints"":[1],""name"":""""}", json); + Assert.AreEqual(@"{""inverseBindMatrices"":-1,""joints"":[1]}", json); Debug.Log(json); var c = new JsonSchemaValidationContext("") { EnableDiagnosisForNotRequiredFields = true, }; - var json2 = JsonSchema.FromType().Serialize(texi, c); - Assert.AreEqual(json, json2); + var json2 = JsonSchema.FromType().Serialize(model, c); + Assert.AreEqual(@"{""joints"":[1],""name"":""""}", json2); } [Test] public void SkinTestErrorNull() { - var texi = new glTFSkin() + var model = new glTFSkin() { name = "b", joints = null, @@ -499,7 +512,7 @@ namespace UniGLTF EnableDiagnosisForNotRequiredFields = true, }; var ex = Assert.Throws( - () => JsonSchema.FromType().Serialize(texi, c) + () => JsonSchema.FromType().Serialize(model, c) ); Assert.AreEqual("[joints.String] null", ex.Message); } @@ -507,7 +520,7 @@ namespace UniGLTF [Test] public void SkinTestError() { - var texi = new glTFSkin() + var model = new glTFSkin() { name = "b", joints = new int[] {}, @@ -518,7 +531,7 @@ namespace UniGLTF EnableDiagnosisForNotRequiredFields = true, }; var ex = Assert.Throws( - () => JsonSchema.FromType().Serialize(texi, c) + () => JsonSchema.FromType().Serialize(model, c) ); Assert.AreEqual("[joints.String] minItems", ex.Message); } diff --git a/Assets/VRM/UniJSON/Editor/Tests/Json/SerializeWithSchemaTests.cs b/Assets/VRM/UniJSON/Editor/Tests/Json/SerializeWithSchemaTests.cs index e5aacd5cb..d4bbcf99e 100644 --- a/Assets/VRM/UniJSON/Editor/Tests/Json/SerializeWithSchemaTests.cs +++ b/Assets/VRM/UniJSON/Editor/Tests/Json/SerializeWithSchemaTests.cs @@ -10,7 +10,7 @@ namespace UniJSON [JsonSchema(Minimum = 0)] public int X; - [JsonSchema(Minimum = 10)] // Not required, thus ignored when the value violates the constraints + [JsonSchema(Minimum = 10, ExplicitIgnorableValue = 0)] // Not required, thus ignored when the value violates the constraints public int Y; } @@ -77,5 +77,51 @@ namespace UniJSON Assert.AreEqual(expected, actual); } + + public class HasDepsTest + { + [JsonSchema(Minimum = 0, ExplicitIgnorableValue = -1)] + public int X; + + [JsonSchema(Dependencies = new string[] {"X"})] + public int Y; + } + + [Test] + public void TestHasDeps() + { + var obj = new HasDepsTest(); + + var s = JsonSchema.FromType(); + { + var c = new JsonSchemaValidationContext(obj); + Assert.Null(s.Validator.Validate(c, s)); + } + var actual = s.Serialize(obj); + + var expected = @"{""X"":0,""Y"":0}"; + + Assert.AreEqual(expected, actual); + } + + [Test] + public void TestHasDepsHasViolation() + { + var obj = new HasDepsTest() + { + X = -1, + }; + + var s = JsonSchema.FromType(); + { + var c = new JsonSchemaValidationContext(obj); + Assert.Null(s.Validator.Validate(c, s)); + } + var actual = s.Serialize(obj); + + var expected = @"{}"; + + Assert.AreEqual(expected, actual); + } } } diff --git a/Assets/VRM/UniJSON/Editor/Tests/Json/ValidatorTests.cs b/Assets/VRM/UniJSON/Editor/Tests/Json/ValidatorTests.cs index 3a071c619..b08eba4c9 100644 --- a/Assets/VRM/UniJSON/Editor/Tests/Json/ValidatorTests.cs +++ b/Assets/VRM/UniJSON/Editor/Tests/Json/ValidatorTests.cs @@ -354,7 +354,7 @@ namespace UniJSON var s = JsonSchema.FromType(); - Assert.Null(s.Validator.Validate(c, new HasArrayOBject { xs = new float[] {} })); + Assert.Null(s.Validator.Validate(c, new HasArrayOBject { xs = new float[] { } })); Assert.Null(s.Validator.Validate(c, new HasArrayOBject { xs = new float[] { 0.5f } })); Assert.NotNull(s.Validator.Validate(c, new HasArrayOBject { xs = new float[] { 1.5f } })); @@ -379,12 +379,39 @@ namespace UniJSON var s = JsonSchema.FromType(); - Assert.Null(s.Validator.Validate(c, new HasListObject { xs = new List {} })); + Assert.Null(s.Validator.Validate(c, new HasListObject { xs = new List { } })); Assert.Null(s.Validator.Validate(c, new HasListObject { xs = new List { 0.5f } })); Assert.NotNull(s.Validator.Validate(c, new HasListObject { xs = new List { 1.5f } })); Assert.True(c.IsEmpty()); } } + + class HasRequiredListObject + { + [JsonSchema(Required = true, MinItems = 1)] + [ItemJsonSchema(Minimum = 0)] + public int[] xs; + } + + [Test] + public void HasRequiredListObjecttValidator() + { + { + var c = new JsonSchemaValidationContext("test") + { + EnableDiagnosisForNotRequiredFields = true, + }; + + var s = JsonSchema.FromType(); + + Assert.NotNull(s.Validator.Validate(c, new HasRequiredListObject())); + Assert.NotNull(s.Validator.Validate(c, new HasRequiredListObject { xs = new int[] {} })); + Assert.NotNull(s.Validator.Validate(c, new HasRequiredListObject { xs = new int[] { -1 } })); + Assert.Null(s.Validator.Validate(c, new HasRequiredListObject { xs = new int[] { 0 } })); + + Assert.True(c.IsEmpty()); + } + } } } diff --git a/Assets/VRM/UniJSON/Scripts/FormatterExtensionsSerializer.cs b/Assets/VRM/UniJSON/Scripts/FormatterExtensionsSerializer.cs index 1273ee582..94abead16 100644 --- a/Assets/VRM/UniJSON/Scripts/FormatterExtensionsSerializer.cs +++ b/Assets/VRM/UniJSON/Scripts/FormatterExtensionsSerializer.cs @@ -162,7 +162,14 @@ namespace UniJSON { // reflection var schema = JsonSchema.FromType(); - return (IFormatter f, T value) => schema.Serialize(f, value); + return (IFormatter f, T value) => + { + var c = new JsonSchemaValidationContext(value) + { + EnableDiagnosisForNotRequiredFields = true + }; + schema.Serialize(f, value, c); + }; } diff --git a/Assets/VRM/UniJSON/Scripts/Json/JsonSchema.cs b/Assets/VRM/UniJSON/Scripts/Json/JsonSchema.cs index 1957c4119..6ad4414c4 100644 --- a/Assets/VRM/UniJSON/Scripts/Json/JsonSchema.cs +++ b/Assets/VRM/UniJSON/Scripts/Json/JsonSchema.cs @@ -392,7 +392,10 @@ namespace UniJSON { if (c == null) { - c = new JsonSchemaValidationContext(o); + c = new JsonSchemaValidationContext(o) + { + EnableDiagnosisForNotRequiredFields = true, + }; } var ex = Validator.Validate(c, o); diff --git a/Assets/VRM/UniJSON/Scripts/JsonSchemaValidator/JsonObjectValidator.cs b/Assets/VRM/UniJSON/Scripts/JsonSchemaValidator/JsonObjectValidator.cs index 631ae8563..703e60d18 100644 --- a/Assets/VRM/UniJSON/Scripts/JsonSchemaValidator/JsonObjectValidator.cs +++ b/Assets/VRM/UniJSON/Scripts/JsonSchemaValidator/JsonObjectValidator.cs @@ -297,28 +297,66 @@ namespace UniJSON } } + static class GenericFieldView + { + public static FieldInfo[] GetFields() + { + var t = typeof(T); + return t.GetFields(BindingFlags.Instance | BindingFlags.Public); + } + + public static void CreateFieldProcessors( + string methodName, + Dictionary processors + ) + { + var mi = typeof(G).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic); + + var t = typeof(T); + foreach (var fi in GetFields()) + { + var value = Expression.Parameter(t, "value"); + var fieldValue = Expression.Field(value, fi); + var compileld = Expression.Lambda(fieldValue, value).Compile(); + + var getter = Expression.Constant(compileld); + var name = Expression.Constant(fi.Name); + + var g = mi.MakeGenericMethod(fi.FieldType); + var call = Expression.Call(g, getter, name); + var lambda = (Func)Expression.Lambda(call).Compile(); + + processors.Add(fi.Name, lambda()); + } + } + } + + internal class ValidationResult + { + public bool IsIgnorable; + public JsonSchemaValidationException Ex; + } + public static class GenericValidator { class ObjectValidator { delegate JsonSchemaValidationException FieldValidator( - JsonSchema s, JsonSchemaValidationContext c, T o, bool isRequired); + JsonSchema s, JsonSchemaValidationContext c, T o, out bool isIgnorable); - Dictionary m_validators = new Dictionary(); + Dictionary m_validators; static FieldValidator CreteFieldValidator(Func getter, string name) { - return (s, c, o, isRequired) => + return (JsonSchema s, JsonSchemaValidationContext c, T o, out bool isIgnorable) => { var v = s.Validator; using (c.Push(name)) { var field = getter(o); var ex = v.Validate(c, field); - if (ex != null && !isRequired && s.IsExplicitlyIgnorableValue(field)) - { - return null; - } + + isIgnorable = ex != null && s.IsExplicitlyIgnorableValue(field); return ex; } @@ -327,25 +365,46 @@ namespace UniJSON public ObjectValidator() { - var mi = typeof(ObjectValidator).GetMethod("CreteFieldValidator", - BindingFlags.Static|BindingFlags.NonPublic); + var validators = new Dictionary(); + GenericFieldView.CreateFieldProcessors( + "CreteFieldValidator", validators); - var t = typeof(T); - foreach(var fi in t.GetFields( - BindingFlags.Instance|BindingFlags.Public)) + m_validators = validators; + } + + public JsonSchemaValidationException ValidateProperty( + HashSet required, + KeyValuePair property, + JsonSchemaValidationContext c, + T o, + out bool isIgnorable + ) + { + var fieldName = property.Key; + var schema = property.Value; + + isIgnorable = false; + + FieldValidator fv; + if (m_validators.TryGetValue(fieldName, out fv)) { - var value = Expression.Parameter(typeof(T), "value"); - var fieldValue = Expression.Field(value, fi); - var compileld = Expression.Lambda(fieldValue, value).Compile(); + var isRequired = required != null && required.Contains(fieldName); - var getter = Expression.Constant(compileld); - var name = Expression.Constant(fi.Name); - var g = mi.MakeGenericMethod(fi.FieldType); - var call = Expression.Call(g, getter, name); - var lambda = (Func)Expression.Lambda(call).Compile(); + bool isMemberIgnorable; + var ex = fv(schema, c, o, out isMemberIgnorable); + if (ex != null) + { + isIgnorable = !isRequired && isMemberIgnorable; - m_validators.Add(fi.Name, lambda()); + if (isRequired // required fields must be checked + || c.EnableDiagnosisForNotRequiredFields) + { + return ex; + } + } } + + return null; } public JsonSchemaValidationException Validate( @@ -355,41 +414,62 @@ namespace UniJSON { foreach (var kv in properties) { - var fieldName = kv.Key; - var schema = kv.Value; - - FieldValidator fv; - if (m_validators.TryGetValue(fieldName, out fv)) + bool isIgnorable; + var ex = ValidateProperty(required, kv, c, o, out isIgnorable); + if (ex != null && !isIgnorable) { - var isRequired = required != null && required.Contains(fieldName); - var ex = fv(schema, c, o, isRequired); - if (ex != null) - { - if (isRequired // required fields must be checked - || c.EnableDiagnosisForNotRequiredFields) - { - return ex; - } - } + return ex; } } return null; } + + public void ValidationResults + (HashSet required, + Dictionary properties, + JsonSchemaValidationContext c, T o, + Dictionary results) + { + foreach (var kv in properties) + { + bool isIgnorable; + var ex = ValidateProperty(required, kv, c, o, out isIgnorable); + + results.Add(kv.Key, new ValidationResult { + IsIgnorable = isIgnorable, + Ex = ex, + }); + } + } } static ObjectValidator s_validator; - public static JsonSchemaValidationException Validate(HashSet required, - Dictionary properties, - JsonSchemaValidationContext c, T o) + static void prepareValidator() { if (s_validator == null) { s_validator = new ObjectValidator(); } + } + + public static JsonSchemaValidationException Validate(HashSet required, + Dictionary properties, + JsonSchemaValidationContext c, T o) + { + prepareValidator(); return s_validator.Validate(required, properties, c, o); } + + internal static void ValidationResults(HashSet required, + Dictionary properties, + JsonSchemaValidationContext c, T o, + Dictionary results) + { + prepareValidator(); + s_validator.ValidationResults(required, properties, c, o, results); + } } public JsonSchemaValidationException Validate(JsonSchemaValidationContext c, T o) @@ -411,103 +491,89 @@ namespace UniJSON { class Serializer { - delegate void FieldSerializer(JsonObjectValidator v, IFormatter f, JsonSchemaValidationContext c, T src); + delegate void FieldSerializer(JsonSchema s, JsonSchemaValidationContext c, IFormatter f, T o, + Dictionary vRes, string[] deps); - List m_fieldSerializers = new List(); + Dictionary m_serializers; - static FieldSerializer CreateSerializer(FieldInfo fi) + static FieldSerializer CreteFieldSerializer(Func getter, string name) { - var src = Expression.Parameter(typeof(T), "src"); - var getter = Expression.Field(src, fi); - var compiled = (Func)Expression.Lambda(getter, src).Compile(); - var name = fi.Name; - return (v, f, c, s) => + return (s, c, f, o, vRes, deps) => { - //c.Push(name); + var v = s.Validator; + var field = getter(o); - var validator = v.Properties[name].Validator; - - var value = compiled(s); - - // validate - if (validator.Validate(c, value) != null) + if (vRes[name].Ex != null) { return; } - /* - // depencencies - string[] dependencies; - if (validator.Dependencies.TryGetValue(name, out dependencies)) + if (deps != null) { - // check dependencies - bool hasDependencies = true; - foreach (var x in dependencies) + foreach(var dep in deps) { - if (!map.ContainsKey(x)) + if (vRes[dep].Ex != null) { - hasDependencies = false; - break; + return; } } - if (!hasDependencies) - { - continue; - } } - */ f.Key(name); - validator.Serialize(f, c, value); - //f.Serialize(value); - - //c.Pop(); + v.Serialize(f, c, field); }; } - public void AddField(FieldInfo fi) + public Serializer() { - var mi = typeof(Serializer).GetMethod("CreateSerializer", - BindingFlags.Static | BindingFlags.NonPublic); - var g = mi.MakeGenericMethod(fi.FieldType); - var f = Expression.Constant(fi); - var call = Expression.Call(g, f); - var compiled = (Func)Expression.Lambda(call).Compile(); - m_fieldSerializers.Add(compiled()); + var serializers = new Dictionary(); + GenericFieldView.CreateFieldProcessors( + "CreteFieldSerializer", serializers); + + m_serializers = serializers; } - public void Serialize(JsonObjectValidator v, IFormatter f, JsonSchemaValidationContext c, T value) + public void Serialize(JsonObjectValidator objectValidator, + IFormatter f, JsonSchemaValidationContext c, T o) { - f.BeginMap(m_fieldSerializers.Count); - foreach (var s in m_fieldSerializers) + // Validates fields + var validationResults = new Dictionary(); + GenericValidator.ValidationResults( + objectValidator.Required, objectValidator.Properties, + c, o, validationResults); + + // Serialize fields + f.BeginMap(objectValidator.Properties.Count()); + foreach (var property in objectValidator.Properties) { - s(v, f, c, value); + var fieldName = property.Key; + var schema = property.Value; + + string[] deps = null; + objectValidator.Dependencies.TryGetValue(fieldName, out deps); + + FieldSerializer fs; + if (m_serializers.TryGetValue(fieldName, out fs)) + { + fs(schema, c, f, o, validationResults, deps); + } } f.EndMap(); } } + static FieldInfo[] s_fields; static Serializer s_serializer; - public static void Serialize(JsonObjectValidator validator, + public static void Serialize(JsonObjectValidator objectValidator, IFormatter f, JsonSchemaValidationContext c, T value) { if (s_serializer == null) { - var t = typeof(T); - if (t == typeof(object)) - { - throw new ArgumentException("object cannot serialize"); - } - var serializer = new Serializer(); - var fields = t.GetFields(BindingFlags.Instance | BindingFlags.Public); - foreach (var fi in fields) - { - serializer.AddField(fi); - } - s_serializer = serializer; + s_serializer = new Serializer(); } - s_serializer.Serialize(validator, f, c, value); + + s_serializer.Serialize(objectValidator, f, c, value); } }