397 lines
10 KiB
C#
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 );
|
|
}
|
|
|
|
}
|
|
} |