diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs
index b516bd13f51f95..d9698c71ce3f00 100644
--- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs
+++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs
@@ -29,6 +29,7 @@ private sealed partial class Emitter
private const string DefaultContextBackingStaticVarName = "s_defaultContext";
internal const string GetConverterFromFactoryMethodName = "GetConverterFromFactory";
private const string InfoVarName = "info";
+ private const string PropertyInfoVarName = "propertyInfo";
internal const string JsonContextVarName = "jsonContext";
private const string NumberHandlingPropName = "NumberHandling";
private const string ObjectCreatorPropName = "ObjectCreator";
@@ -709,6 +710,7 @@ private static string GeneratePropMetadataInitFunc(TypeGenerationSpec typeGenera
string memberTypeCompilableName = memberTypeMetadata.TypeRef;
string infoVarName = $"{InfoVarName}{i}";
+ string propertyInfoVarName = $"{PropertyInfoVarName}{i}";
sb.Append($@"
{JsonPropertyInfoValuesTypeRef}<{memberTypeCompilableName}> {infoVarName} = new {JsonPropertyInfoValuesTypeRef}<{memberTypeCompilableName}>()
@@ -728,7 +730,16 @@ private static string GeneratePropMetadataInitFunc(TypeGenerationSpec typeGenera
JsonPropertyName = {jsonPropertyNameValue}
}};
- {PropVarName}[{i}] = {JsonMetadataServicesTypeRef}.CreatePropertyInfo<{memberTypeCompilableName}>({OptionsLocalVariableName}, {infoVarName});
+ {JsonPropertyInfoTypeRef} {propertyInfoVarName} = {JsonMetadataServicesTypeRef}.CreatePropertyInfo<{memberTypeCompilableName}>({OptionsLocalVariableName}, {infoVarName});");
+
+ if (memberMetadata.IsRequired)
+ {
+ sb.Append($@"
+ {propertyInfoVarName}.IsRequired = true;");
+ }
+
+ sb.Append($@"
+ {PropVarName}[{i}] = {propertyInfoVarName};
");
}
diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs
index ca04dff1fc839a..b1fe30e7f4acee 100644
--- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs
+++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs
@@ -40,6 +40,7 @@ private sealed class Parser
private const string JsonNumberHandlingAttributeFullName = "System.Text.Json.Serialization.JsonNumberHandlingAttribute";
private const string JsonPropertyNameAttributeFullName = "System.Text.Json.Serialization.JsonPropertyNameAttribute";
private const string JsonPropertyOrderAttributeFullName = "System.Text.Json.Serialization.JsonPropertyOrderAttribute";
+ private const string JsonRequiredAttributeFullName = "System.Text.Json.Serialization.JsonRequiredAttribute";
private const string JsonSerializerContextFullName = "System.Text.Json.Serialization.JsonSerializerContext";
private const string JsonSourceGenerationOptionsAttributeFullName = "System.Text.Json.Serialization.JsonSourceGenerationOptionsAttribute";
@@ -1197,7 +1198,8 @@ private PropertyGenerationSpec GetPropertyGenerationSpec(
out string? converterInstantiationLogic,
out int order,
out bool hasFactoryConverter,
- out bool isExtensionData);
+ out bool isExtensionData,
+ out bool isRequired);
ProcessMember(
memberInfo,
@@ -1229,6 +1231,7 @@ private PropertyGenerationSpec GetPropertyGenerationSpec(
IsProperty = memberInfo.MemberType == MemberTypes.Property,
IsPublic = isPublic,
IsVirtual = isVirtual,
+ IsRequired = isRequired,
JsonPropertyName = jsonPropertyName,
RuntimePropertyName = runtimePropertyName,
PropertyNameVarName = propertyNameVarName,
@@ -1275,7 +1278,8 @@ private void ProcessMemberCustomAttributes(
out string? converterInstantiationLogic,
out int order,
out bool hasFactoryConverter,
- out bool isExtensionData)
+ out bool isExtensionData,
+ out bool isRequired)
{
hasJsonInclude = false;
jsonPropertyName = null;
@@ -1284,6 +1288,7 @@ private void ProcessMemberCustomAttributes(
converterInstantiationLogic = null;
order = 0;
isExtensionData = false;
+ isRequired = false;
bool foundDesignTimeCustomConverter = false;
hasFactoryConverter = false;
@@ -1350,6 +1355,11 @@ private void ProcessMemberCustomAttributes(
isExtensionData = true;
}
break;
+ case JsonRequiredAttributeFullName:
+ {
+ isRequired = true;
+ }
+ break;
default:
break;
}
diff --git a/src/libraries/System.Text.Json/gen/PropertyGenerationSpec.cs b/src/libraries/System.Text.Json/gen/PropertyGenerationSpec.cs
index 62d6ff746c0fbb..5417f25b6c649a 100644
--- a/src/libraries/System.Text.Json/gen/PropertyGenerationSpec.cs
+++ b/src/libraries/System.Text.Json/gen/PropertyGenerationSpec.cs
@@ -30,6 +30,11 @@ internal sealed class PropertyGenerationSpec
public bool IsVirtual { get; init; }
+ ///
+ /// The property has JsonRequiredAttribute.
+ ///
+ public bool IsRequired { get; init; }
+
///
/// The property name specified via JsonPropertyNameAttribute, if available.
///
diff --git a/src/libraries/System.Text.Json/ref/System.Text.Json.cs b/src/libraries/System.Text.Json/ref/System.Text.Json.cs
index 514dd8cd5852f1..acf62902c450a2 100644
--- a/src/libraries/System.Text.Json/ref/System.Text.Json.cs
+++ b/src/libraries/System.Text.Json/ref/System.Text.Json.cs
@@ -944,6 +944,11 @@ public sealed partial class JsonPropertyOrderAttribute : System.Text.Json.Serial
public JsonPropertyOrderAttribute(int order) { }
public int Order { get { throw null; } }
}
+ [System.AttributeUsageAttribute(System.AttributeTargets.Field | System.AttributeTargets.Property, AllowMultiple = false)]
+ public sealed partial class JsonRequiredAttribute : System.Text.Json.Serialization.JsonAttribute
+ {
+ public JsonRequiredAttribute() { }
+ }
[System.AttributeUsageAttribute(System.AttributeTargets.Class, AllowMultiple=true)]
public sealed partial class JsonSerializableAttribute : System.Text.Json.Serialization.JsonAttribute
{
@@ -1152,6 +1157,7 @@ internal JsonPropertyInfo() { }
public System.Text.Json.Serialization.JsonConverter? CustomConverter { get { throw null; } set { } }
public System.Func