Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id E8F22200C71 for ; Sun, 2 Apr 2017 19:45:48 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id E7CFB160B8E; Sun, 2 Apr 2017 17:45:48 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 2B5ED160BC5 for ; Sun, 2 Apr 2017 19:45:44 +0200 (CEST) Received: (qmail 14606 invoked by uid 500); 2 Apr 2017 17:45:43 -0000 Mailing-List: contact commits-help@polygene.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@polygene.apache.org Delivered-To: mailing list commits@polygene.apache.org Received: (qmail 13563 invoked by uid 99); 2 Apr 2017 17:45:42 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 02 Apr 2017 17:45:42 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id AD895E0EE6; Sun, 2 Apr 2017 17:45:42 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: paulmerlin@apache.org To: commits@polygene.apache.org Date: Sun, 02 Apr 2017 17:46:21 -0000 Message-Id: In-Reply-To: <0088a29e2e0d476a907e84190e3d8c97@git.apache.org> References: <0088a29e2e0d476a907e84190e3d8c97@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [41/51] [abbrv] polygene-java git commit: JSON Serialization enhancements archived-at: Sun, 02 Apr 2017 17:45:49 -0000 JSON Serialization enhancements Reuse JSON factories and transformers for performance reasons. Allow to explicitly set JSON provider implementation during assembly. Provide JsonBuilderFactory to adapters. Ignore JSON comments by default when using Johnzon. Project: http://git-wip-us.apache.org/repos/asf/polygene-java/repo Commit: http://git-wip-us.apache.org/repos/asf/polygene-java/commit/b1a3dbe7 Tree: http://git-wip-us.apache.org/repos/asf/polygene-java/tree/b1a3dbe7 Diff: http://git-wip-us.apache.org/repos/asf/polygene-java/diff/b1a3dbe7 Branch: refs/heads/serialization-3.0 Commit: b1a3dbe7b13dd420b7aa84a3b80cebb82d2c6360 Parents: 2c643b8 Author: Paul Merlin Authored: Sun Apr 2 18:35:58 2017 +0200 Committer: Paul Merlin Committed: Sun Apr 2 19:16:24 2017 +0200 ---------------------------------------------------------------------- .../javaxjson/JavaxJsonAdapter.java | 4 +- .../javaxjson/JavaxJsonAdapters.java | 50 +++++--- .../javaxjson/JavaxJsonDeserializer.java | 109 ++++++++++++++-- .../javaxjson/JavaxJsonFactories.java | 127 +++++++++++++++++++ .../javaxjson/JavaxJsonSerializer.java | 77 ++++++++--- .../javaxjson/JavaxJsonSettings.java | 11 ++ .../spi/serialization/JsonDeserializer.java | 84 ------------ .../spi/serialization/JsonSerializer.java | 30 ----- .../javaxjson/CustomJsonAdapterTest.java | 17 ++- .../javaxjson/HandCraftedJsonTest.java | 2 - 10 files changed, 338 insertions(+), 173 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/polygene-java/blob/b1a3dbe7/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonAdapter.java ---------------------------------------------------------------------- diff --git a/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonAdapter.java b/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonAdapter.java index 99d5d80..9b17f37 100644 --- a/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonAdapter.java +++ b/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonAdapter.java @@ -19,6 +19,7 @@ package org.apache.polygene.serialization.javaxjson; import java.util.function.BiFunction; import java.util.function.Function; +import javax.json.JsonBuilderFactory; import javax.json.JsonValue; import org.apache.polygene.api.type.ValueType; @@ -37,11 +38,12 @@ public interface JavaxJsonAdapter /** * Serialize. * + * @param builderFactory Factory to create JSON * @param object Object to serialize, never null * @param serialize Serialization function for nested structure serialization * @return Serialized JSON representation */ - JsonValue serialize( Object object, Function serialize ); + JsonValue serialize( JsonBuilderFactory builderFactory, Object object, Function serialize ); /** * Deserialize. http://git-wip-us.apache.org/repos/asf/polygene-java/blob/b1a3dbe7/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonAdapters.java ---------------------------------------------------------------------- diff --git a/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonAdapters.java b/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonAdapters.java index a6c7933..fdb3e53 100644 --- a/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonAdapters.java +++ b/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonAdapters.java @@ -21,7 +21,7 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.function.BiFunction; import java.util.function.Function; -import javax.json.Json; +import javax.json.JsonBuilderFactory; import javax.json.JsonNumber; import javax.json.JsonString; import javax.json.JsonValue; @@ -112,7 +112,8 @@ public interface JavaxJsonAdapters private static abstract class ToJsonStringAdapter implements JavaxJsonAdapter { @Override - public JsonValue serialize( Object object, Function serialize ) + public JsonValue serialize( JsonBuilderFactory builderFactory, Object object, + Function serialize ) { return JavaxJson.toJsonString( object ); } @@ -149,7 +150,8 @@ public interface JavaxJsonAdapters public Class type() { return Boolean.class; } @Override - public JsonValue serialize( Object object, Function serialize ) + public JsonValue serialize( JsonBuilderFactory builderFactory, Object object, + Function serialize ) { return type().cast( object ) ? JsonValue.TRUE : JsonValue.FALSE; } @@ -181,10 +183,11 @@ public interface JavaxJsonAdapters public Class type() { return Integer.class; } @Override - public JsonValue serialize( Object object, Function serialize ) + public JsonValue serialize( JsonBuilderFactory builderFactory, + Object object, Function serialize ) { - return Json.createObjectBuilder().add( "value", type().cast( object ) ).build() - .getJsonNumber( "value" ); + return builderFactory.createObjectBuilder().add( "value", type().cast( object ) ).build() + .getJsonNumber( "value" ); } @Override @@ -211,10 +214,11 @@ public interface JavaxJsonAdapters public Class type() { return Long.class; } @Override - public JsonValue serialize( Object object, Function serialize ) + public JsonValue serialize( JsonBuilderFactory builderFactory, + Object object, Function serialize ) { - return Json.createObjectBuilder().add( "value", type().cast( object ) ).build().getJsonNumber( - "value" ); + return builderFactory.createObjectBuilder().add( "value", type().cast( object ) ).build() + .getJsonNumber( "value" ); } @Override @@ -241,10 +245,11 @@ public interface JavaxJsonAdapters public Class type() { return Short.class; } @Override - public JsonValue serialize( Object object, Function serialize ) + public JsonValue serialize( JsonBuilderFactory builderFactory, + Object object, Function serialize ) { - return Json.createObjectBuilder().add( "value", type().cast( object ) ).build() - .getJsonNumber( "value" ); + return builderFactory.createObjectBuilder().add( "value", type().cast( object ) ).build() + .getJsonNumber( "value" ); } @Override @@ -271,10 +276,11 @@ public interface JavaxJsonAdapters public Class type() { return Byte.class; } @Override - public JsonValue serialize( Object object, Function serialize ) + public JsonValue serialize( JsonBuilderFactory builderFactory, + Object object, Function serialize ) { - return Json.createObjectBuilder().add( "value", type().cast( object ) ).build() - .getJsonNumber( "value" ); + return builderFactory.createObjectBuilder().add( "value", type().cast( object ) ).build() + .getJsonNumber( "value" ); } @Override @@ -301,10 +307,11 @@ public interface JavaxJsonAdapters public Class type() { return Float.class; } @Override - public JsonValue serialize( Object object, Function serialize ) + public JsonValue serialize( JsonBuilderFactory builderFactory, + Object object, Function serialize ) { - return Json.createObjectBuilder().add( "value", type().cast( object ) ).build() - .getJsonNumber( "value" ); + return builderFactory.createObjectBuilder().add( "value", type().cast( object ) ).build() + .getJsonNumber( "value" ); } @Override @@ -331,10 +338,11 @@ public interface JavaxJsonAdapters public Class type() { return Double.class; } @Override - public JsonValue serialize( Object object, Function serialize ) + public JsonValue serialize( JsonBuilderFactory builderFactory, + Object object, Function serialize ) { - return Json.createObjectBuilder().add( "value", type().cast( object ) ).build() - .getJsonNumber( "value" ); + return builderFactory.createObjectBuilder().add( "value", type().cast( object ) ).build() + .getJsonNumber( "value" ); } @Override http://git-wip-us.apache.org/repos/asf/polygene-java/blob/b1a3dbe7/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonDeserializer.java ---------------------------------------------------------------------- diff --git a/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonDeserializer.java b/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonDeserializer.java index 43765c9..d1310d7 100644 --- a/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonDeserializer.java +++ b/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonDeserializer.java @@ -17,6 +17,11 @@ */ package org.apache.polygene.serialization.javaxjson; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.io.UncheckedIOException; import java.lang.reflect.Array; import java.util.AbstractMap; import java.util.ArrayList; @@ -31,12 +36,16 @@ import java.util.function.Function; import java.util.stream.Stream; import javax.json.JsonArray; import javax.json.JsonObject; +import javax.json.JsonReader; import javax.json.JsonStructure; import javax.json.JsonValue; +import javax.json.stream.JsonParser; +import javax.json.stream.JsonParsingException; import org.apache.polygene.api.association.AssociationDescriptor; import org.apache.polygene.api.entity.EntityReference; import org.apache.polygene.api.injection.scope.This; import org.apache.polygene.api.injection.scope.Uses; +import org.apache.polygene.api.mixin.Initializable; import org.apache.polygene.api.property.PropertyDescriptor; import org.apache.polygene.api.serialization.Converter; import org.apache.polygene.api.serialization.Converters; @@ -57,6 +66,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Collections.unmodifiableList; import static java.util.Collections.unmodifiableMap; import static java.util.Collections.unmodifiableSet; +import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toCollection; import static org.apache.polygene.api.util.Collectors.toMapWithNullValues; import static org.apache.polygene.serialization.javaxjson.JavaxJson.asString; @@ -64,9 +74,13 @@ import static org.apache.polygene.serialization.javaxjson.JavaxJson.requireJsonA import static org.apache.polygene.serialization.javaxjson.JavaxJson.requireJsonObject; import static org.apache.polygene.serialization.javaxjson.JavaxJson.requireJsonStructure; -public class JavaxJsonDeserializer extends AbstractTextDeserializer implements JsonDeserializer +public class JavaxJsonDeserializer extends AbstractTextDeserializer + implements JsonDeserializer, Initializable { @This + private JavaxJsonFactories jsonFactories; + + @This private Converters converters; @This @@ -75,6 +89,88 @@ public class JavaxJsonDeserializer extends AbstractTextDeserializer implements J @Uses private ServiceDescriptor descriptor; + private JavaxJsonSettings settings; + + @Override + public void initialize() throws Exception + { + settings = JavaxJsonSettings.orDefault( descriptor.metaInfo( JavaxJsonSettings.class ) ); + } + + @Override + public T deserialize( ModuleDescriptor module, ValueType valueType, Reader state ) + { + // JSR-353 Does not allow reading "out of structure" values + // See https://www.jcp.org/en/jsr/detail?id=353 + // And commented JsonReader#readValue() method in the javax.json API + // BUT, it will be part of the JsonReader contract in the next version + // See https://www.jcp.org/en/jsr/detail?id=374 + // Implementation by provider is optional though, so we'll always need a default implementation here. + // Fortunately, JsonParser has new methods allowing to read structures while parsing so it will be easy to do. + // In the meantime, a poor man's implementation reading the json into memory will do. + // TODO Revisit values out of structure JSON deserialization when JSR-374 is out + String stateString; + try( BufferedReader buffer = new BufferedReader( state ) ) + { + stateString = buffer.lines().collect( joining( "\n" ) ); + } + catch( IOException ex ) + { + throw new UncheckedIOException( ex ); + } + // We want plain Strings, BigDecimals, BigIntegers to be deserialized even when unquoted + Function plainValueFunction = string -> + { + String poorMans = "{\"value\":" + string + "}"; + JsonObject poorMansJson = jsonFactories.readerFactory() + .createReader( new StringReader( poorMans ) ) + .readObject(); + JsonValue value = poorMansJson.get( "value" ); + return fromJson( module, valueType, value ); + }; + Function outOfStructureFunction = string -> + { + // Is this an unquoted plain value? + try + { + return plainValueFunction.apply( '"' + string + '"' ); + } + catch( JsonParsingException ex ) + { + return plainValueFunction.apply( string ); + } + }; + try( JsonParser parser = jsonFactories.parserFactory().createParser( new StringReader( stateString ) ) ) + { + if( parser.hasNext() ) + { + JsonParser.Event e = parser.next(); + switch( e ) + { + case VALUE_NULL: + return null; + case START_ARRAY: + case START_OBJECT: + // JSON Structure + try( JsonReader reader = jsonFactories.readerFactory() + .createReader( new StringReader( stateString ) ) ) + { + return fromJson( module, valueType, reader.read() ); + } + default: + // JSON Value out of structure + return outOfStructureFunction.apply( stateString ); + } + } + } + catch( JsonParsingException ex ) + { + return outOfStructureFunction.apply( stateString ); + } + // Empty state string? + return fromJson( module, valueType, JavaxJson.EMPTY_STRING ); + } + @Override public T fromJson( ModuleDescriptor module, ValueType valueType, JsonValue state ) { @@ -148,7 +244,8 @@ public class JavaxJsonDeserializer extends AbstractTextDeserializer implements J { case OBJECT: JsonObject object = (JsonObject) json; - String typeInfo = object.getString( getTypeInfoPropertyName(), valueType.primaryType().getName() ); + String typeInfo = object.getString( settings.getTypeInfoPropertyName(), + valueType.primaryType().getName() ); ValueDescriptor valueDescriptor = module.valueDescriptor( typeInfo ); if( valueDescriptor != null ) { @@ -206,7 +303,7 @@ public class JavaxJsonDeserializer extends AbstractTextDeserializer implements J private Object deserializeValueComposite( ModuleDescriptor module, ValueCompositeType valueType, JsonObject json ) { - String typeInfoName = getTypeInfoPropertyName(); + String typeInfoName = settings.getTypeInfoPropertyName(); String typeInfo = json.getString( typeInfoName, null ); if( typeInfo != null ) { @@ -284,10 +381,4 @@ public class JavaxJsonDeserializer extends AbstractTextDeserializer implements J return map == null ? Stream.empty() : map.entrySet().stream(); }; } - - private String getTypeInfoPropertyName() - { - return JavaxJsonSettings.orDefault( descriptor.metaInfo( JavaxJsonSettings.class ) ) - .getTypeInfoPropertyName(); - } } http://git-wip-us.apache.org/repos/asf/polygene-java/blob/b1a3dbe7/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonFactories.java ---------------------------------------------------------------------- diff --git a/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonFactories.java b/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonFactories.java new file mode 100644 index 0000000..e61e3e6 --- /dev/null +++ b/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonFactories.java @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.polygene.serialization.javaxjson; + +import java.util.Collections; +import java.util.Map; +import javax.json.JsonBuilderFactory; +import javax.json.JsonException; +import javax.json.JsonReaderFactory; +import javax.json.JsonWriterFactory; +import javax.json.spi.JsonProvider; +import javax.json.stream.JsonGenerator; +import javax.json.stream.JsonGeneratorFactory; +import javax.json.stream.JsonParserFactory; +import org.apache.polygene.api.injection.scope.Uses; +import org.apache.polygene.api.mixin.Initializable; +import org.apache.polygene.api.mixin.Mixins; +import org.apache.polygene.api.service.ServiceDescriptor; + +@Mixins( JavaxJsonFactories.Mixin.class ) +public interface JavaxJsonFactories +{ + JsonParserFactory parserFactory(); + + JsonReaderFactory readerFactory(); + + JsonGeneratorFactory generatorFactory(); + + JsonBuilderFactory builderFactory(); + + JsonWriterFactory writerFactory(); + + class Mixin implements JavaxJsonFactories, Initializable + { + @Uses + private ServiceDescriptor descriptor; + + private JsonParserFactory parserFactory; + private JsonReaderFactory readerFactory; + private JsonGeneratorFactory generatorFactory; + private JsonBuilderFactory builderFactory; + private JsonWriterFactory writerFactory; + + @Override + public void initialize() throws Exception + { + JavaxJsonSettings settings = JavaxJsonSettings.orDefault( descriptor.metaInfo( JavaxJsonSettings.class ) ); + + String jsonProviderClassName = settings.getJsonProviderClassName(); + JsonProvider jsonProvider; + if( jsonProviderClassName == null ) + { + jsonProvider = JsonProvider.provider(); + } + else + { + try + { + Class clazz = Class.forName( jsonProviderClassName ); + jsonProvider = (JsonProvider) clazz.newInstance(); + } + catch( ClassNotFoundException ex ) + { + throw new JsonException( "Provider " + jsonProviderClassName + " not found", ex ); + } + catch( Exception ex ) + { + throw new JsonException( "Provider " + jsonProviderClassName + " could not be instantiated", ex ); + } + } + + Map parserProperties = Collections.singletonMap( "org.apache.johnzon.supports-comments", true ); + parserFactory = jsonProvider.createParserFactory( parserProperties ); + readerFactory = jsonProvider.createReaderFactory( parserProperties ); + + Map generatorProperties = Collections.singletonMap( JsonGenerator.PRETTY_PRINTING, false ); + generatorFactory = jsonProvider.createGeneratorFactory( generatorProperties ); + builderFactory = jsonProvider.createBuilderFactory( generatorProperties ); + writerFactory = jsonProvider.createWriterFactory( generatorProperties ); + } + + @Override + public JsonParserFactory parserFactory() + { + return parserFactory; + } + + @Override + public JsonReaderFactory readerFactory() + { + return readerFactory; + } + + @Override + public JsonGeneratorFactory generatorFactory() + { + return generatorFactory; + } + + @Override + public JsonBuilderFactory builderFactory() + { + return builderFactory; + } + + @Override + public JsonWriterFactory writerFactory() + { + return writerFactory; + } + } +} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/b1a3dbe7/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonSerializer.java ---------------------------------------------------------------------- diff --git a/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonSerializer.java b/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonSerializer.java index 3bf8e1e..dcc2db8 100644 --- a/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonSerializer.java +++ b/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonSerializer.java @@ -17,23 +17,28 @@ */ package org.apache.polygene.serialization.javaxjson; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.io.Writer; import java.util.Base64; import java.util.Map; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; import java.util.stream.StreamSupport; -import javax.json.Json; import javax.json.JsonArray; import javax.json.JsonArrayBuilder; import javax.json.JsonObject; import javax.json.JsonObjectBuilder; +import javax.json.JsonString; import javax.json.JsonValue; import org.apache.polygene.api.PolygeneAPI; import org.apache.polygene.api.association.AssociationStateHolder; +import org.apache.polygene.api.common.Optional; import org.apache.polygene.api.composite.CompositeInstance; import org.apache.polygene.api.injection.scope.This; import org.apache.polygene.api.injection.scope.Uses; +import org.apache.polygene.api.mixin.Initializable; import org.apache.polygene.api.serialization.Converter; import org.apache.polygene.api.serialization.Converters; import org.apache.polygene.api.service.ServiceDescriptor; @@ -51,9 +56,13 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.stream.Collectors.toList; import static org.apache.polygene.api.util.Collectors.toMap; -public class JavaxJsonSerializer extends AbstractTextSerializer implements JsonSerializer +public class JavaxJsonSerializer extends AbstractTextSerializer + implements JsonSerializer, Initializable { @This + private JavaxJsonFactories jsonFactories; + + @This private Converters converters; @This @@ -62,6 +71,41 @@ public class JavaxJsonSerializer extends AbstractTextSerializer implements JsonS @Uses private ServiceDescriptor descriptor; + private JavaxJsonSettings settings; + + @Override + public void initialize() throws Exception + { + settings = JavaxJsonSettings.orDefault( descriptor.metaInfo( JavaxJsonSettings.class ) ); + } + + @Override + public void serialize( Options options, Writer writer, @Optional Object object ) + { + JsonValue jsonValue = toJson( options, object ); + if( jsonValue == null ) + { + return; + } + try + { + // We want plain Strings to be serialized without quotes which is non JSON compliant + // See https://java.net/jira/browse/JSON_PROCESSING_SPEC-65 + if( jsonValue.getValueType() == JsonValue.ValueType.STRING ) + { + writer.write( ( (JsonString) jsonValue ).getString() ); + } + else + { + writer.write( jsonValue.toString() ); + } + } + catch( IOException ex ) + { + throw new UncheckedIOException( ex ); + } + } + @Override public Function toJsonFunction( Options options ) { @@ -83,7 +127,8 @@ public class JavaxJsonSerializer extends AbstractTextSerializer implements JsonS JavaxJsonAdapter adapter = adapters.adapterFor( objectClass ); if( adapter != null ) { - return adapter.serialize( object, obj -> doSerialize( options, obj, false ) ); + return adapter.serialize( jsonFactories.builderFactory(), object, + obj -> doSerialize( options, obj, false ) ); } if( ValueCompositeType.isValueComposite( objectClass ) ) { @@ -117,7 +162,7 @@ public class JavaxJsonSerializer extends AbstractTextSerializer implements JsonS AssociationStateHolder state = (AssociationStateHolder) instance.state(); ValueCompositeType valueType = descriptor.valueType(); - JsonObjectBuilder builder = Json.createObjectBuilder(); + JsonObjectBuilder builder = jsonFactories.builderFactory().createObjectBuilder(); valueType.properties().forEach( property -> builder.add( property.qualifiedName().name(), @@ -148,7 +193,7 @@ public class JavaxJsonSerializer extends AbstractTextSerializer implements JsonS private JsonObjectBuilder withTypeInfo( JsonObjectBuilder builder, ValueType valueType ) { - return builder.add( getTypeInfoPropertyName(), valueType.primaryType().getName() ); + return builder.add( settings.getTypeInfoPropertyName(), valueType.primaryType().getName() ); } /** @@ -163,26 +208,26 @@ public class JavaxJsonSerializer extends AbstractTextSerializer implements JsonS if( map.isEmpty() ) { // Defaults to {} - return Json.createObjectBuilder().build(); + return jsonFactories.builderFactory().createObjectBuilder().build(); } Predicate characterKeyPredicate = key -> key != null && ( key instanceof CharSequence || key instanceof Character ); if( map.keySet().stream().allMatch( characterKeyPredicate ) ) { - JsonObjectBuilder builder = Json.createObjectBuilder(); + JsonObjectBuilder builder = jsonFactories.builderFactory().createObjectBuilder(); map.entrySet().forEach( entry -> builder.add( entry.getKey().toString(), doSerialize( options, entry.getValue(), false ) ) ); return builder.build(); } else { - JsonArrayBuilder builder = Json.createArrayBuilder(); + JsonArrayBuilder builder = jsonFactories.builderFactory().createArrayBuilder(); map.entrySet().forEach( entry -> builder.add( - Json.createObjectBuilder() - .add( "key", doSerialize( options, entry.getKey(), false ) ) - .add( "value", doSerialize( options, entry.getValue(), false ) ) - .build() ) ); + jsonFactories.builderFactory().createObjectBuilder() + .add( "key", doSerialize( options, entry.getKey(), false ) ) + .add( "value", doSerialize( options, entry.getValue(), false ) ) + .build() ) ); return builder.build(); } } @@ -209,14 +254,8 @@ public class JavaxJsonSerializer extends AbstractTextSerializer implements JsonS private JsonArray serializeStream( Options options, Stream stream ) { - JsonArrayBuilder builder = Json.createArrayBuilder(); + JsonArrayBuilder builder = jsonFactories.builderFactory().createArrayBuilder(); stream.forEach( element -> builder.add( doSerialize( options, element, false ) ) ); return builder.build(); } - - private String getTypeInfoPropertyName() - { - return JavaxJsonSettings.orDefault( descriptor.metaInfo( JavaxJsonSettings.class ) ) - .getTypeInfoPropertyName(); - } } http://git-wip-us.apache.org/repos/asf/polygene-java/blob/b1a3dbe7/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonSettings.java ---------------------------------------------------------------------- diff --git a/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonSettings.java b/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonSettings.java index 7042638..de5c27f 100644 --- a/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonSettings.java +++ b/core/spi/src/main/java/org/apache/polygene/serialization/javaxjson/JavaxJsonSettings.java @@ -31,6 +31,7 @@ public class JavaxJsonSettings extends SerializationSettings return settings != null ? settings : DEFAULT; } + private String jsonProviderClassName; private String typeInfoPropertyName; private Map> adapters; @@ -40,6 +41,16 @@ public class JavaxJsonSettings extends SerializationSettings adapters = new LinkedHashMap<>(); } + public String getJsonProviderClassName() + { + return jsonProviderClassName; + } + + public void setJsonProviderClassName( String jsonProviderClassName ) + { + this.jsonProviderClassName = jsonProviderClassName; + } + public String getTypeInfoPropertyName() { return typeInfoPropertyName; http://git-wip-us.apache.org/repos/asf/polygene-java/blob/b1a3dbe7/core/spi/src/main/java/org/apache/polygene/spi/serialization/JsonDeserializer.java ---------------------------------------------------------------------- diff --git a/core/spi/src/main/java/org/apache/polygene/spi/serialization/JsonDeserializer.java b/core/spi/src/main/java/org/apache/polygene/spi/serialization/JsonDeserializer.java index 30060ef..fdec10c 100644 --- a/core/spi/src/main/java/org/apache/polygene/spi/serialization/JsonDeserializer.java +++ b/core/spi/src/main/java/org/apache/polygene/spi/serialization/JsonDeserializer.java @@ -17,28 +17,15 @@ */ package org.apache.polygene.spi.serialization; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.Reader; -import java.io.StringReader; -import java.io.UncheckedIOException; import java.util.function.Function; import java.util.stream.Stream; import java.util.stream.StreamSupport; -import javax.json.Json; -import javax.json.JsonObject; -import javax.json.JsonReader; import javax.json.JsonValue; -import javax.json.stream.JsonParser; -import javax.json.stream.JsonParsingException; import org.apache.polygene.api.serialization.Deserializer; import org.apache.polygene.api.structure.ModuleDescriptor; import org.apache.polygene.api.type.ValueType; -import org.apache.polygene.serialization.javaxjson.JavaxJson; import org.apache.polygene.spi.module.ModuleSpi; -import static java.util.stream.Collectors.joining; - /** * {@literal javax.json} deserializer. */ @@ -92,75 +79,4 @@ public interface JsonDeserializer extends Deserializer { return fromJsonEach( module, valueType, Stream.of( states ) ); } - - @Override - default T deserialize( ModuleDescriptor module, ValueType valueType, Reader state ) - { - // JSR-353 Does not allow reading "out of structure" values - // See https://www.jcp.org/en/jsr/detail?id=353 - // And commented JsonReader#readValue() method in the javax.json API - // BUT, it will be part of the JsonReader contract in the next version - // See https://www.jcp.org/en/jsr/detail?id=374 - // Implementation by provider is optional though, so we'll always need a default implementation here. - // Fortunately, JsonParser has new methods allowing to read structures while parsing so it will be easy to do. - // In the meantime, a poor man's implementation reading the json into memory will do. - // TODO Revisit values out of structure JSON deserialization when JSR-374 is out - String stateString; - try( BufferedReader buffer = new BufferedReader( state ) ) - { - stateString = buffer.lines().collect( joining( "\n" ) ); - } - catch( IOException ex ) - { - throw new UncheckedIOException( ex ); - } - // We want plain Strings, BigDecimals, BigIntegers to be deserialized even when unquoted - Function plainValueFunction = string -> - { - String poorMans = "{\"value\":" + string + "}"; - JsonObject poorMansJson = Json.createReader( new StringReader( poorMans ) ).readObject(); - JsonValue value = poorMansJson.get( "value" ); - return fromJson( module, valueType, value ); - }; - Function outOfStructureFunction = string -> - { - // Is this an unquoted plain value? - try - { - return plainValueFunction.apply( '"' + string + '"' ); - } - catch( JsonParsingException ex ) - { - return plainValueFunction.apply( string ); - } - }; - try( JsonParser parser = Json.createParser( new StringReader( stateString ) ) ) - { - if( parser.hasNext() ) - { - JsonParser.Event e = parser.next(); - switch( e ) - { - case VALUE_NULL: - return null; - case START_ARRAY: - case START_OBJECT: - // JSON Structure - try( JsonReader reader = Json.createReader( new StringReader( stateString ) ) ) - { - return fromJson( module, valueType, reader.read() ); - } - default: - // JSON Value out of structure - return outOfStructureFunction.apply( stateString ); - } - } - } - catch( JsonParsingException ex ) - { - return outOfStructureFunction.apply( stateString ); - } - // Empty state string? - return fromJson( module, valueType, JavaxJson.EMPTY_STRING ); - } } http://git-wip-us.apache.org/repos/asf/polygene-java/blob/b1a3dbe7/core/spi/src/main/java/org/apache/polygene/spi/serialization/JsonSerializer.java ---------------------------------------------------------------------- diff --git a/core/spi/src/main/java/org/apache/polygene/spi/serialization/JsonSerializer.java b/core/spi/src/main/java/org/apache/polygene/spi/serialization/JsonSerializer.java index 9ec1863..956b591 100644 --- a/core/spi/src/main/java/org/apache/polygene/spi/serialization/JsonSerializer.java +++ b/core/spi/src/main/java/org/apache/polygene/spi/serialization/JsonSerializer.java @@ -17,13 +17,9 @@ */ package org.apache.polygene.spi.serialization; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.io.Writer; import java.util.function.Function; import java.util.stream.Stream; import java.util.stream.StreamSupport; -import javax.json.JsonString; import javax.json.JsonValue; import org.apache.polygene.api.common.Optional; import org.apache.polygene.api.serialization.Serializer; @@ -79,30 +75,4 @@ public interface JsonSerializer extends Serializer { return toJsonEach( Options.DEFAULT, Stream.of( objects ) ); } - - default void serialize( Options options, Writer writer, @Optional Object object ) - { - JsonValue jsonValue = toJson( options, object ); - if( jsonValue == null ) - { - return; - } - try - { - // We want plain Strings to be serialized without quotes which is non JSON compliant - // See https://java.net/jira/browse/JSON_PROCESSING_SPEC-65 - if( jsonValue.getValueType() == JsonValue.ValueType.STRING ) - { - writer.write( ( (JsonString) jsonValue ).getString() ); - } - else - { - writer.write( jsonValue.toString() ); - } - } - catch( IOException ex ) - { - throw new UncheckedIOException( ex ); - } - } } http://git-wip-us.apache.org/repos/asf/polygene-java/blob/b1a3dbe7/extensions/serialization-javaxjson/src/test/java/org/apache/polygene/serialization/javaxjson/CustomJsonAdapterTest.java ---------------------------------------------------------------------- diff --git a/extensions/serialization-javaxjson/src/test/java/org/apache/polygene/serialization/javaxjson/CustomJsonAdapterTest.java b/extensions/serialization-javaxjson/src/test/java/org/apache/polygene/serialization/javaxjson/CustomJsonAdapterTest.java index c03c3a8..57ad62b 100644 --- a/extensions/serialization-javaxjson/src/test/java/org/apache/polygene/serialization/javaxjson/CustomJsonAdapterTest.java +++ b/extensions/serialization-javaxjson/src/test/java/org/apache/polygene/serialization/javaxjson/CustomJsonAdapterTest.java @@ -20,7 +20,7 @@ package org.apache.polygene.serialization.javaxjson; import java.time.LocalDate; import java.util.function.BiFunction; import java.util.function.Function; -import javax.json.Json; +import javax.json.JsonBuilderFactory; import javax.json.JsonObject; import javax.json.JsonString; import javax.json.JsonValue; @@ -86,8 +86,10 @@ public class CustomJsonAdapterTest extends AbstractPolygeneTest public Class type() { return CustomValue.class; } @Override - public JsonValue serialize( Object object, Function serialize ) + public JsonValue serialize( JsonBuilderFactory builderFactory, + Object object, Function serialize ) { + // TODO FUCK JSON return JavaxJson.toJsonString( type().cast( object ).state ); } @@ -110,13 +112,14 @@ public class CustomJsonAdapterTest extends AbstractPolygeneTest public Class type() { return CustomStructure.class; } @Override - public JsonValue serialize( Object object, Function serialize ) + public JsonValue serialize( JsonBuilderFactory builderFactory, + Object object, Function serialize ) { CustomStructure customStructure = type().cast( object ); - return Json.createObjectBuilder() - .add( "foo", customStructure.foo ) - .add( "bar", serialize.apply( customStructure.bar ) ) - .build(); + return builderFactory.createObjectBuilder() + .add( "foo", customStructure.foo ) + .add( "bar", serialize.apply( customStructure.bar ) ) + .build(); } @Override http://git-wip-us.apache.org/repos/asf/polygene-java/blob/b1a3dbe7/extensions/serialization-javaxjson/src/test/java/org/apache/polygene/serialization/javaxjson/HandCraftedJsonTest.java ---------------------------------------------------------------------- diff --git a/extensions/serialization-javaxjson/src/test/java/org/apache/polygene/serialization/javaxjson/HandCraftedJsonTest.java b/extensions/serialization-javaxjson/src/test/java/org/apache/polygene/serialization/javaxjson/HandCraftedJsonTest.java index 2181b6b..18ad8ff 100644 --- a/extensions/serialization-javaxjson/src/test/java/org/apache/polygene/serialization/javaxjson/HandCraftedJsonTest.java +++ b/extensions/serialization-javaxjson/src/test/java/org/apache/polygene/serialization/javaxjson/HandCraftedJsonTest.java @@ -63,8 +63,6 @@ public class HandCraftedJsonTest extends AbstractPolygeneTest } @Test - @NotYetImplemented( reason = "need to manage javax.json providers and properties first, could work with Johnzon" ) - // See org.apache.johnzon.supports-comments public void canReadCommentedJson() { String json = "// One comment\n { \n\t\"foo\" : \"bar\" \n/* Two comments */ }\n ";