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

397 lines
10 KiB
C#

using System.Collections;
using System.Collections.Generic;
using System.Text;
using System;
namespace Rokojori
{
public class JSONDeserializer
{
JSONSerializationSettings settings = new JSONSerializationSettings();
Dictionary<Type,CustomSerializer> customSerializers = null;
public JSONDeserializer ( JSONSerializationSettings settings )
{
this.settings = settings == null ? new JSONSerializationSettings() : settings;
}
public T Deserialize<T>( string data ) where T:new()
{
return Deserialize<T>( JSON.Parse( data ).AsObject() );
}
public T Deserialize<T>( JSONObject jsonObject ) where T:new()
{
Initialize();
var output = new T();
var keys = jsonObject.keys;
for ( int i = 0; i < keys.Count; i++)
{
var key = keys[ i ];
DeserializeMemberField( jsonObject.Get( key ), output, key );
}
return output;
}
public void Deserialize<T>( string data, T output )
{
Deserialize<T>( JSON.Parse( data ).AsObject(), output );
}
public void Deserialize<T>( JSONObject jsonObject, T output )
{
Initialize();
var keys = jsonObject.keys;
for ( int i = 0; i < keys.Count; i++)
{
var key = keys[ i ];
DeserializeMemberField( jsonObject.Get( key ), output, key );
}
}
void DeserializeMemberField( JSONData data, object parent, string name )
{
if ( data.isNull )
{
SetMemberValue( parent, name, null );
return;
}
var type = parent.GetType();
var field = type.GetField( name );
if ( field == null )
{
RJLog.Log( "Field not present: " + name );
return;
}
var reference = new Reference( parent, name );
var fieldType = field.FieldType;
AssignValue( data, reference, fieldType );
}
void DeserializeListField( JSONData data, IList parent, int index )
{
if ( data.isNull )
{
SetListValue( parent, index, null );
return;
}
var type = parent.GetType();
var reference = new Reference( parent, index );
var listType = type.GetGenericArguments()[ 0 ];
AssignValue( data, reference, listType );
}
void DeserializeDictionaryField( JSONData data, IDictionary parent, string key, int index )
{
var type = parent.GetType();
var isIndexed = type.GetGenericArguments()[ 0 ] == typeof( int );
if ( data.isNull )
{
if ( isIndexed )
{
SetDictionaryValue( parent, index, null );
}
else
{
SetDictionaryValue( parent, key, null );
}
return;
}
var reference = isIndexed ? new Reference( parent, index ) : new Reference( parent, key );
var valueType = type.GetGenericArguments()[ 1 ];
AssignValue( data, reference, valueType );
}
void AssignValue( JSONData data, Reference reference, Type type )
{
var customSerializer = GetCustomDeserializer( type );
if ( customSerializer != null )
{
customSerializer.Deserialize( data, reference );
return;
}
if ( typeof( int ) == type )
{
SetNumber( data, reference, INT );
}
else if ( typeof( float ) == type )
{
SetNumber( data, reference, FLOAT );
}
else if ( typeof( double ) == type )
{
SetNumber( data, reference, DOUBLE );
}
else if ( typeof( bool ) == type )
{
if ( ! data.isBoolean )
{
RJLog.Log( "Type not matching: " + reference.GetInfo() + ">>" + data );
return;
}
reference.AssignValue( data.booleanValue );
}
else if ( type.IsEnum )
{
reference.AssignValue( data.enumValue( type ) );
}
else if ( typeof( string ) == type )
{
if ( ! data.isString )
{
RJLog.Log( "Type not matching: " + reference.GetInfo() + ">>" + data );
return;
}
reference.AssignValue( data.stringValue );
}
else if ( ReflectionHelper.IsList( type ) )
{
if ( ! data.isArray )
{
RJLog.Log( "Type not matching: " + reference.GetInfo() + ">>" + data );
return;
}
reference.AssignValue( CreateList( data, type ) );
}
else if ( IsSerializableDictionary( type ) )
{
if ( ! data.isObject )
{
RJLog.Log( "Type not matching: " + reference.GetInfo() + ">>" + data );
return;
}
reference.AssignValue( CreateDictionary( data, type ) );
}
else
{
if ( ! data.isObject )
{
RJLog.Log( "Type not matching: " + reference.GetInfo() + ">>" + data );
return;
}
reference.AssignValue( CreateObject( data, type ) );
}
}
IList CreateList( JSONData data, Type fieldType )
{
var array = data.AsArray();
var list = (IList) Activator.CreateInstance( fieldType );
for ( int i = 0 ; i < array.size; i++ )
{
var jsonValue = array.Get( i );
DeserializeListField( jsonValue, list, i );
}
return list;
}
IDictionary CreateDictionary( JSONData data, Type fieldType )
{
var map = data.AsObject();
var dict = (IDictionary) Activator.CreateInstance( fieldType );
var keys = map.keys;
var isIndexed = dict.GetType().GetGenericArguments()[ 0 ] == typeof( int );
if ( isIndexed )
{
for ( int i = 0 ; i < keys.Count; i++ )
{
var jsonValue = map.Get( keys[ i ] );
var index = RegexUtility.ParseInt( keys[ i ] );
DeserializeDictionaryField( jsonValue, dict, "", index );
}
}
else
{
for ( int i = 0 ; i < keys.Count; i++ )
{
var jsonValue = map.Get( keys[ i ] );
DeserializeDictionaryField( jsonValue, dict, keys[ i ], 0 );
}
}
return dict;
}
object CreateObject( JSONData data, Type type )
{
var output = Activator.CreateInstance( type );
var jsonObject = data.AsObject();
var keys = jsonObject.keys;
for ( int i = 0; i < keys.Count; i++)
{
var key = keys[ i ];
DeserializeMemberField( jsonObject.Get( key ), output, key );
}
return output;
}
void SetMemberValue( object instance, string name, object value )
{
ReflectionHelper.SetMemberValue( instance, name, value );
}
void SetListValue( IList list, int index, object value )
{
list[ index ] = value;
}
void SetDictionaryValue( IDictionary dictionary, string index, object value )
{
dictionary[ index ] = value;
}
void SetDictionaryValue( IDictionary dictionary, int index, object value )
{
dictionary[ index ] = value;
}
const int INT = 0;
const int FLOAT = 1;
const int DOUBLE = 2;
void SetNumber( JSONData data, Reference reference, int numberType )
{
if ( ! settings.saveNumbersWithType )
{
if ( ! data.isNumber )
{
RJLog.Log( "Type not matching: " + reference.GetInfo() + ">>" + data );
return;
}
switch ( numberType )
{
case INT:{ reference.AssignValue( data.intValue ); return; }
case FLOAT:{ reference.AssignValue( data.floatValue ); return; }
case DOUBLE:{ reference.AssignValue( data.numberValue ); return; }
}
RJLog.Log( "Unknown number type: " + reference.GetInfo() + ">>" + data );
return;
}
if ( ! data.isObject )
{
RJLog.Log( "Type not matching: " + reference.GetInfo() + ">>" + data );
return;
}
var objectValue = data.AsObject();
if ( ! objectValue.Contains( JSONSerializationSettings.NUMBER_VALUE ) )
{
RJLog.Log( "Type not matching: " + reference.GetInfo() + ">>" + data );
return;
}
switch ( numberType )
{
case INT:
{
var value = objectValue.Get( JSONSerializationSettings.NUMBER_VALUE ).intValue;
reference.AssignValue( value );
}
break;
case FLOAT:
{
var value = objectValue.Get( JSONSerializationSettings.NUMBER_VALUE ).floatValue;
reference.AssignValue( value );
}
break;
case DOUBLE:
{
var value = objectValue.Get( JSONSerializationSettings.NUMBER_VALUE ).numberValue;
reference.AssignValue( value );
}
break;
}
}
void Initialize()
{
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 GetCustomDeserializer( Type type )
{
if ( customSerializers.ContainsKey( type ) )
{
return customSerializers[ type ];
}
return null;
}
static bool IsSerializableDictionary( Type type )
{
return JSONSerializationSettings.IsSerializableDictionary( type );
}
}
}