using System.Collections; using System.Collections.Generic; using System.Text; using System; namespace Rokojori { public class JSONDeserializer { JSONSerializationSettings settings = new JSONSerializationSettings(); Dictionary customSerializers = null; public JSONDeserializer ( JSONSerializationSettings settings ) { this.settings = settings == null ? new JSONSerializationSettings() : settings; } public T Deserialize( string data ) where T:new() { return Deserialize( JSON.Parse( data ).AsObject() ); } public T Deserialize( 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( string data, T output ) { Deserialize( JSON.Parse( data ).AsObject(), output ); } public void Deserialize( 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(); 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 ); } } }