Json.NET require all properties on deserialization - json

In Json.NET, how do I make ALL properties required upon deserialization? I know that I can do this with attributes on the messages, but I don't want to do that. Mainly because it would require my message library to take on an external dependency.
I tried the MissingMemberHandling.Error setting, but it does the opposite of what I want. I'm okay with the JSON having extra properties. I want it to fail when any target object properties are missing in the JSON.
I'm actually deserializing to F# records, and the properties can't ordinarily be null anyway. (They can't be assigned null by normal means in code.) But Json.NET happily defaults properties to null under the covers when data is missing.
F# version of accepted answer
Resolver
open System
open Newtonsoft.Json
open Newtonsoft.Json.Serialization
type RequireAllPropertiesContractResolver() =
inherit DefaultContractResolver()
override me.CreateObjectContract(objectType:Type) =
let contract = base.CreateObjectContract(objectType)
contract.ItemRequired <- new Nullable<Required>(Required.Always)
contract
In the settings
let settings = new JsonSerializerSettings() // default settings
...
settings.ContractResolver <- new RequireAllPropertiesContractResolver()

If your model has properties that your JSON may omit, and you want that to be an error, add the attribute [JsonObject(ItemRequired=Required.Always)] to your classes:
Type: Required
A value indicating whether the object's properties are required.
Possible values for Required are:
Default: The property is not required. The default state.
AllowNull: The property must be defined in JSON but can be a null value.
Always: The property must be defined in JSON and cannot be a null value.
DisallowNull: The property is not required but it cannot be a null value [if present]. (Json.NET 8.0.1 and later.)
The setting is inherited so can be added to a generic base class.
Update
To do it globally for all objects, subclass the DefaultContractResolver and add the ItemRequired flag to all object contracts:
public class RequireObjectPropertiesContractResolver : DefaultContractResolver
{
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
var contract = base.CreateObjectContract(objectType);
contract.ItemRequired = Required.Always;
return contract;
}
}
And then later, in settings:
var settings = new JsonSerializerSettings { ContractResolver = new RequireObjectPropertiesContractResolver() };
Notes:
If you don't want to require JSON properties when your f# member is optional see this answer to this question and also the question Json.NET make property required based on property type.
This contract resolver applies a default setting of Required.Always to all object properties, but will not override JsonProperty.AttributeRequired when applied directly. If you need that, see e.g. How to override the "Required.Always" in newtonsoft json.
As stated in the question, the setting MissingMemberHandling = MissingMemberHandling.Error solves a complimentary problem: if your JSON may have properties that your model omits, and you want that to be an error, use MissingMemberHandling.Error. See: MissingMemberHandling setting.
You may want to cache the contract resolver for best performance.

I know I am late on party here, but... Accepted answer forces all properties to be available, which could be not so good for case when your record contains Option types combining with NullValueHandling.Ignore parameter on JsonSerializerSettings. In that case you would require option type to be present, which is too limiting. We found this solution works for us:
type RequireAllPropertiesContractResolver() =
inherit CamelCasePropertyNamesContractResolver()
override __.CreateProperty(memb, serialization) =
let prop = base.CreateProperty(memb, serialization)
let isRequired = not (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() = typedefof<option<_>>)
if isRequired then prop.Required <- Required.Always
prop
I hope it helps someone.

Related

Flexsource properties not appearing in rule editor

I followed the demo project here https://codeeffects.com/Doc/Business-Rule-Flex-Source for a sample of how the Flex properties work. My rules are evaluated correctly, but the editor does not show the fields.
I have looked at all of the properties of the FlexPropertyInfo object and confirmed that they set as I would expect. What else should I try in order to troubleshoot this?
Make sure that your Flex type inherits from Type and implements the minimum required properties and methods, and GetProperties in particular, e.g.:
public override PropertyInfo[] GetProperties(BindingFlags bindingAttr)
{
List<FlexPropertyInfo> properties = new List<FlexPropertyInfo>();
properties.Add(new FlexPropertyInfo("Id", typeof(int), typeName));
properties.Add(new FlexPropertyInfo("Name", typeof(string), typeName));
return properties.ToArray();
}
Make sure that you pass a new instance of your Flex type and not the type itself.
RuleEditor editor = new RuleEditor("divRuleEditor")
{
Mode = Common.RuleType.Execution,
SourceType = new MyFlexType() //and not typeof(MyFlexType)
}
The Editor itself knows nothing about Flex. As far as it is concerned it is another type and it is using reflection to pull the list of all members. Which is why it is important to pass an instance of your type. Otherwise you will get reflection on the Type class instead. Same goes for properties and other Flex objects.

How to I get Json.NET to throw an exception when JSON doesn't contain a property [duplicate]

In Json.NET, how do I make ALL properties required upon deserialization? I know that I can do this with attributes on the messages, but I don't want to do that. Mainly because it would require my message library to take on an external dependency.
I tried the MissingMemberHandling.Error setting, but it does the opposite of what I want. I'm okay with the JSON having extra properties. I want it to fail when any target object properties are missing in the JSON.
I'm actually deserializing to F# records, and the properties can't ordinarily be null anyway. (They can't be assigned null by normal means in code.) But Json.NET happily defaults properties to null under the covers when data is missing.
F# version of accepted answer
Resolver
open System
open Newtonsoft.Json
open Newtonsoft.Json.Serialization
type RequireAllPropertiesContractResolver() =
inherit DefaultContractResolver()
override me.CreateObjectContract(objectType:Type) =
let contract = base.CreateObjectContract(objectType)
contract.ItemRequired <- new Nullable<Required>(Required.Always)
contract
In the settings
let settings = new JsonSerializerSettings() // default settings
...
settings.ContractResolver <- new RequireAllPropertiesContractResolver()
If your model has properties that your JSON may omit, and you want that to be an error, add the attribute [JsonObject(ItemRequired=Required.Always)] to your classes:
Type: Required
A value indicating whether the object's properties are required.
Possible values for Required are:
Default: The property is not required. The default state.
AllowNull: The property must be defined in JSON but can be a null value.
Always: The property must be defined in JSON and cannot be a null value.
DisallowNull: The property is not required but it cannot be a null value [if present]. (Json.NET 8.0.1 and later.)
The setting is inherited so can be added to a generic base class.
Update
To do it globally for all objects, subclass the DefaultContractResolver and add the ItemRequired flag to all object contracts:
public class RequireObjectPropertiesContractResolver : DefaultContractResolver
{
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
var contract = base.CreateObjectContract(objectType);
contract.ItemRequired = Required.Always;
return contract;
}
}
And then later, in settings:
var settings = new JsonSerializerSettings { ContractResolver = new RequireObjectPropertiesContractResolver() };
Notes:
If you don't want to require JSON properties when your f# member is optional see this answer to this question and also the question Json.NET make property required based on property type.
This contract resolver applies a default setting of Required.Always to all object properties, but will not override JsonProperty.AttributeRequired when applied directly. If you need that, see e.g. How to override the "Required.Always" in newtonsoft json.
As stated in the question, the setting MissingMemberHandling = MissingMemberHandling.Error solves a complimentary problem: if your JSON may have properties that your model omits, and you want that to be an error, use MissingMemberHandling.Error. See: MissingMemberHandling setting.
You may want to cache the contract resolver for best performance.
I know I am late on party here, but... Accepted answer forces all properties to be available, which could be not so good for case when your record contains Option types combining with NullValueHandling.Ignore parameter on JsonSerializerSettings. In that case you would require option type to be present, which is too limiting. We found this solution works for us:
type RequireAllPropertiesContractResolver() =
inherit CamelCasePropertyNamesContractResolver()
override __.CreateProperty(memb, serialization) =
let prop = base.CreateProperty(memb, serialization)
let isRequired = not (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() = typedefof<option<_>>)
if isRequired then prop.Required <- Required.Always
prop
I hope it helps someone.

Jackson JsonTypeInfo.As.EXTERNAL_PROPERTY doesn't work as expected

I am using Jackson to parse JSON that I have no control over. The JSON looks like this:
{
"status":"0"
"type":"type1"
"info": {
// additional fields
}
}
My class looks like this
public class Response {
private String status;
private String type;
private Info info
}
The subclass of Info that I use depends on the type property, so my mapping for info is
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "type")
#JsonSubTypes(value = {
#JsonSubTypes.Type(value = Type1Info.class, name = "type1"),
#JsonSubTypes.Type(value = Type2Info.class, name = "type2") })
public abstract class Info {
// some fields
}
As far as I can tell this is the correct way to use type info when the distinguishing element is at the same level as the element that has to be casted. But this doesn't work, I always get the same error:
com.fasterxml.jackson.databind.JsonMappingException: Unexpected token
(END_OBJECT), expected FIELD_NAME: missing property 'type' that is to
contain type id
If I change EXTERNAL_PROPERTY to PROPERTY I still get the same error. Is my understanding of EXTERNAL_PROPERTY wrong?
From Javadoc:
Inclusion mechanism similar to PROPERTY, except that property is
included one-level higher in hierarchy, i.e. as sibling property at
same level as JSON Object to type. Note that this choice can only be
used for properties, not for types (classes). Trying to use it for
classes will result in inclusion strategy of basic PROPERTY instead.
Noticed that can only be used for properties is bolded. Source: JsonTypeInfo.As.EXTERNAL_PROPERTY.
So, you have to move all annotation from Info class to property info or setInfo method in Response class.
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "type")
#JsonSubTypes(value = { #JsonSubTypes.Type(value = Type1Info.class, name = "type1"),
#JsonSubTypes.Type(value = Type2Info.class, name = "type2") })
public void setInfo(Info info) {
this.info = info;
}
For me, you should also remove type property from Response class. It will be generated dynamically during serialization process. In deserialization you do not need it because Jackson cares about types. Your class could look like this:
class Response {
private String status;
private Info info;
//getters, setters
}
See also this question: JSON nest class data binding.
For all those who use AutoValue or any other source code generator: #JsonTypeInfo and #JsonSubTypes annotations does not work when you annotate your abstract methods (which in generated code returns the actual property).
If you do it this way, you will get following exception:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of [xxx] (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
Also it not works when you annotate parameter in your method annotated as #JsonCreator. If you do it this way you would get this weird exception: com.fasterxml.jackson.databind.exc.MismatchedInputException: Unexpected token (START_OBJECT), expected START_ARRAY: need JSON Array to contain As.WRAPPER_ARRAY type information for class [xxx]
So to deal with it just dont use source code generator for this class, just map the Response object using common jackson annotations: #JsonCreator, #JsonProperty and #JsonTypeInfo, #JsonSubTypes
tested with jackson 2.10.5

Return an unset value in value converter

Using a value converter in WPF, you can return something like DependecyProperty.UnsetValue or Binding.DoNothing as special values to say leave the binding alone. Is there a similar mechanism in MVVMCross?
To be more specific about what I'm trying to do, is I have a view model property that is a three-state enum that I need to bind to 3 binary controls. So I thought I could bind each of the controls to a MyEnum -> bool converter that will have a conversion parameter set to the value of the converter and in the Convert method it will return true if the MyEnum state is equal to the parameter and false otherwise. So far so good. But I want this binding to be two-way, so I need to convert back. My convert back works something like this:
protected override MyEnum ConvertBack(bool value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (parameter is MyEnum)
{
if (value)
{
return (MyEnum)parameter; // this is fine
}
else
{
return ???
}
}
return base.ConvertBack(value, targetType, parameter, culture);
}
Basically, what I want to be able to do is say, if the state of my control is true update the bound property on my view model to be the same as the parameter, if not, leave the view model property alone.
Maybe this is the problem with using the strongly typed value converters?
If anybody else encounters a similar problem, in addition to Stuart's suggestions, this is what I actually ended up doing.
In the View Model
private MyEnum _selectedValue = MyEnum.SomeValue;
public MyEnum ? SelectedValue
{
get
{
return _selectedTab;
}
set
{
if (value.HasValue)
{
_selectedTab = value.Value;
RaisePropertyChanged(() => SelectedTab);
}
}
}
Then in my converter (now a MvxValueConverter<MyEnum?, bool>):
protected override MyEnum? ConvertBack(bool value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (parameter is MyEnum) // this is just a sanity check
{
if (value)
{
return (MyEnum)parameter;
}
else
{
return null
}
}
return base.ConvertBack(value, targetType, parameter, culture);
}
It's not a general solution, but it fits my immediate need.
Update: UnsetValue is now available in mvvmcross - so this answer is no longer required.
Binding.DoNothing, DependencyProperty.UnsetValue or equivalent are currently not implemented in the MvvmCross binding system, and I don't believe there are any feature or pull requests currently open on this.
I'm afraid I don't really understand your example - the 'conversion parameter set to the value of the converter' and the if (parameter is MyEnum) snippet rather threw me - as far as I know, the parameter in windows xaml binding is a constant so I don't quite understand this example. Sorry if I've misunderstood.
Regardless, some possible approaches that might be used to assist with getting this functionality up and running in your mvx app are:
You could throw an exception from the ValueConverter:
For the Convert direction, the binding FallbackValue is used if a ValueConverter fails (throws an exception)
For the ConvertBack direction, the binding does nothing if an exception is thrown (although this would unfortunately generate some trace "error" output each time)
You could implement a custom binding for your control - something which only fires change updates when the change is one you are interested in (some custom bindings are introduced in N=28 in http://mvvmcross.wordpress.com which creates bindings like BinaryEditFooTargetBinding.cs - it would be straight-forward to customise/filter the TargetOnMyCountChanged behaviour in that class)
You could implement a custom binary control - which only fires change updates when the change is one you are interested in (for various platforms, some custom controls are introduced in N=18 to N=20 in http://mvvmcross.wordpress.com)
You could implement ViewModel binary properties which mirror your View and map to your three state enum
You could use a ValueCombiner within the Tibet binding system - it should be relatively straight-forward to work out a combiner based on top of something like MvxSingleValueCombiner.cs
Alternatively/additionally, please do also consider raising a Feature and/or Pull Request for this 'do nothing' type of functionality to be included in the TryGetValue/SetValue methods in https://github.com/slodge/MvvmCross/blob/v3/Cirrious/Cirrious.MvvmCross.Binding/Bindings/SourceSteps/MvxSourceStep.cs#L66 - but obviously the timeline on that might be longer.

TypedFactoryFacility: Passing null argument

Consider the following test:
[Test]
public void Create_ServiceWithDynamicDependency_Created()
{
// arrange
IWindsorContainer container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IServiceFactory>().AsFactory());
container.Register(Component.For<ServiceWithDynamicDependency>().LifeStyle.Transient);
container.Register(Component.For<SomethingStatic>().LifeStyle.Transient);
var factory = container.Resolve<IServiceFactory>();
// act
ServiceWithDynamicDependency serviceWithDynamicDependency = factory.Create(null);
// assert
Assert.That(serviceWithDynamicDependency, Is.Not.Null);
}
This fails with the following exception: Could not resolve non-optional dependency for 'Testing.Windsor.Factory.ServiceWithDynamicDependency' (Testing.Windsor.Factory.ServiceWithDynamicDependency). Parameter 'somethingDynamic' type 'System.String'
If I replace the assert part with this:
ServiceWithDynamicDependency serviceWithDynamicDependency = factory.Create("foo");
The component is resolved as expected. Does anyone know of a workaround for this or do I have to hand-roll factories which accepts null arguments?
Although you didn't specify it I'm assuming your component has one constructor that looks like this:
public ServiceWithDynamicDependency(string somethingDynamic) {}
The behavior you're observing is not a bug - this is by design, and here's why.
If a value is required an actual value has to be provided, and null is not considered to be a correct value. Otherwise Windsor would just be passing null in for every constructor instead of bothering to find actual dependencies for that.
null is a special value in .NET and it means "no value". So even though you explicitly provide null as an argument Windsor will ignore it.
To solve this, instead of working around be explicit that the value is optional and provide a second constructor that does not include it.
Windsor is smart enough to pick the right constructor and if the value is not provided (or null as in your case) it will pick the no-argument constructor, and when the value is there (is not null) it will pick the one with the value.