Repository: zest-java Updated Branches: refs/heads/ZEST-150 [created] cce88384a
ZEST-150 - Starting to fix that OrgJsonDeserializer can handle the Map Object format. But things isn't quite right. Committing to a new branch so CI doesn't break. Project: http://git-wip-us.apache.org/repos/asf/zest-java/repo Commit: http://git-wip-us.apache.org/repos/asf/zest-java/commit/cce88384 Tree: http://git-wip-us.apache.org/repos/asf/zest-java/tree/cce88384 Diff: http://git-wip-us.apache.org/repos/asf/zest-java/diff/cce88384 Branch: refs/heads/ZEST-150 Commit: cce88384a0c65791f340156e2d05d92eb548bf56 Parents: 92e5605 Author: Niclas Hedhman <[email protected]> Authored: Fri Jun 10 17:51:01 2016 +0800 Committer: Niclas Hedhman <[email protected]> Committed: Fri Jun 10 17:51:01 2016 +0800 ---------------------------------------------------------------------- abc.json | 86 ++++++++ .../apache/zest/api/value/ValueSerializer.java | 2 +- .../zest/runtime/defaults/UseDefaultsTest.java | 10 +- .../orgjson/OrgJsonValueDeserializer.java | 199 ++++++++++++------- .../AbstractCollectionSerializationTest.java | 26 +++ 5 files changed, 241 insertions(+), 82 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/zest-java/blob/cce88384/abc.json ---------------------------------------------------------------------- diff --git a/abc.json b/abc.json new file mode 100644 index 0000000..5431235 --- /dev/null +++ b/abc.json @@ -0,0 +1,86 @@ +{ + "number": 42, + "string": "Foo\"Bar\"\nTest\t", + "foo": { + "_type": "org.apache.zest.test.value.AbstractValueCompositeSerializationTest$FooValue", + "bar": "" + }, + "customFoo": { + "_type": "org.apache.zest.test.value.AbstractValueCompositeSerializationTest$CustomFooValue", + "custom": "", + "bar": "" + }, + "customFooValue": { + "_type": "org.apache.zest.test.value.AbstractValueCompositeSerializationTest$CustomFooValue", + "custom": "", + "bar": "" + }, + "stringIntMap": { + "foo": 42 + }, + "stringValueMap": { + "foo": { + "_type": "org.apache.zest.test.value.AbstractValueCompositeSerializationTest$AnotherValue", + "val1": "Foo", + "val2": "Bar" + } + }, + "anotherList": [ + { + "_type": "org.apache.zest.test.value.AbstractValueCompositeSerializationTest$AnotherValue", + "val1": "", + "val2": "" + } + ], + "specificCollection": { + "_type": "org.apache.zest.test.value.AbstractValueCompositeSerializationTest$SpecificCollection", + "genericList": [ + "Some", + "String" + ] + }, + "string2": "/Foo/bar", + "dateTime": "2020-03-04T13:24:35.000+01:00", + "localDate": "2016-06-10", + "localDateTime": "2016-06-10T17:44:23.716", + "entityReference": "12345", + "another": { + "_type": "org.apache.zest.test.value.AbstractValueCompositeSerializationTest$AnotherValue", + "val1": "Foo", + "val2": "Bar" + }, + "serializable": "rO0ABXNyAFVvcmcuYXBhY2hlLnplc3QudGVzdC52YWx1ZS5BYnN0cmFjdFZhbHVlQ29tcG9zaXRlU2VyaWFsaXphdGlvblRlc3QkU2VyaWFsaXphYmxlT2JqZWN0AAAAAAAAAAECAAJJAAN2YWxMAANmb290ABJMamF2YS9sYW5nL1N0cmluZzt4cAAAACN0AANGb28=", + "fooValue": { + "_type": "org.apache.zest.test.value.AbstractValueCompositeSerializationTest$FooValue", + "bar": "" + }, + "emptyString": "", + "stringList": [ ], + "anotherNull": null, + "testEnum": "somevalue", + "nullString": null, + "anotherListNull": null, + "anotherListEmpty": [ ], + "date": "2016-06-10T09:44:23.427Z", + "barAssociation": "6ca26469-9eb3-48fc-a4ae-a26cf73ded34-0", + "barEntityAssociation": "6ca26469-9eb3-48fc-a4ae-a26cf73ded34-1", + "barAssociationOptional": null, + "barManyAssociation": [ + "6ca26469-9eb3-48fc-a4ae-a26cf73ded34-2", + "6ca26469-9eb3-48fc-a4ae-a26cf73ded34-3" + ], + "barEntityManyAssociation": [ + "6ca26469-9eb3-48fc-a4ae-a26cf73ded34-4", + "6ca26469-9eb3-48fc-a4ae-a26cf73ded34-5" + ], + "barManyAssociationEmpty": [ ], + "barNamedAssociation": { + "bazar": "6ca26469-9eb3-48fc-a4ae-a26cf73ded34-6", + "cathedral": "6ca26469-9eb3-48fc-a4ae-a26cf73ded34-7" + }, + "barEntityNamedAssociation": { + "bazar": "6ca26469-9eb3-48fc-a4ae-a26cf73ded34-8", + "cathedral": "6ca26469-9eb3-48fc-a4ae-a26cf73ded34-9" + }, + "barNamedAssociationEmpty": {} +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/zest-java/blob/cce88384/core/api/src/main/java/org/apache/zest/api/value/ValueSerializer.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/zest/api/value/ValueSerializer.java b/core/api/src/main/java/org/apache/zest/api/value/ValueSerializer.java index 16886fd..6ab536e 100644 --- a/core/api/src/main/java/org/apache/zest/api/value/ValueSerializer.java +++ b/core/api/src/main/java/org/apache/zest/api/value/ValueSerializer.java @@ -187,7 +187,7 @@ public interface ValueSerializer public Options() { this.options.put( INCLUDE_TYPE_INFO, "true" ); - this.options.put( MAP_ENTRIES_AS_OBJECTS, "false" ); + this.options.put( MAP_ENTRIES_AS_OBJECTS, "true" ); } /** http://git-wip-us.apache.org/repos/asf/zest-java/blob/cce88384/core/runtime/src/test/java/org/apache/zest/runtime/defaults/UseDefaultsTest.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/test/java/org/apache/zest/runtime/defaults/UseDefaultsTest.java b/core/runtime/src/test/java/org/apache/zest/runtime/defaults/UseDefaultsTest.java index 9f9ac92..bade6f5 100644 --- a/core/runtime/src/test/java/org/apache/zest/runtime/defaults/UseDefaultsTest.java +++ b/core/runtime/src/test/java/org/apache/zest/runtime/defaults/UseDefaultsTest.java @@ -109,12 +109,10 @@ public class UseDefaultsTest @UseDefaults( "123.45" ) Property<Float> initializedFloatDefaultValue(); -// TODO: Seems that OrgJsonValueDeserializer has problem with arrays. -// @UseDefaults( "[\"abcde\"]" ) -// Property<List<String>> initializedStringListDefultString(); + @UseDefaults( "[\"abcde\"]" ) + Property<List<String>> initializedStringListDefultString(); -// TODO: Seems that OrgJsonValueDeserializer has problem with arrays. -// @UseDefaults( "{\"abcd\" : 345 }" ) -// Property<Map<String, Integer>> initializedMapDefaultValue(); + @UseDefaults( "{\"abcd\" : 345 }" ) + Property<Map<String, Integer>> initializedMapDefaultValue(); } } http://git-wip-us.apache.org/repos/asf/zest-java/blob/cce88384/core/spi/src/main/java/org/apache/zest/valueserialization/orgjson/OrgJsonValueDeserializer.java ---------------------------------------------------------------------- diff --git a/core/spi/src/main/java/org/apache/zest/valueserialization/orgjson/OrgJsonValueDeserializer.java b/core/spi/src/main/java/org/apache/zest/valueserialization/orgjson/OrgJsonValueDeserializer.java index 06ede92..7b5eb4d 100644 --- a/core/spi/src/main/java/org/apache/zest/valueserialization/orgjson/OrgJsonValueDeserializer.java +++ b/core/spi/src/main/java/org/apache/zest/valueserialization/orgjson/OrgJsonValueDeserializer.java @@ -29,6 +29,7 @@ import org.apache.zest.api.structure.ModuleDescriptor; import org.apache.zest.api.value.ValueSerializationException; import org.apache.zest.spi.value.ValueDeserializerAdapter; import org.json.JSONArray; +import org.json.JSONException; import org.json.JSONObject; import org.json.JSONTokener; @@ -112,7 +113,7 @@ public class OrgJsonValueDeserializer return collection; } input.back(); - for(; ; ) + for( ; ; ) { if( input.nextClean() == ',' ) { @@ -159,6 +160,7 @@ public class OrgJsonValueDeserializer { char c = input.nextClean(); char q; + boolean objectStructure = false; if( c == 'n' ) // null? { /* @@ -188,6 +190,11 @@ public class OrgJsonValueDeserializer { q = ']'; } + else if( c == '{' ) + { + objectStructure = true; + q = '}'; + } else { throw input.syntaxError( "A JSONArray text must start with '['" ); @@ -197,8 +204,13 @@ public class OrgJsonValueDeserializer return map; } input.back(); + if( input.nextClean() == '}' ) + { + return map; + } + input.back(); - for(; ; ) + for( ; ; ) { if( input.nextClean() == ',' ) { @@ -208,84 +220,17 @@ public class OrgJsonValueDeserializer { input.back(); // Map entry! - if( input.nextClean() != '{' ) + if( objectStructure ) { - throw input.syntaxError( "A JSONObject text must begin with '{'" ); + parseMapEntry( input, keyDeserializer, valueDeserializer, map ); } - - String objectKey; - K key = null; - V value = null; - - boolean breakIteration = false; - while( !breakIteration ) + else { - c = input.nextClean(); - switch( c ) - { - case 0: - throw input.syntaxError( "A JSONObject text must end with '}'" ); - case '}': - breakIteration = true; - continue; - default: - input.back(); - objectKey = input.nextValue().toString(); - } - - /* - * The key is followed by ':'. We will also tolerate '=' or '=>'. - */ - c = input.nextClean(); - if( c == '=' ) - { - if( input.next() != '>' ) - { - input.back(); - } - } - else if( c != ':' ) - { - throw input.syntaxError( "Expected a ':' after a key" ); - } - - if( "key".equals( objectKey ) ) - { - key = keyDeserializer.apply( input ); - } - else if( "value".equals( objectKey ) ) - { - value = valueDeserializer.apply( input ); - } - else + if( input.nextClean() != '{' ) { - input.nextValue(); + throw input.syntaxError( "A JSONObject text must begin with '{'" ); } - - /* - * Pairs are separated by ','. We will also tolerate ';'. - */ - switch( input.nextClean() ) - { - case ';': - case ',': - if( input.nextClean() == '}' ) - { - breakIteration = true; - continue; - } - input.back(); - continue; - case '}': - breakIteration = true; - continue; - default: - throw input.syntaxError( "Expected a ',' or '}'" ); - } - } - if( key != null ) - { - map.put( key, value ); + parseNodeEntry( input, keyDeserializer, valueDeserializer, map ); } } c = input.nextClean(); @@ -301,6 +246,7 @@ public class OrgJsonValueDeserializer break; case ']': case ')': + case '}': if( q != c ) { throw input.syntaxError( "Expected a '" + Character.valueOf( q ) + "'" ); @@ -312,6 +258,109 @@ public class OrgJsonValueDeserializer } } + private <K, V> void parseMapEntry( JSONTokener input, + Function<JSONTokener, K> keyDeserializer, + Function<JSONTokener, V> valueDeserializer, + Map<K, V> map + ) + throws JSONException + { + K key = keyDeserializer.apply( input ); + char c = input.nextClean(); + if( c != ':' ) + { + throw input.syntaxError( "Expected a ':' after a key" ); + } + V value = valueDeserializer.apply( input ); + if( key != null ) + { + map.put( key, value ); + } + } + + private <K, V> void parseNodeEntry( JSONTokener input, + Function<JSONTokener, K> keyDeserializer, + Function<JSONTokener, V> valueDeserializer, + Map<K, V> map + ) + throws JSONException + { + char c; + String objectKey; + boolean breakIteration = false; + K key = null; + V value = null; + while( !breakIteration ) + { + c = input.nextClean(); + switch( c ) + { + case 0: + throw input.syntaxError( "A JSONObject text must end with '}'" ); + case '}': + breakIteration = true; + continue; + default: + input.back(); + objectKey = input.nextValue().toString(); + } + + /* + * The key is followed by ':'. We will also tolerate '=' or '=>'. + */ + c = input.nextClean(); + if( c == '=' ) + { + if( input.next() != '>' ) + { + input.back(); + } + } + else if( c != ':' ) + { + throw input.syntaxError( "Expected a ':' after a key" ); + } + + if( "key".equals( objectKey ) ) + { + key = keyDeserializer.apply( input ); + } + else if( "value".equals( objectKey ) ) + { + value = valueDeserializer.apply( input ); + } + else + { + input.nextValue(); + } + + /* + * Pairs are separated by ','. We will also tolerate ';'. + */ + switch( input.nextClean() ) + { + case ';': + case ',': + if( input.nextClean() == '}' ) + { + breakIteration = true; + continue; + } + input.back(); + continue; + case '}': + breakIteration = true; + continue; + default: + throw input.syntaxError( "Expected a ',' or '}'" ); + } + } + if( key != null ) + { + map.put( key, value ); + } + } + // // Deserialization - Tree parsing // http://git-wip-us.apache.org/repos/asf/zest-java/blob/cce88384/core/testsupport/src/main/java/org/apache/zest/test/value/AbstractCollectionSerializationTest.java ---------------------------------------------------------------------- diff --git a/core/testsupport/src/main/java/org/apache/zest/test/value/AbstractCollectionSerializationTest.java b/core/testsupport/src/main/java/org/apache/zest/test/value/AbstractCollectionSerializationTest.java index d843d6f..fefcaae 100644 --- a/core/testsupport/src/main/java/org/apache/zest/test/value/AbstractCollectionSerializationTest.java +++ b/core/testsupport/src/main/java/org/apache/zest/test/value/AbstractCollectionSerializationTest.java @@ -22,6 +22,7 @@ package org.apache.zest.test.value; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; @@ -49,8 +50,10 @@ import static org.apache.zest.io.Inputs.text; import static org.apache.zest.io.Outputs.collection; import static org.apache.zest.io.Outputs.text; import static org.apache.zest.io.Transforms.map; +import static org.hamcrest.core.IsEqual.equalTo; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; /** * Assert that ValueSerialization behaviour on Collections and Maps is correct. @@ -254,6 +257,29 @@ public class AbstractCollectionSerializationTest assertEquals( valueCompositesList(), value ); } + @Test + public void givenHandCodedArrayWhenDeserializingListExpectPopulatedList() + throws Exception + { + ValueType valueType = ValueType.of( String.class ); + CollectionType collectionType = new CollectionType( List.class, valueType ); + List<String> value = valueSerialization.deserialize( module, collectionType, "[ \"abc\" ]" ); + List<String> expected = Collections.singletonList( "abc" ); + assertThat( value, equalTo( expected) ); + } + + @Test + public void givenHandCodedObejctWhenDeserializingMapExpectPopulatedMap() + throws Exception + { + ValueType keyType = ValueType.of( String.class ); + ValueType valueType = ValueType.of( Integer.class ); + MapType collectionType = new MapType( Map.class, keyType, valueType ); + Map<String, Integer> value = valueSerialization.deserialize( module, collectionType, "{\"abcd\" : 345 }" ); + Map<String, Integer> expected = Collections.singletonMap( "abcd", 345 ); + assertThat( value, equalTo( expected) ); + } + private ArrayList<Byte> byteCollection() { ArrayList<Byte> value = new ArrayList<>();
