Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding Microsoft-style JSON Date Deserialization to as3corelib #146

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 74 additions & 62 deletions src/com/adobe/serialization/json/JSONDecoder.as
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,12 @@

package com.adobe.serialization.json
{
import com.adobe.utils.DateUtil;

public class JSONDecoder
{
/**
{

/**
* Flag indicating if the parser should be strict about the format
* of the JSON string it is attempting to decode.
*/
Expand All @@ -52,7 +53,7 @@ package com.adobe.serialization.json
private var token:JSONToken;

/**
* Constructs a new JSONDecoder to parse a JSON string
* Constructs a new JSONDecoder to parse a JSON string
* into a native object.
*
* @param s The JSON string to be converted
Expand All @@ -64,7 +65,7 @@ package com.adobe.serialization.json
* @tiptext
*/
public function JSONDecoder( s:String, strict:Boolean )
{
{
this.strict = strict;
tokenizer = new JSONTokenizer( s, strict );

Expand Down Expand Up @@ -97,47 +98,23 @@ package com.adobe.serialization.json
* Returns the next token from the tokenzier reading
* the JSON string
*/
private final function nextToken():JSONToken
private function nextToken():JSONToken
{
return token = tokenizer.getNextToken();
}

/**
* Returns the next token from the tokenizer reading
* the JSON string and verifies that the token is valid.
*/
private final function nextValidToken():JSONToken
{
token = tokenizer.getNextToken();
checkValidToken();

return token;
}

/**
* Verifies that the token is valid.
*/
private final function checkValidToken():void
{
// Catch errors when the input stream ends abruptly
if ( token == null )
{
tokenizer.parseError( "Unexpected end of input" );
}
}

/**
* Attempt to parse an array.
*/
private final function parseArray():Array
private function parseArray():Array
{
// create an array internally that we're going to attempt
// to parse from the tokenizer
var a:Array = new Array();

// grab the next token from the tokenizer to move
// past the opening [
nextValidToken();
nextToken();

// check to see if we have an empty array
if ( token.type == JSONTokenType.RIGHT_BRACKET )
Expand All @@ -150,12 +127,12 @@ package com.adobe.serialization.json
else if ( !strict && token.type == JSONTokenType.COMMA )
{
// move past the comma
nextValidToken();
nextToken();

// check to see if we're reached the end of the array
if ( token.type == JSONTokenType.RIGHT_BRACKET )
{
return a;
return a;
}
else
{
Expand All @@ -169,9 +146,9 @@ package com.adobe.serialization.json
{
// read in the value and add it to the array
a.push( parseValue() );

// after the value there should be a ] or a ,
nextValidToken();
nextToken();

if ( token.type == JSONTokenType.RIGHT_BRACKET )
{
Expand All @@ -187,8 +164,6 @@ package com.adobe.serialization.json
// if the decoder is not in strict mode
if ( !strict )
{
checkValidToken();

// Reached ",]" as the end of the array, so return it
if ( token.type == JSONTokenType.RIGHT_BRACKET )
{
Expand All @@ -201,25 +176,24 @@ package com.adobe.serialization.json
tokenizer.parseError( "Expecting ] or , but found " + token.value );
}
}

return null;
return null;
}

/**
* Attempt to parse an object.
*/
private final function parseObject():Object
private function parseObject():Object
{
// create the object internally that we're going to
// attempt to parse from the tokenizer
var o:Object = new Object();

// store the string part of an object member so
// that we can assign it a value in the object
var key:String

// grab the next token from the tokenizer
nextValidToken();
nextToken();

// check to see if we have an empty object
if ( token.type == JSONTokenType.RIGHT_BRACE )
Expand All @@ -232,7 +206,7 @@ package com.adobe.serialization.json
else if ( !strict && token.type == JSONTokenType.COMMA )
{
// move past the comma
nextValidToken();
nextToken();

// check to see if we're reached the end of the object
if ( token.type == JSONTokenType.RIGHT_BRACE )
Expand All @@ -255,23 +229,23 @@ package com.adobe.serialization.json
key = String( token.value );

// move past the string to see what's next
nextValidToken();
nextToken();

// after the string there should be a :
if ( token.type == JSONTokenType.COLON )
{
{
// move past the : and read/assign a value for the key
nextToken();
o[ key ] = parseValue();
o[key] = parseValue();

// move past the value to see what's next
nextValidToken();
nextToken();

// after the value there's either a } or a ,
if ( token.type == JSONTokenType.RIGHT_BRACE )
{
// we're done reading the object, so return it
return o;
return o;
}
else if ( token.type == JSONTokenType.COMMA )
{
Expand All @@ -282,8 +256,6 @@ package com.adobe.serialization.json
// if the decoder is not in strict mode
if ( !strict )
{
checkValidToken();

// Reached ",}" as the end of the object, so return it
if ( token.type == JSONTokenType.RIGHT_BRACE )
{
Expand All @@ -302,35 +274,45 @@ package com.adobe.serialization.json
}
}
else
{
{
tokenizer.parseError( "Expecting string but found " + token.value );
}
}
return null;
return null;
}

/**
* Attempt to parse a value
*/
private final function parseValue():Object
private function parseValue():Object
{
checkValidToken();

// Catch errors when the input stream ends abruptly
if ( token == null )
{
tokenizer.parseError( "Unexpected end of input" );
}

switch ( token.type )
{
case JSONTokenType.LEFT_BRACE:
return parseObject();

case JSONTokenType.LEFT_BRACKET:
return parseArray();

case JSONTokenType.STRING:
if (!isDate(token))
return token.value;

convertToDate(token);
return token.value;

case JSONTokenType.NUMBER:
case JSONTokenType.TRUE:
case JSONTokenType.FALSE:
case JSONTokenType.NULL:
return token.value;

case JSONTokenType.NAN:
if ( !strict )
{
Expand All @@ -340,13 +322,43 @@ package com.adobe.serialization.json
{
tokenizer.parseError( "Unexpected " + token.value );
}

default:
tokenizer.parseError( "Unexpected " + token.value );

}

return null;
return null;
}

/**
* Determine if the given token contains a a Date in serialized form
* @return
*/
private function isDate(token:JSONToken):Boolean
{
if (JSONTokenType.DATE == token.type)
return true;

if (DateUtil.isMicrosoftJSONDate(String(token.value)))
return true;

return false;
}

/**
* Convert the given token's type/value to Date
* @param token
*/
private function convertToDate(token:JSONToken):void
{
if (JSONTokenType.DATE == token.type)
return;

var result:Date = DateUtil.parseMicrosoftJSONDate(String(token.value));

token.value = result;
token.type = JSONTokenType.DATE;
}
}
}
Loading