cymhappy / as3corelib

Automatically exported from code.google.com/p/as3corelib
0 stars 0 forks source link

JSON cannot encode class instance as String correctly #2

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1. Create a simple class, like the following:

public class ExampleClass
{
    public var prop1:String;
    public var prop2:int;
}

2. Attempt to get the jsonString from the class:

var instance:ExampleClass = new ExampleClass();
instance.prop1 = "test";
instance.prop2 = 42;
var jsonString:String = JSON.encode( instance );

3. Output the jsonString value:

trace( jsonString );  // "{}"

What is the expected output? What do you see instead?

The expected output is the following string:
{"prop1":"test","prop2":42}

Please use labels and text to provide additional information.

The problem lies in the objectToString() method in JSONEncoder.as,
specifically line 248:

   // loop over the keys in the object and add their converted
   // values to the string
   for ( var key:String in o ) {
   ...

That loop fails to iterate over the class members when o is a class instance.

The solution to the problem will need to use the describeType() method to
get the class meta data information, and then loop over that to create the
json string based on what the class members are.

Original issue reported on code.google.com by darron.schall on 29 Dec 2006 at 7:49

GoogleCodeExporter commented 9 years ago

Original comment by darron.schall on 29 Dec 2006 at 7:49

GoogleCodeExporter commented 9 years ago
A possible fix to this issue would be the following code.  Note that this code 
has
not been extensively tested, but seems to work under preliminary analysis:

        /**
         * Converts an object to it's JSON string equivalent
         *
         * @param o The object to convert
         * @return The JSON string representation of <code>o</code>
         */
        private function objectToString( o:Object ):String
        {
            // create a string to store the object's jsonstring value
            var s:String = "";

            // determine if o is a class instance or a plain object
            var classInfo:XML = describeType( o );
            if ( classInfo.@name.toString() == "Object" )
            {
                // the value of o[key] in the loop below - store this 
                // as a variable so we don't have to keep looking up o[key]
                // when testing for valid values to convert
                var value:Object;

                // loop over the keys in the object and add their converted
                // values to the string
                for ( var key:String in o )
                {
                    // assign value to a variable for quick lookup
                    value = o[key];

                    // don't add function's to the JSON string
                    if ( value is Function )
                    {
                        // skip this key and try another
                        continue;
                    }

                    // when the length is 0 we're adding the first item so
                    // no comma is necessary
                    if ( s.length > 0 ) {
                        // we've already added an item, so add the comma separator
                        s += ","
                    }

                    s += escapeString( key ) + ":" + convertToString( value );
                }
            }
            else // o is a class instance
            {
                // Loop over all of the variables in the class and serialize them
                // along with their values.
                for each ( var v:XML in classInfo..variable )
                {
                    // When the length is 0 we're adding the first item so
                    // no comma is necessary
                    if ( s.length > 0 ) {
                        // We've already added an item, so add the comma separator
                        s += ","
                    }

                    s += escapeString( v.@name.toString() ) + ":" 
                            + convertToString( o[ v.@name ] );
                }

            }

            return "{" + s + "}";
        }

Original comment by darron.schall on 29 Dec 2006 at 8:17

GoogleCodeExporter commented 9 years ago
Along with looking for the variables in the case of a class instance, we also 
need to
look for accessors:

for each ( var v:XML in classInfo..*.( name() == "variable" || name() == 
"accessor" ) )

Original comment by darron.schall on 2 Jan 2007 at 8:58

GoogleCodeExporter commented 9 years ago

Original comment by mikechambers on 14 Feb 2007 at 6:03

GoogleCodeExporter commented 9 years ago
Fixed in revision 23.

Original comment by darron.schall on 21 Feb 2007 at 3:15