-
-
Save INTERNALINTERFERENCE/7ed5ce2af487429c3756a58ba5ea4f7b to your computer and use it in GitHub Desktop.
json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
static public class Json | |
{ | |
static private readonly ConcurrentDictionary<Type, JsonShouldSerialize> _shouldSerializeAnalyzers = | |
new(); | |
static private readonly JsonSerializerSettings DefaultSerializerSettings = | |
new JsonSerializerSettings() | |
.Apply( settings => | |
{ | |
settings.Converters.Add( new ExceptionJsonConverter() ); | |
settings.Converters.Add( new StringEnumConverter() ); | |
settings.Converters.Add( new IPAddressJsonConverter() ); | |
settings.Converters.Add( new IPEndPointJsonConverter() ); | |
settings.Converters.Add( new OptionalValueJsonConverter() ); | |
settings.Converters.Add( new DateTimeOffsetIntervalJsonConverter() ); | |
settings.Converters.Add( new FixedSizeImmutableArrayJsonConverter() ); | |
settings.Converters.Add( new FixedSizeImmutableByteArrayJsonConverter() ); | |
static bool ShouldSerialize( object value ) | |
{ | |
if ( value.IsNotNull() ) | |
{ | |
var valueType = value.GetType(); | |
var shouldSerializeAnalyzer = _shouldSerializeAnalyzers.GetOrAdd( valueType, _ => | |
{ | |
var shouldSerializeAttribute = value | |
.GetType() | |
.GetCustomAttribute<JsonShouldSerializeAttribute>(); | |
return | |
shouldSerializeAttribute.IsNotNull() | |
? Activator.CreateInstance( shouldSerializeAttribute.AnalyzerType ).As<JsonShouldSerialize>() | |
: default; | |
} ); | |
if ( shouldSerializeAnalyzer.IsNotNull() ) | |
return shouldSerializeAnalyzer.ShouldSerialize( value ); | |
} | |
/// serialize abstract object always | |
/// even if it is actually empty | |
if ( value.Is<JObject>() ) | |
return true; | |
var result = true; | |
if ( value is ICollection collection ) | |
{ | |
/// do not serialize empty collections | |
result = collection.Count != 0; | |
} | |
else if ( value is IValueContainer valueContainer ) | |
{ | |
/// do not serialize <see cref="IValueContainer"/> with undefined value | |
result = valueContainer.HasValue; | |
} | |
else if ( value.IsNotNull() ) | |
{ | |
var valueType = value.GetType(); | |
if ( valueType.IsGenericType | |
&& valueType.GetInterfaces().Any( x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof( ICollection<> ) ) ) | |
result = (int)valueType.GetProperty( "Count" ).GetValue( value ) != 0; | |
} | |
return result; | |
}; | |
static void CreatePropertyAfter( | |
JsonProperty property, | |
MemberInfo memberInfo, | |
MemberSerialization memberSerialization ) | |
{ | |
if ( typeof( IValueContainer ).IsAssignableFrom( property.PropertyType ) ) | |
property.NullValueHandling = NullValueHandling.Include; | |
} | |
settings.DateTimeZoneHandling = DateTimeZoneHandling.Unspecified; | |
settings.ContractResolver = new CustomContractResolver | |
{ | |
ShouldSerialize = ShouldSerialize, | |
CreatePropertyAfter = CreatePropertyAfter | |
}; | |
settings.NullValueHandling = NullValueHandling.Ignore; | |
settings.Formatting = Formatting.None; | |
settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; | |
settings | |
.ConfigureForNodaTime( DateTimeZoneProviders.Tzdb ) | |
.WithIsoIntervalConverter(); | |
/// override noda time serializers | |
ConverterSet<LocalDate>( settings.Converters, new LocalDateJsonConverter() ); | |
ConverterSet<LocalTime>( settings.Converters, new LocalTimeJsonConverter() ); | |
ConverterSet<LocalDateTime>( settings.Converters, new LocalDateTimeJsonConverter() ); | |
} ); | |
static private readonly Lazy<JsonSerializer> _serializerDefault = | |
new( () => JsonSerializer.Create( DefaultSerializerSettings ), LazyThreadSafetyMode.PublicationOnly ); | |
static private readonly Lazy<JsonSerializer> _serializerPretty = | |
new( () => JsonSerializer.Create( DefaultSerializerSettings.Apply( x => x.Formatting = Formatting.Indented ) ), LazyThreadSafetyMode.PublicationOnly ); | |
static public JsonSerializer SerializerDefault => | |
_serializerDefault.Value; | |
static public JsonSerializer SerializerIndented => | |
_serializerPretty.Value; | |
static public JToken FromJsonFile( string filePath ) | |
{ | |
using var stream = File.OpenText( filePath.CheckIsNotNullOrWhitespace() ); | |
return stream.FromJson(); | |
} | |
static public T FromJsonFile<T>( string filePath ) | |
{ | |
using var stream = File.OpenText( filePath.CheckIsNotNullOrWhitespace() ); | |
return stream.FromJson<T>(); | |
} | |
static public bool TryParse( string jsonString, out JToken jToken ) | |
{ | |
try | |
{ | |
jToken = JToken.Parse( jsonString ); | |
return true; | |
} | |
catch | |
{ | |
jToken = null; | |
return false; | |
}; | |
} | |
static internal void ConverterSet<T>( | |
IList<JsonConverter> converters, | |
JsonConverter converter ) | |
{ | |
for ( var index = converters.Count - 1; index >= 0; --index ) | |
if ( converters[ index ].CanConvert( typeof( T ) ) ) | |
converters.RemoveAt( index ); | |
converters.Add( converter ); | |
} | |
static public void ConverterSet<T>( JsonConverter converter ) | |
{ | |
SerializerDefault.ConverterSet<T>( converter ); | |
SerializerIndented.ConverterSet<T>( converter ); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment