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 processedObjects = new HashSet(); HashSet alwaysReprocessTypes = new HashSet() { typeof( DateTime ), typeof( BigInteger ) }; public JSONSerializer ( JSONSerializationSettings settings = null ) { this.settings = settings == null ? new JSONSerializationSettings() : settings; } Dictionary 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(); 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 ) ); } } } } }