Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ private class DefaultValueWithConstructor

[DefaultValue(DefaultText)]
[JsonProperty(PropertyName = "myText", DefaultValueHandling = DefaultValueHandling.Populate)]
public readonly string Text;
public string Text { get; }

public DefaultValueWithConstructor([JsonProperty(PropertyName = "myText")]string text = DefaultText)
{
Expand All @@ -88,6 +88,51 @@ public void DefaultValueWithConstructorTest()
Assert.AreEqual(DefaultValueWithConstructor.DefaultText, myObject.Text);
}

private class DefaultValueWithUnmatchedConstructorParameter
{
public const string DefaultText = "...";

[DefaultValue(DefaultText)]
[JsonProperty(PropertyName = "myText", DefaultValueHandling = DefaultValueHandling.Populate)]
public string Text { get; }

public DefaultValueWithUnmatchedConstructorParameter(string text = DefaultText)
{
Text = text;
}
}

[Test]
public void DefaultValueWithUnmatchedConstructorParameterTest()
{
DefaultValueWithUnmatchedConstructorParameter myObject = JsonConvert.DeserializeObject<DefaultValueWithUnmatchedConstructorParameter>("{}");
Assert.IsNull(myObject.Text);
}

private class DefaultValueWithRenamedConstructorParameter
{
public const string DefaultText = "...";

[DefaultValue(DefaultText)]
[JsonProperty("renamedText", DefaultValueHandling = DefaultValueHandling.Populate)]
public string Text { get; }

public DefaultValueWithRenamedConstructorParameter(
[DefaultValue(DefaultText)]
[JsonProperty("renamedText", DefaultValueHandling = DefaultValueHandling.Populate)]
string text)
{
Text = text;
}
}

[Test]
public void DefaultValueWithRenamedConstructorParameterTest()
{
DefaultValueWithRenamedConstructorParameter myObject = JsonConvert.DeserializeObject<DefaultValueWithRenamedConstructorParameter>("{}");
Assert.AreEqual(DefaultValueWithRenamedConstructorParameter.DefaultText, myObject.Text);
}

public class MyClass
{
[JsonIgnore]
Expand Down Expand Up @@ -647,4 +692,4 @@ public enum ExportFormat
Currency,
Integer
}
}
}
63 changes: 37 additions & 26 deletions Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -700,7 +700,15 @@ protected virtual IList<JsonProperty> CreateConstructorParameters(ConstructorInf
continue;
}

JsonProperty? matchingMemberProperty = MatchProperty(memberProperties, parameterInfo.Name, parameterInfo.ParameterType);
string propertyName = parameterInfo.Name;
JsonPropertyAttribute? propertyAttribute = JsonTypeReflector.GetAttribute<JsonPropertyAttribute>(parameterInfo);
if (propertyAttribute?.PropertyName != null)
{
// Resolve an explicitly named parameter before matching it to a member property.
propertyName = ResolvePropertyNameFromAttribute(propertyAttribute.PropertyName, constructor.DeclaringType!, true, propertyAttribute);
}

JsonProperty? matchingMemberProperty = MatchProperty(memberProperties, propertyName, parameterInfo.ParameterType);

// ensure that property will have a name from matching property or from parameterinfo
// parameterinfo could have no name if generated by a proxy (I'm looking at you Castle)
Expand Down Expand Up @@ -1515,30 +1523,7 @@ private void SetPropertySettingsFromAttributes(JsonProperty property, object att
hasSpecifiedName = false;
}

JsonContainerAttribute? containerAttribute = JsonTypeReflector.GetAttribute<JsonContainerAttribute>(declaringType);

NamingStrategy? namingStrategy;
if (propertyAttribute?.NamingStrategyType != null)
{
namingStrategy = JsonTypeReflector.CreateNamingStrategyInstance(propertyAttribute.NamingStrategyType, propertyAttribute.NamingStrategyParameters);
}
else if (containerAttribute?.NamingStrategyType != null)
{
namingStrategy = JsonTypeReflector.GetContainerNamingStrategy(containerAttribute);
}
else
{
namingStrategy = NamingStrategy;
}

if (namingStrategy != null)
{
property.PropertyName = namingStrategy.GetPropertyName(mappedName, hasSpecifiedName);
}
else
{
property.PropertyName = ResolvePropertyName(mappedName);
}
property.PropertyName = ResolvePropertyNameFromAttribute(mappedName, declaringType, hasSpecifiedName, propertyAttribute);

property.UnderlyingName = name;

Expand Down Expand Up @@ -1643,6 +1628,32 @@ private void SetPropertySettingsFromAttributes(JsonProperty property, object att
}
}

private string ResolvePropertyNameFromAttribute(string mappedName, Type declaringType, bool hasSpecifiedName, JsonPropertyAttribute? propertyAttribute)
{
JsonContainerAttribute? containerAttribute = JsonTypeReflector.GetAttribute<JsonContainerAttribute>(declaringType);

NamingStrategy? namingStrategy;
if (propertyAttribute?.NamingStrategyType != null)
{
namingStrategy = JsonTypeReflector.CreateNamingStrategyInstance(propertyAttribute.NamingStrategyType, propertyAttribute.NamingStrategyParameters);
}
else if (containerAttribute?.NamingStrategyType != null)
{
namingStrategy = JsonTypeReflector.GetContainerNamingStrategy(containerAttribute);
}
else
{
namingStrategy = NamingStrategy;
}

if (namingStrategy != null)
{
return namingStrategy.GetPropertyName(mappedName, hasSpecifiedName);
}

return ResolvePropertyName(mappedName);
}

private Predicate<object>? CreateShouldSerializeTest(MemberInfo member)
{
MethodInfo? shouldSerializeMethod = member.DeclaringType!.GetMethod(JsonTypeReflector.ShouldSerializePrefix + member.Name, ReflectionUtils.EmptyTypes);
Expand Down Expand Up @@ -1738,4 +1749,4 @@ public string GetResolvedPropertyName(string propertyName)
return ResolvePropertyName(propertyName);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2057,7 +2057,8 @@ private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObj
JsonProperty? constructorProperty = context.ConstructorProperty;
if (constructorProperty == null && context.Property != null)
{
constructorProperty = contract.CreatorParameters.ForgivingCaseSensitiveFind(p => p.PropertyName!, context.Property.UnderlyingName!);
constructorProperty = contract.CreatorParameters.ForgivingCaseSensitiveFind(p => p.PropertyName!, context.Property.UnderlyingName!)
?? contract.CreatorParameters.ForgivingCaseSensitiveFind(p => p.PropertyName!, context.Property.PropertyName!);
}

if (constructorProperty != null && !constructorProperty.Ignored)
Expand Down