Skip to content

Instantly share code, notes, and snippets.

@INTERNALINTERFERENCE
Created March 26, 2023 12:58
Show Gist options
  • Save INTERNALINTERFERENCE/7ed5ce2af487429c3756a58ba5ea4f7b to your computer and use it in GitHub Desktop.
Save INTERNALINTERFERENCE/7ed5ce2af487429c3756a58ba5ea4f7b to your computer and use it in GitHub Desktop.
json
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