429 lines
11 KiB
C#
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 ) );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
} |