rj-action-library/Runtime/Text/JSON/Serializers/JSONSerializer.cs

429 lines
11 KiB
C#

using System.Collections;
using System.Collections.Generic;
using System.Text;
using System;
using System.Linq;
using System.Numerics;
namespace Rokojori
{
public class JSONSerializer
{
JSONSerializationSettings settings = new JSONSerializationSettings();
HashSet<object> processedObjects = new HashSet<object>();
HashSet<Type> alwaysReprocessTypes = new HashSet<Type>()
{
typeof( DateTime ), typeof( BigInteger )
};
public JSONSerializer ( JSONSerializationSettings settings = null )
{
this.settings = settings == null ? new JSONSerializationSettings() : settings;
}
Dictionary<Type,CustomSerializer> customSerializers = null;
public string Serialize( object value )
{
Initialize();
if ( value == null )
{
return JSON.Stringify( new JSONValue() );
}
else if ( value is int )
{
return JSON.Stringify( CreateNumber( (int) value ) );
}
else if ( value is double )
{
return JSON.Stringify( CreateNumber( (double) value ) );
}
else if ( value is float )
{
return JSON.Stringify( CreateNumber( (float) value ) );
}
else if ( value is string )
{
return JSON.Stringify( new JSONValue( (string) value ) );
}
else if ( value is bool )
{
return JSON.Stringify( new JSONValue( (bool) value ) );
}
else if ( ReflectionHelper.IsList( value ) )
{
return JSON.Stringify( CreateArray( value as IList ) );
}
else if ( IsSerializableDictionary( value ) )
{
return JSON.Stringify( CreateMapLikeObject( value as IDictionary ) );
}
else
{
var serializer = GetCustomSerializer( value );
if ( serializer != null )
{
return JSON.Stringify( serializer.Serialize( value ) );
}
else
{
return JSON.Stringify( CreateObject( value ) );
}
}
}
void Initialize()
{
processedObjects.Clear();
if ( customSerializers != null ){ return ;}
customSerializers = new Dictionary<Type,CustomSerializer>();
settings.customSerializers.ForEach( s => AddSerializer( s ) );
JSONSerializationSettings.defaultSerializers.ForEach( s => AddSerializer( s ) );
}
void AddSerializer( CustomSerializer serializer )
{
var types = serializer.HandlingTypes();
types.ForEach( type => AddSerializerForType( type, serializer ) );
}
void AddSerializerForType( Type type, CustomSerializer serializer )
{
if ( customSerializers.ContainsKey( type ) )
{
return;
}
customSerializers[ type ] = serializer;
}
CustomSerializer GetCustomSerializer( object value )
{
if ( value == null ){ return null; }
var type = value.GetType();
if ( customSerializers.ContainsKey( type ) )
{
return customSerializers[ type ];
}
return null;
}
static bool IsSerializableDictionary( object value )
{
return JSONSerializationSettings.IsSerializableDictionary( value );
}
JSONData CreateNumber( int value )
{
if ( settings.saveNumbersWithType )
{
var jsonObject = new JSONObject();
jsonObject.Set( JSONSerializationSettings.NUMBER_TYPE, JSONSerializationSettings.INT_NUMBER_TYPE );
jsonObject.Set( JSONSerializationSettings.NUMBER_VALUE, value );
return jsonObject;
}
return new JSONValue( value );
}
JSONData CreateNumber( float value )
{
if ( settings.saveNumbersWithType )
{
var jsonObject = new JSONObject();
jsonObject.Set( JSONSerializationSettings.NUMBER_TYPE, JSONSerializationSettings.FLOAT_NUMBER_TYPE );
jsonObject.Set( JSONSerializationSettings.NUMBER_VALUE, value );
return jsonObject;
}
return new JSONValue( value );
}
JSONData CreateNumber( double value )
{
if ( settings.saveNumbersWithType )
{
var jsonObject = new JSONObject();
jsonObject.Set( JSONSerializationSettings.NUMBER_TYPE, JSONSerializationSettings.DOUBLE_NUMBER_TYPE );
jsonObject.Set( JSONSerializationSettings.NUMBER_VALUE, value );
return jsonObject;
}
return new JSONValue( value );
}
bool IsProcessableObject( object value )
{
if (System.Attribute.IsDefined( value.GetType(), typeof(JSONAlwaysProcessable) ) )
{
return true;
}
if ( alwaysReprocessTypes.Contains( value.GetType() ) )
{
return true;
}
if ( processedObjects.Contains( value ) )
{
RJLog.Error( "Cycle detected: " + value );
var interfaces = typeof( object ).GetInterfaces();
for ( int i = 0; i < interfaces.Length; i++ )
{
RJLog.Error( "Interfaces[" + i + "]" + interfaces[ i ].Name );
}
if ( settings.throwErrorOnCycles )
{
throw new System.Exception( "Cycle detected: " + value );
}
return false;
}
processedObjects.Add( value );
return true;
}
JSONData CreateArray( IList value )
{
if ( ! IsProcessableObject( value ) )
{
return new JSONValue();
}
var jsonArray = new JSONArray();
//RJLog.Log(value );
for ( int i = 0; i < value.Count; i++ )
{
AssignArrayMember( jsonArray, i, value[ i ] );
}
return jsonArray;
}
JSONData CreateMapLikeObject( IDictionary value )
{
if ( ! IsProcessableObject( value ) )
{
return new JSONValue();
}
var jsonObject = new JSONObject();
foreach ( var key in value.Keys )
{
AssignObjectMember( jsonObject, key + "", value[ key ] );
}
return jsonObject;
}
JSONData CreateObject( object obj )
{
if ( ! IsProcessableObject( obj ) )
{
return new JSONValue();
}
var type = obj.GetType();
var fields = type.GetFields();
var jsonObject = new JSONObject();
foreach ( var f in fields )
{
if ( f.IsStatic )
{
continue;
}
var name = f.Name;
var value = f.GetValue( obj );
if ( value == null )
{
jsonObject.Set( name, new JSONValue() );
}
else if ( value is int )
{
jsonObject.Set( name, CreateNumber( (int) value ) );
}
else if ( value is double )
{
jsonObject.Set( name, CreateNumber( (double) value ) );
}
else if ( value is float )
{
jsonObject.Set( name, CreateNumber( (float) value ) );
}
else if ( value is string )
{
jsonObject.Set( name, (string) value );
}
else if ( value is bool )
{
jsonObject.Set( name, (bool) value );
}
else if ( value is Enum )
{
jsonObject.Set( name, (int) value );
}
else if ( ReflectionHelper.IsList( value ) )
{
jsonObject.Set( name, CreateArray( value as IList ) );
}
else if ( IsSerializableDictionary( value ) )
{
jsonObject.Set( name, CreateMapLikeObject( value as IDictionary ) );
}
else
{
var exporter = GetCustomSerializer( value );
if ( exporter != null )
{
jsonObject.Set( name, exporter.Serialize( value ) );
}
else
{
jsonObject.Set( name, CreateObject( value ) );
}
}
}
return jsonObject;
}
void AssignArrayMember( JSONArray jsonArray, int index, object value )
{
if ( value == null )
{
jsonArray.Set( index, new JSONValue() );
}
else if ( value is int )
{
jsonArray.Set( index, CreateNumber( (int) value ) );
}
else if ( value is double )
{
jsonArray.Set( index, CreateNumber( (double) value ) );
}
else if ( value is float )
{
jsonArray.Set( index, CreateNumber( (float) value ) );
}
else if ( value is string )
{
jsonArray.Set( index, (string) value );
}
else if ( value is bool )
{
jsonArray.Set( index, (bool) value );
}
else if ( ReflectionHelper.IsList( value ) )
{
jsonArray.Set( index, CreateArray( value as IList) );
}
else if ( IsSerializableDictionary( value ) )
{
jsonArray.Set( index, CreateMapLikeObject( value as IDictionary ) );
}
else
{
var exporter = GetCustomSerializer( value );
if ( exporter != null )
{
jsonArray.Set( index, exporter.Serialize( value ) );
}
else
{
jsonArray.Set( index, CreateObject( value ) );
}
}
}
void AssignObjectMember( JSONObject jsonObject, string name, object value )
{
if ( value == null )
{
jsonObject.Set( name, new JSONValue() );
}
else if ( value is int )
{
jsonObject.Set( name, CreateNumber( (int) value ) );
}
else if ( value is double )
{
jsonObject.Set( name, CreateNumber( (double) value ) );
}
else if ( value is float )
{
jsonObject.Set( name, CreateNumber( (float) value ) );
}
else if ( value is string )
{
jsonObject.Set( name, (string) value );
}
else if ( value is bool )
{
jsonObject.Set( name, (bool) value );
}
else if ( ReflectionHelper.IsList( value ) )
{
jsonObject.Set( name, CreateArray( value as IList ) );
}
else if ( IsSerializableDictionary( value ) )
{
jsonObject.Set( name, CreateMapLikeObject( value as IDictionary ) );
}
else
{
var exporter = GetCustomSerializer( value );
if ( exporter != null )
{
jsonObject.Set( name, exporter.Serialize( value ) );
}
else
{
jsonObject.Set( name, CreateObject( value ) );
}
}
}
}
}