http://git-wip-us.apache.org/repos/asf/polygene-java/blob/17b11697/core/spi/src/main/java/org/apache/polygene/spi/type/ValueTypeFactory.java ---------------------------------------------------------------------- diff --git a/core/spi/src/main/java/org/apache/polygene/spi/type/ValueTypeFactory.java b/core/spi/src/main/java/org/apache/polygene/spi/type/ValueTypeFactory.java new file mode 100644 index 0000000..73f79eb --- /dev/null +++ b/core/spi/src/main/java/org/apache/polygene/spi/type/ValueTypeFactory.java @@ -0,0 +1,11 @@ +package org.apache.polygene.spi.type; + +import org.apache.polygene.api.structure.ModuleDescriptor; +import org.apache.polygene.api.type.ValueType; + +public interface ValueTypeFactory +{ + ValueType valueTypeOf( ModuleDescriptor module, Object object ); + + ValueType valueTypeOf( ModuleDescriptor module, Class<?> type ); +}
http://git-wip-us.apache.org/repos/asf/polygene-java/blob/17b11697/core/spi/src/main/java/org/apache/polygene/spi/value/ValueDeserializerAdapter.java ---------------------------------------------------------------------- diff --git a/core/spi/src/main/java/org/apache/polygene/spi/value/ValueDeserializerAdapter.java b/core/spi/src/main/java/org/apache/polygene/spi/value/ValueDeserializerAdapter.java deleted file mode 100644 index c586498..0000000 --- a/core/spi/src/main/java/org/apache/polygene/spi/value/ValueDeserializerAdapter.java +++ /dev/null @@ -1,1001 +0,0 @@ -/* - * 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.spi.value; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.time.Duration; -import java.time.Instant; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.OffsetDateTime; -import java.time.Period; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.Base64; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Scanner; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; -import org.apache.polygene.api.entity.EntityReference; -import org.apache.polygene.api.identity.Identity; -import org.apache.polygene.api.identity.StringIdentity; -import org.apache.polygene.api.property.Property; -import org.apache.polygene.api.structure.ModuleDescriptor; -import org.apache.polygene.api.type.CollectionType; -import org.apache.polygene.api.type.EnumType; -import org.apache.polygene.api.type.MapType; -import org.apache.polygene.api.type.Serialization; -import org.apache.polygene.api.type.ValueCompositeType; -import org.apache.polygene.api.type.ValueType; -import org.apache.polygene.api.value.ValueBuilder; -import org.apache.polygene.api.value.ValueDescriptor; -import org.apache.polygene.api.value.ValueDeserializer; -import org.apache.polygene.api.value.ValueSerializationException; - -/** - * Adapter for pull-parsing and tree-parsing capable ValueDeserializers. - * - * <p> - * Among Plain values (see {@link ValueDeserializer}) some are considered primitives to underlying serialization - * mechanisms and by so handed/come without conversion to/from implementations. Primitive values can be one of: - * </p> - * <ul> - * <li>String,</li> - * <li>Character or char,</li> - * <li>Boolean or boolean,</li> - * <li>Integer or int,</li> - * <li>Long or long,</li> - * <li>Short or short,</li> - * <li>Byte or byte,</li> - * <li>Float or float,</li> - * <li>Double or double.</li> - * </ul> - * <p> - * Some other Plain values are expected in given formats: - * </p> - * <ul> - * <li>BigInteger and BigDecimal depends on {@link org.apache.polygene.api.value.ValueSerializer.Options};</li> - * <li>Date as String in ISO-8601, {@literal @millis@} or {@literal /Date(..)} Microsoft format;</li> - * <li>DateTime (JodaTime) as a ISO-8601 String with optional timezone offset;</li> - * <li>LocalDateTime (JodaTime) as whatever {@link LocalDateTime#parse} accept as {@literal instant};</li> - * <li>LocalDate (JodaTime) as whatever {@link LocalDate#parse} accept as {@literal instant};</li> - * </ul> - * - * @param <InputType> Implementor pull-parser type - * @param <InputNodeType> Implementor tree-parser node type - */ -public abstract class ValueDeserializerAdapter<InputType, InputNodeType> - implements ValueDeserializer -{ - public interface ComplexDeserializer<T, InputType, InputNodeType> - { - T deserializePull( InputType input ) - throws Exception; - - T deserializeTree( InputNodeType inputNode ) - throws Exception; - } - - private static final String UTF_8 = "UTF-8"; - private final Map<Class<?>, Function<Object, Object>> deserializers = new HashMap<>( 16 ); - private final Map<Class<?>, ComplexDeserializer<Object, InputType, InputNodeType>> complexDeserializers = new HashMap<>( 2 ); - - /** - * Register a Plain Value type deserialization Function. - * - * @param <T> Plain Value parametrized Type - * @param type Plain Value Type - * @param deserializer Deserialization Function - */ - @SuppressWarnings( "unchecked" ) - protected final <T> void registerDeserializer( Class<T> type, Function<Object, T> deserializer ) - { - deserializers.put( type, (Function<Object, Object>) deserializer ); - } - - @SuppressWarnings( { "UnusedDeclaration", "unchecked" } ) - protected final <T> void registerComplexDeserializer( Class<T> type, - ComplexDeserializer<T, InputType, InputNodeType> deserializer - ) - { - complexDeserializers.put( type, (ComplexDeserializer<Object, InputType, InputNodeType>) deserializer ); - } - - protected ValueDeserializerAdapter() - { - - // Primitive Value types - registerDeserializer( String.class, Object::toString ); - registerDeserializer( Character.class, input -> input.toString().charAt( 0 ) ); - registerDeserializer( Boolean.class, input -> ( input instanceof String ) - ? Boolean.parseBoolean( (String) input ) - : (Boolean) input ); - registerDeserializer( Integer.class, input -> ( input instanceof String ) - ? Integer.parseInt( (String) input ) - : ( (Number) input ).intValue() ); - registerDeserializer( Long.class, input -> ( input instanceof String ) - ? Long.parseLong( (String) input ) - : ( (Number) input ).longValue() ); - registerDeserializer( Short.class, input -> ( input instanceof String ) - ? Short.parseShort( (String) input ) - : ( (Number) input ).shortValue() ); - registerDeserializer( Byte.class, input -> ( input instanceof String ) - ? Byte.parseByte( (String) input ) - : ( (Number) input ).byteValue() ); - registerDeserializer( Float.class, input -> ( input instanceof String ) - ? Float.parseFloat( (String) input ) - : ( (Number) input ).floatValue() ); - registerDeserializer( Double.class, input -> ( input instanceof String ) - ? Double.parseDouble( (String) input ) - : ( (Number) input ).doubleValue() ); - - // Number types - registerDeserializer( BigDecimal.class, input -> new BigDecimal( input.toString() ) ); - registerDeserializer( BigInteger.class, input -> new BigInteger( input.toString() ) ); - registerDeserializer( Identity.class, input -> StringIdentity.fromString( input.toString() ) ); - - // Date types - registerDeserializer( Instant.class, input -> Instant.parse( input.toString() ) ); - registerDeserializer( ZonedDateTime.class, input -> ZonedDateTime.parse( input.toString() ) ); - registerDeserializer( OffsetDateTime.class, input -> OffsetDateTime.parse( input.toString() ) ); - registerDeserializer( LocalDateTime.class, input -> LocalDateTime.parse( input.toString() ) ); - registerDeserializer( LocalDate.class, input -> LocalDate.parse( input.toString() )); - registerDeserializer( LocalTime.class, input -> LocalTime.parse( input.toString() )); - registerDeserializer( Duration.class, input -> Duration.parse( input.toString() )); - registerDeserializer( Period.class, input -> Period.parse( input.toString() )); - - // Other supported types - registerDeserializer( EntityReference.class, input -> EntityReference.parseEntityReference( input.toString() ) ); - } - - @Override - public <T> Function<String, T> deserialize( ModuleDescriptor module, Class<T> type ) - { - if( CollectionType.isCollection( type ) ) - { - ValueType objectValueType = new ValueType( Object.class ); - return deserialize( module, new CollectionType( type, objectValueType ) ); - } - if( MapType.isMap( type ) ) - { - ValueType objectValueType = new ValueType( Object.class ); - return deserialize( module, new MapType( type, objectValueType, objectValueType ) ); - } - return deserialize( module, new ValueType( type ) ); - } - - @Override - public final <T> Function<String, T> deserialize( ModuleDescriptor module, ValueType valueType ) - { - return input -> deserialize( module, valueType, input ); - } - - @Override - public final <T> T deserialize( ModuleDescriptor module, Class<?> type, String input ) - throws ValueSerializationException - { - if( CollectionType.isCollection( type ) ) - { - ValueType objectValueType = new ValueType( Object.class ); - return deserialize( module, new CollectionType( type, objectValueType ), input ); - } - if( MapType.isMap( type ) ) - { - ValueType objectValueType = new ValueType( Object.class ); - return deserialize( module, new MapType( type, objectValueType, objectValueType ), input ); - } - return deserialize( module, new ValueType( type ), input ); - } - - @Override - public final <T> T deserialize( ModuleDescriptor module, ValueType valueType, String input ) - throws ValueSerializationException - { - try - { - return deserializeRoot( module, valueType, new ByteArrayInputStream( input.getBytes( UTF_8 ) ) ); - } - catch( ValueSerializationException ex ) - { - throw ex; - } - catch( Exception ex ) - { - throw new ValueSerializationException( "Could not deserialize value", ex ); - } - } - - @Override - public final <T> T deserialize( ModuleDescriptor module, Class<?> type, InputStream input ) - throws ValueSerializationException - { - if( CollectionType.isCollection( type ) ) - { - ValueType objectValueType = new ValueType( Object.class ); - return deserialize( module, new CollectionType( type, objectValueType ), input ); - } - if( MapType.isMap( type ) ) - { - ValueType objectValueType = new ValueType( Object.class ); - return deserialize( module, new MapType( type, objectValueType, objectValueType ), input ); - } - return deserialize( module, new ValueType( type ), input ); - } - - @Override - public final <T> T deserialize( ModuleDescriptor module, ValueType valueType, InputStream input ) - throws ValueSerializationException - { - try - { - return deserializeRoot( module, valueType, input ); - } - catch( ValueSerializationException ex ) - { - throw ex; - } - catch( Exception ex ) - { - throw new ValueSerializationException( "Could not deserialize value", ex ); - } - } - - @SuppressWarnings( "unchecked" ) - private <T> T deserializeRoot( ModuleDescriptor module, ValueType valueType, InputStream input ) - throws Exception - { - Class<?> type = valueType.types().findFirst().orElse( null ); - - if( Identity.class.isAssignableFrom( type ) ) - { - type = Identity.class; - } - - // Plain ValueType - Function<Object, Object> deserializationFunction = deserializers.get( type ); - if( deserializationFunction != null ) - { - Scanner scanner = new Scanner( input, UTF_8 ).useDelimiter( "\\A" ); - if( !scanner.hasNext() ) - { - return String.class.equals( type ) ? (T) "" : null; - } - String string = scanner.next(); - return (T) deserializationFunction.apply( string ); - } - else // Array ValueType - if( type.isArray() ) - { - Scanner scanner = new Scanner( input, UTF_8 ).useDelimiter( "\\A" ); - if( !scanner.hasNext() ) - { - return null; - } - String string = scanner.next(); - return (T) deserializeBase64Serialized( module, string ); - } - else if( type.isEnum() ) - { - Scanner scanner = new Scanner( input, UTF_8 ).useDelimiter( "\\A" ); - if( !scanner.hasNext() ) - { - return String.class.equals( type ) ? (T) "" : null; - } - String string = scanner.next(); - return (T) Enum.valueOf( (Class) type, string ); - } - else // Complex ValueType - { - InputType adaptedInput = adaptInput( module, input ); - onDeserializationStart( module, valueType, adaptedInput ); - T deserialized = doDeserialize( module, valueType, adaptedInput ); - onDeserializationEnd( module, valueType, adaptedInput ); - return deserialized; - } - } - - @SuppressWarnings( "unchecked" ) - private <T> T doDeserialize( ModuleDescriptor module, ValueType valueType, InputType input ) - throws Exception - { - final Class<?> type = valueType.types().findFirst().orElse( null ); - // Registered deserializers - if( deserializers.get( type ) != null ) - { - Object value = readPlainValue( module, input ); - if( value == null ) - { - return null; - } - return (T) deserializers.get( type ).apply( value ); - } - else if( complexDeserializers.get( type ) != null ) - { - return (T) complexDeserializers.get( type ).deserializePull( input ); - } - else // Explicit ValueComposite - if( ValueCompositeType.class.isAssignableFrom( valueType.getClass() ) ) - { - return (T) deserializeValueComposite( module, valueType, input ); - } - else // Explicit Collections - if( CollectionType.class.isAssignableFrom( valueType.getClass() ) ) - { - return (T) deserializeCollection( module, (CollectionType) valueType, input ); - } - else // Explicit Map - if( MapType.class.isAssignableFrom( valueType.getClass() ) ) - { - return (T) deserializeMap( module, (MapType) valueType, input ); - } - else // Enum - if( EnumType.class.isAssignableFrom( valueType.getClass() ) || type.isEnum() ) - { - return (T) Enum.valueOf( (Class) type, readPlainValue( module, input ).toString() ); - } - else // Array - if( type.isArray() ) - { - return (T) deserializeBase64Serialized( module, readPlainValue( module, input ).toString() ); - } - // Guessed Deserialization - return (T) deserializeGuessed( module, valueType, input ); - } - - private <T> Function<InputType, T> buildDeserializeInputFunction( ModuleDescriptor module, ValueType valueType ) - { - return input -> { - try - { - return doDeserialize( module, valueType, input ); - } - catch( ValueSerializationException ex ) - { - throw ex; - } - catch( Exception ex ) - { - throw new ValueSerializationException( ex ); - } - }; - } - - private <T> Collection<T> deserializeCollection( ModuleDescriptor module, CollectionType collectionType, InputType input ) - throws Exception - { - Collection<T> collection; - Class<?> collectionMainType = collectionType.types().findFirst().orElse( null ); - if( Set.class.equals( collectionMainType ) ) - { - collection = new LinkedHashSet<>(); - } - else - { - collection = new ArrayList<>(); - } - return readArrayInCollection( module, - input, - this.buildDeserializeInputFunction( module, collectionType.collectedType() ), - collection ); - } - - private <K, V> Map<K, V> deserializeMap( ModuleDescriptor module, MapType mapType, InputType input ) - throws Exception - { - return readMapInMap( module, - input, - this.<K>buildDeserializeInputFunction( module, mapType.keyType() ), - this.<V>buildDeserializeInputFunction( module, mapType.valueType() ), - new HashMap<>() ); - } - - private <T> T deserializeValueComposite( ModuleDescriptor module, ValueType valueType, InputType input ) - throws Exception - { - InputNodeType inputNode = readObjectTree( module, input ); - if( inputNode == null ) - { - return null; - } - return deserializeNodeValueComposite( module, valueType, inputNode ); - } - - private <T> T deserializeNodeValueComposite( ModuleDescriptor module, ValueType valueType, InputNodeType inputNode ) - throws Exception - { - ValueCompositeType valueCompositeType = (ValueCompositeType) valueType; - Class<?> valueBuilderType = valueCompositeType.types().findFirst().orElse( null ); - String typeInfo = this.getObjectFieldValue( - module, - inputNode, - "_type", - this.<String>buildDeserializeInputNodeFunction( module, new ValueType( String.class ) ) ); - if( typeInfo != null ) - { - ValueDescriptor valueDescriptor = module.valueDescriptor( typeInfo ); - if( valueDescriptor == null ) - { - throw new ValueSerializationException( "Specified value type could not be resolved: " + typeInfo ); - } - valueCompositeType = valueDescriptor.valueType(); - valueBuilderType = Class.forName( typeInfo ); - } - return deserializeValueComposite( module, valueCompositeType, valueBuilderType, inputNode ); - } - - @SuppressWarnings( "unchecked" ) - private <T> T deserializeValueComposite( ModuleDescriptor module, - ValueCompositeType valueCompositeType, - Class<?> valueBuilderType, - InputNodeType inputNode - ) - throws Exception - { - final Map<String, Object> stateMap = new HashMap<>(); - - // Properties - valueCompositeType.properties().forEach( propertyDescriptor -> { - String propertyName = null; - Object value; - try - { - propertyName = propertyDescriptor.qualifiedName().name(); - if( objectHasField( module, inputNode, propertyName ) ) - { - value = getObjectFieldValue( - module, - inputNode, - propertyName, - buildDeserializeInputNodeFunction( module, propertyDescriptor.valueType() ) ); - if( propertyDescriptor.isImmutable() ) - { - if( value instanceof Set ) - { - value = Collections.unmodifiableSet( (Set<?>) value ); - } - else if( value instanceof List ) - { - value = Collections.unmodifiableList( (List<?>) value ); - } - else if( value instanceof Map ) - { - value = Collections.unmodifiableMap( (Map<?, ?>) value ); - } - } - } - else - { - // Serialized object does not contain the field, try to default it - value = propertyDescriptor.resolveInitialValue(module); - } - } - catch( Exception e ) - { - throw new ValueSerializationException( "Unable to deserialize property " + propertyDescriptor, e ); - } - stateMap.put( propertyName, value ); - } ); - - // Associations - valueCompositeType.associations().forEach( association -> { - try - { - String associationName = association.qualifiedName().name(); - if( objectHasField( module, inputNode, associationName ) ) - { - Object value = getObjectFieldValue( - module, - inputNode, - associationName, - buildDeserializeInputNodeFunction( module, new ValueType( EntityReference.class ) ) ); - stateMap.put( associationName, value ); - } - } - catch( Exception e ) - { - throw new ValueSerializationException( "Unable to deserialize association " + association, e ); - } - } ); - - // ManyAssociations - valueCompositeType.manyAssociations().forEach( manyAssociation -> { - try - { - String manyAssociationName = manyAssociation.qualifiedName().name(); - if( objectHasField( module, inputNode, manyAssociationName ) ) - { - Object value = getObjectFieldValue( - module, - inputNode, - manyAssociationName, - buildDeserializeInputNodeFunction( - module, - new CollectionType( - Collection.class, - new ValueType( EntityReference.class ) ) ) ); - stateMap.put( manyAssociationName, value ); - } - } - catch( Exception e ) - { - throw new ValueSerializationException( "Unable to deserialize manyassociation " + manyAssociation, e ); - } - } ); - - // NamedAssociations - valueCompositeType.namedAssociations().forEach( namedAssociation -> { - try - { - String namedAssociationName = namedAssociation.qualifiedName().name(); - if( objectHasField( module, inputNode, namedAssociationName ) ) - { - Object value = getObjectFieldValue( - module, - inputNode, - namedAssociationName, - buildDeserializeInputNodeFunction( module, MapType.of( String.class, EntityReference.class, Serialization.Variant.object ) ) ); - stateMap.put( namedAssociationName, value ); - } - } - catch( Exception e ) - { - throw new ValueSerializationException( "Unable to deserialize namedassociation " + namedAssociation, e ); - } - } ); - - ValueBuilder<?> valueBuilder = buildNewValueBuilderWithState( module, valueBuilderType, stateMap ); - return (T) valueBuilder.newInstance(); // Unchecked cast because the builder could use a type != T - } - - private <T> Function<InputNodeType, T> buildDeserializeInputNodeFunction( ModuleDescriptor module, final ValueType valueType ) - { - return inputNode -> { - try - { - return doDeserializeInputNodeValue( module, valueType, inputNode ); - } - catch( ValueSerializationException ex ) - { - throw ex; - } - catch( Exception ex ) - { - throw new ValueSerializationException( ex ); - } - }; - } - - @SuppressWarnings( "unchecked" ) - private <T> T doDeserializeInputNodeValue( ModuleDescriptor module, ValueType valueType, InputNodeType inputNode ) - throws Exception - { - if( inputNode == null ) - { - return null; - } - final Class<?> type = valueType.types().findFirst().orElse( null ); - // Registered deserializers - if( deserializers.get( type ) != null ) - { - Object value = asSimpleValue( module, inputNode ); - if( value == null ) - { - return null; - } - return (T) deserializers.get( type ).apply( value ); - } - else if( complexDeserializers.get( type ) != null ) - { - return (T) complexDeserializers.get( type ).deserializeTree( inputNode ); - } - else // Explicit ValueComposite - if( ValueCompositeType.class.isAssignableFrom( valueType.getClass() ) ) - { - return (T) deserializeNodeValueComposite( module, valueType, inputNode ); - } - else // Explicit Collections - if( CollectionType.class.isAssignableFrom( valueType.getClass() ) ) - { - return (T) deserializeNodeCollection( module, (CollectionType) valueType, inputNode ); - } - else // Explicit Map - if( MapType.class.isAssignableFrom( valueType.getClass() ) ) - { - MapType mapType = (MapType) valueType; - if( mapType.variant().equals( Serialization.Variant.entry ) ) - { - return (T) deserializeNodeEntryMap( module, (MapType) valueType, inputNode ); - } - else - { - return (T) deserializeNodeObjectMap( module, (MapType) valueType, inputNode ); - } - } - else // Enum - if( EnumType.class.isAssignableFrom( valueType.getClass() ) || type.isEnum() ) - { - Object value = asSimpleValue( module, inputNode ); - if( value == null ) - { - return null; - } - return (T) Enum.valueOf( (Class) type, value.toString() ); - } - // Guessed deserialization - return (T) deserializeNodeGuessed( module, valueType, inputNode ); - } - - private ValueBuilder<?> buildNewValueBuilderWithState( ModuleDescriptor module, - Class<?> type, - final Map<String, Object> stateMap - ) - { - return module.instance().newValueBuilderWithState( - type, - property -> stateMap.get( property.qualifiedName().name() ), - association -> { - Object entityRef = stateMap.get( association.qualifiedName().name() ); - if( entityRef == null ) - { - return null; - } - return (EntityReference) entityRef; - }, - manyAssociation -> { - Object entityRefs = stateMap.get( manyAssociation.qualifiedName().name() ); - if( entityRefs == null ) - { - return Stream.empty(); - } - //noinspection unchecked - return StreamSupport.stream( ( (Iterable<EntityReference>) entityRefs ).spliterator(), false ); - }, - namedAssociation -> { - Object entityRefs = stateMap.get( namedAssociation.qualifiedName().name() ); - if( entityRefs == null ) - { - return Stream.empty(); - } - //noinspection unchecked - return ( (Map<String, EntityReference>) entityRefs ).entrySet().stream(); - } ); - } - - @SuppressWarnings( "unchecked" ) - private <T> T deserializeGuessed( ModuleDescriptor module, ValueType valueType, InputType input ) - throws Exception - { - InputNodeType inputNode = readObjectTree( module, input ); - if( inputNode == null ) - { - return null; - } - return deserializeNodeGuessed( module, valueType, inputNode ); - } - - private <T> Collection<T> deserializeNodeCollection( ModuleDescriptor module, - CollectionType collectionType, - InputNodeType inputNode - ) - throws Exception - { - Collection<T> collection; - Class<?> collectionMainType = collectionType.types().findFirst().orElse( null ); - if( Set.class.equals( collectionMainType ) ) - { - collection = new LinkedHashSet<>(); - } - else - { - collection = new ArrayList<>(); - } - putArrayNodeInCollection( module, - inputNode, - this.buildDeserializeInputNodeFunction( module, collectionType.collectedType() ), - collection ); - return collection; - } - - private <K, V> Map<K, V> deserializeNodeEntryMap( ModuleDescriptor module, MapType mapType, InputNodeType inputNode ) - throws Exception - { - Map<K, V> map = new HashMap<>(); - putArrayNodeInMap( module, - inputNode, - this.buildDeserializeInputNodeFunction( module, mapType.keyType() ), - this.buildDeserializeInputNodeFunction( module, mapType.valueType() ), - map ); - return map; - } - - private <V> Map<String, V> deserializeNodeObjectMap( ModuleDescriptor module, MapType mapType, InputNodeType inputNode ) - throws Exception - { - Map<String, V> map = new HashMap<>(); - putObjectNodeInMap( module, - inputNode, - this.buildDeserializeInputNodeFunction( module, mapType.valueType() ), - map ); - return map; - } - - @SuppressWarnings( "unchecked" ) - private <T> T deserializeNodeGuessed( ModuleDescriptor module, ValueType valueType, InputNodeType inputNode ) - throws Exception - { - if( isObjectValue( module, inputNode ) ) - { - // Attempt ValueComposite deserialization - ValueCompositeType valueCompositeType; - if( objectHasField( module, inputNode, "_type" ) ) // with _type info - { - String typeInfo = this.getObjectFieldValue( - module, - inputNode, - "_type", - this.<String>buildDeserializeInputNodeFunction( module, new ValueType( String.class ) ) ); - ValueDescriptor valueDescriptor = module.valueDescriptor( typeInfo ); - if( valueDescriptor == null ) - { - throw new ValueSerializationException( "Specified value type could not be resolved: " + typeInfo ); - } - valueCompositeType = valueDescriptor.valueType(); - } - else // without _type info - { - ValueDescriptor valueDescriptor = module.valueDescriptor( valueType.types() - .findFirst() - .get() - .getName() ); - if( valueDescriptor == null ) - { - throw new ValueSerializationException( "Don't know how to deserialize " + inputNode ); - } - valueCompositeType = valueDescriptor.valueType(); - } - Class<?> valueBuilderType = valueCompositeType.types().findFirst().orElse( null ); - return deserializeValueComposite( module, valueCompositeType, valueBuilderType, inputNode ); - } - // Last resort : base64 java deserialization - return (T) deserializeBase64Serialized( module, inputNode ); - } - - @SuppressWarnings( "unchecked" ) - private <T> T deserializeBase64Serialized( ModuleDescriptor module, InputNodeType inputNode ) - throws Exception - { - Object value = asSimpleValue( module, inputNode ); - if( value == null ) - { - return null; - } - String base64 = value.toString(); - return deserializeBase64Serialized( module, base64 ); - } - - @SuppressWarnings( "unchecked" ) - private <T> T deserializeBase64Serialized( ModuleDescriptor module, String inputString ) - throws Exception - { - byte[] bytes = inputString.getBytes( UTF_8 ); - bytes = Base64.getDecoder().decode( bytes ); - Object result; - try (ObjectInputStream oin = new ObjectInputStream( new ByteArrayInputStream( bytes ) )) - { - result = oin.readObject(); - } - return (T) result; - } - - // - // Deserialization Extension Points - // - - /** - * Called by the adapter on deserialization start, after {@link #adaptInput(ModuleDescriptor, java.io.InputStream)}. - * - * @param module Module descriptor - * @param valueType ValueType - * @param input Input - * - * @throws Exception that will be wrapped in a {@link ValueSerializationException} - */ - @SuppressWarnings( "UnusedParameters" ) - protected void onDeserializationStart( ModuleDescriptor module, ValueType valueType, InputType input ) - throws Exception - { - // NOOP - } - - /** - * Called by the adapter on deserialization end. - * - * @param module Module descriptor - * @param valueType ValueType - * @param input Input - * - * @throws Exception that will be wrapped in a {@link ValueSerializationException} - */ - protected void onDeserializationEnd( ModuleDescriptor module, ValueType valueType, InputType input ) - throws Exception - { - // NOOP - } - - // - // Pull Parsing Deserialization - // - - /** - * This method is always called first, this is a chance to wrap the input type. - * - * @param module Module descriptor - * @param input InputStream to adapt - * - * @return Adapted input - * - * @throws Exception that will be wrapped in a {@link ValueSerializationException} - */ - protected abstract InputType adaptInput( ModuleDescriptor module, InputStream input ) - throws Exception; - - /** - * @param module Module descriptor - * @param input Input - * - * @return a Plain Value read from the input - * - * @throws Exception that will be wrapped in a {@link ValueSerializationException} - */ - protected abstract Object readPlainValue( ModuleDescriptor module, InputType input ) - throws Exception; - - /** - * @param module Module descriptor - * @param input Input - * @param deserializer Deserialization function - * @param collection Collection - * @param <T> Parameterized collection type - * - * @return The filled collection or null if no array - * - * @throws Exception that will be wrapped in a {@link ValueSerializationException} - */ - protected abstract <T> Collection<T> readArrayInCollection( ModuleDescriptor module, - InputType input, - Function<InputType, T> deserializer, - Collection<T> collection - ) - throws Exception; - - /** - * A Map<K,V> is serialized in an array of entries objects. - * - * <p>Here is an example in JSON:</p> - * <pre> - * [ - * { "key": "foo", "value": "bar" }, - * { "key": "cathedral", "value": "bazar" } - * ] - * </pre> - * <p>And an empty Map:</p> - * <pre>[]</pre> - * <p> - * This allow to use any type as keys and values while keeping the Map order at the cost of having - * non-predictible order of key/value inside an entry object. - * </p> - * - * @param module Module descriptor - * @param input Input - * @param keyDeserializer Map key deserialization function - * @param valueDeserializer Map value deserialization function - * @param map Map - * @param <K> Parameterized map key type - * @param <V> Parameterized map value type - * - * @return The filled map or null if no array - * - * @throws Exception that will be wrapped in a {@link ValueSerializationException} - */ - protected abstract <K, V> Map<K, V> readMapInMap( ModuleDescriptor module, - InputType input, - Function<InputType, K> keyDeserializer, - Function<InputType, V> valueDeserializer, - Map<K, V> map - ) - throws Exception; - - /** - * @param module Module descriptor - * @param input Input - * - * @return an InputNodeType or null if the value was null - * - * @throws Exception that will be wrapped in a {@link ValueSerializationException} - */ - protected abstract InputNodeType readObjectTree( ModuleDescriptor module, InputType input ) - throws Exception; - - // - // Tree Parsing Deserialization - // - protected abstract Object asSimpleValue( ModuleDescriptor module, InputNodeType inputNode ) - throws Exception; - - protected abstract boolean isObjectValue( ModuleDescriptor module, InputNodeType inputNode ) - throws Exception; - - protected abstract boolean objectHasField( ModuleDescriptor module, InputNodeType inputNode, String key ) - throws Exception; - - /** - * Return null if the field do not exists. - * - * @param module Module descriptor - * @param inputNode Input Node - * @param key Object key - * @param valueDeserializer Deserialization function - * @param <T> Parameterized object field value type - * - * @return The value of the field. - * - * @throws Exception that will be wrapped in a {@link ValueSerializationException} - */ - protected abstract <T> T getObjectFieldValue( ModuleDescriptor module, - InputNodeType inputNode, - String key, - Function<InputNodeType, T> valueDeserializer - ) - throws Exception; - - protected abstract <T> void putArrayNodeInCollection( ModuleDescriptor module, - InputNodeType inputNode, - Function<InputNodeType, T> deserializer, - Collection<T> collection - ) - throws Exception; - - protected abstract <K, V> void putArrayNodeInMap( ModuleDescriptor module, - InputNodeType inputNode, - Function<InputNodeType, K> keyDeserializer, - Function<InputNodeType, V> valueDeserializer, - Map<K, V> map - ) - throws Exception; - - protected abstract <V> void putObjectNodeInMap( ModuleDescriptor module, - InputNodeType inputNode, - Function<InputNodeType, V> valueDeserializer, - Map<String, V> map - ) - throws Exception; -} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/17b11697/core/spi/src/main/java/org/apache/polygene/spi/value/ValueSerializerAdapter.java ---------------------------------------------------------------------- diff --git a/core/spi/src/main/java/org/apache/polygene/spi/value/ValueSerializerAdapter.java b/core/spi/src/main/java/org/apache/polygene/spi/value/ValueSerializerAdapter.java deleted file mode 100644 index e9313b5..0000000 --- a/core/spi/src/main/java/org/apache/polygene/spi/value/ValueSerializerAdapter.java +++ /dev/null @@ -1,570 +0,0 @@ -/* - * 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.spi.value; - -import java.io.ByteArrayOutputStream; -import java.io.ObjectOutputStream; -import java.io.OutputStream; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.time.Duration; -import java.time.Instant; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.OffsetDateTime; -import java.time.Period; -import java.time.ZonedDateTime; -import java.util.Base64; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.function.BiFunction; -import java.util.function.Function; -import org.apache.polygene.api.PolygeneAPI; -import org.apache.polygene.api.association.Association; -import org.apache.polygene.api.association.AssociationStateHolder; -import org.apache.polygene.api.association.ManyAssociation; -import org.apache.polygene.api.association.NamedAssociation; -import org.apache.polygene.api.composite.CompositeInstance; -import org.apache.polygene.api.entity.EntityComposite; -import org.apache.polygene.api.entity.EntityReference; -import org.apache.polygene.api.identity.Identity; -import org.apache.polygene.api.property.Property; -import org.apache.polygene.api.value.ValueComposite; -import org.apache.polygene.api.value.ValueDescriptor; -import org.apache.polygene.api.value.ValueSerializationException; -import org.apache.polygene.api.value.ValueSerializer; - -/** - * Adapter for pull-parsing capable ValueSerializers. - * - * <p> - * Among Plain values (see {@link ValueSerializer}) some are considered primitives to underlying serialization - * mechanisms and by so handed/come without conversion to/from implementations. Primitive values can be one of: - * </p> - * <ul> - * <li>String,</li> - * <li>Character or char,</li> - * <li>Boolean or boolean,</li> - * <li>Integer or int,</li> - * <li>Long or long,</li> - * <li>Short or short,</li> - * <li>Byte or byte,</li> - * <li>Float or float,</li> - * <li>Double or double.</li> - * </ul> - * <p> - * Some other Plain values are transformed before being handed to implementations: - * </p> - * <ul> - * <li>BigInteger and BigDecimal depends on ValueSerializer.{@link org.apache.polygene.api.value.ValueSerializer.Options};</li> - * <li>Date as a ISO-8601 UTC String;</li> - * <li>DateTime (JodaTime) as a ISO-8601 String with timezone offset or Z for UTC;</li> - * <li>LocalDateTime (JodaTime) as a ISO-8601 String with no timezone offset;</li> - * <li>LocalDate (JodaTime) as a ISO-8601 String with no time info;</li> - * </ul> - * - * @param <OutputType> Implementor output type - */ -public abstract class ValueSerializerAdapter<OutputType> - implements ValueSerializer -{ - - public interface ComplexSerializer<T, OutputType> - { - void serialize( Options options, T object, OutputType output ) - throws Exception; - } - - private static final String UTF_8 = "UTF-8"; - - private static <TO, FROM extends TO> BiFunction<Options, FROM, TO> identitySerializer() - { - return ( options, from ) -> from; - } - - private final Map<Class<?>, BiFunction<Options, Object, Object>> serializers = new HashMap<>( 16 ); - private final Map<Class<?>, ComplexSerializer<Object, OutputType>> complexSerializers = new HashMap<>( 2 ); - - /** - * Register a Plain Value type serialization Function. - * - * @param <T> Plain Value parametrized Type - * @param type Plain Value Type - * @param serializer Serialization Function - */ - @SuppressWarnings( "unchecked" ) - protected final <T> void registerSerializer( Class<T> type, BiFunction<Options, T, Object> serializer ) - { - serializers.put( type, (BiFunction<Options, Object, Object>) serializer ); - } - - /** - * Register a Complex Value type serialization Function. - * - * @param <T> Complex Value parametrized Type - * @param type Complex Value Type - * @param serializer Serialization Function - */ - @SuppressWarnings( "unchecked" ) - protected final <T> void registerComplexSerializer( Class<T> type, ComplexSerializer<T, OutputType> serializer ) - { - complexSerializers.put( type, (ComplexSerializer<Object, OutputType>) serializer ); - } - - public ValueSerializerAdapter() - { - // Primitive Value types - registerSerializer( String.class, ValueSerializerAdapter.identitySerializer() ); - registerSerializer( Character.class, ValueSerializerAdapter.identitySerializer() ); - registerSerializer( Boolean.class, ValueSerializerAdapter.identitySerializer() ); - registerSerializer( Integer.class, ValueSerializerAdapter.identitySerializer() ); - registerSerializer( Long.class, ValueSerializerAdapter.identitySerializer() ); - registerSerializer( Short.class, ValueSerializerAdapter.identitySerializer() ); - registerSerializer( Byte.class, ValueSerializerAdapter.identitySerializer() ); - registerSerializer( Float.class, ValueSerializerAdapter.identitySerializer() ); - registerSerializer( Double.class, ValueSerializerAdapter.identitySerializer() ); - - // Number types - registerSerializer( BigDecimal.class, ( options, bigDecimal ) -> bigDecimal.toString() ); - registerSerializer( BigInteger.class, ( options, bigInteger ) -> bigInteger.toString() ); - registerSerializer( Identity.class, ( options, identity ) -> identity.toString() ); - - // Date types - registerSerializer( Instant.class, ( options, date ) -> date.toString() ); - registerSerializer( Duration.class, ( options, date ) -> date.toString() ); - registerSerializer( Period.class, ( options, date ) -> date.toString() ); - registerSerializer( ZonedDateTime.class, ( options, date ) -> date.toString() ); - registerSerializer( OffsetDateTime.class, ( options, date ) -> date.toString() ); - registerSerializer( LocalDateTime.class, ( options, date ) -> date.toString() ); - registerSerializer( LocalDate.class, ( options, date ) -> date.toString() ); - registerSerializer( LocalTime.class, ( options, date ) -> date.toString() ); - - // Other supported types - registerSerializer( EntityReference.class, ( options, ref ) -> ref.toString() ); - } - - @Override - public final <T> Function<T, String> serialize() - { - return this::serialize; - } - - @Override - public final <T> Function<T, String> serialize( final Options options ) - { - return object -> serialize( options, object ); - } - - @Override - public final String serialize( Object object ) - throws ValueSerializationException - { - return serialize( new Options(), object ); - } - - @Override - public final String serialize( Options options, Object object ) - throws ValueSerializationException - { - try - { - ByteArrayOutputStream output = new ByteArrayOutputStream(); - serializeRoot( options, object, output ); - return output.toString( UTF_8 ); - } - catch( ValueSerializationException ex ) - { - throw ex; - } - catch( Exception ex ) - { - throw new ValueSerializationException( "Could not serialize value", ex ); - } - } - - @Override - public final void serialize( Object object, OutputStream output ) - throws ValueSerializationException - { - serialize( new Options(), object, output ); - } - - @Override - public final void serialize( Options options, Object object, OutputStream output ) - throws ValueSerializationException - { - try - { - serializeRoot( options, object, output ); - } - catch( ValueSerializationException ex ) - { - throw ex; - } - catch( Exception ex ) - { - throw new ValueSerializationException( "Could not serialize value", ex ); - } - } - - private void serializeRoot( Options options, Object object, OutputStream output ) - throws Exception - { - if( object != null ) - { - if( serializers.get( object.getClass() ) != null ) - { - // Plain Value - Object serialized = serializers.get( object.getClass() ).apply( options, object ); - output.write( serialized.toString().getBytes( UTF_8 ) ); - } - else if( object instanceof Identity ) - { - Object serialized = serializers.get( Identity.class ).apply( options, object ); - output.write( serialized.toString().getBytes( UTF_8 ) ); - } - else if( object.getClass().isEnum() ) - { - // Enum Value - output.write( object.toString().getBytes( UTF_8 ) ); - } - else if( object.getClass().isArray() ) - { - // Array Value - output.write( serializeBase64Serializable( object ).getBytes( UTF_8 ) ); - } - else - { - // Complex Value - OutputType adaptedOutput = adaptOutput( output ); - onSerializationStart( object, adaptedOutput ); - doSerialize( options, object, adaptedOutput, true ); - onSerializationEnd( object, adaptedOutput ); - } - } - } - - private void doSerialize( Options options, Object object, OutputType output, boolean rootPass ) - throws Exception - { - // Null - if( object == null ) - { - onValue( output, null ); - } - else // Registered serializer - if( serializers.get( object.getClass() ) != null ) - { - onValue( output, serializers.get( object.getClass() ).apply( options, object ) ); - } - else if( complexSerializers.get( object.getClass() ) != null ) - { - complexSerializers.get( object.getClass() ).serialize( options, object, output ); - } - else // ValueComposite - if( Identity.class.isAssignableFrom( object.getClass() ) ) - { - serializeIdentity( object, output ); - } - else if( ValueComposite.class.isAssignableFrom( object.getClass() ) ) - { - serializeValueComposite( options, object, output, rootPass ); - } - else // EntityComposite - if( EntityComposite.class.isAssignableFrom( object.getClass() ) ) - { - serializeEntityComposite( object, output ); - } - else // Collection - Iterable - if( Iterable.class.isAssignableFrom( object.getClass() ) ) - { - serializeIterable( options, object, output ); - } - else // Array - QUID Remove this and use java serialization for arrays? - if( object.getClass().isArray() ) - { - serializeBase64Serializable( object, output ); - } - else // Map - if( Map.class.isAssignableFrom( object.getClass() ) ) - { - serializeMap( options, object, output ); - } - else // Enum - if( object.getClass().isEnum() ) - { - onValue( output, object.toString() ); - } - else // Fallback to Base64 encoded Java Serialization - { - serializeBase64Serializable( object, output ); - } - } - - private void serializeIdentity( Object object, OutputType output ) - throws Exception - { - onValue( output, object.toString() ); - } - - private void serializeValueComposite( Options options, Object object, OutputType output, boolean rootPass ) - throws Exception - { - CompositeInstance valueInstance = PolygeneAPI.FUNCTION_COMPOSITE_INSTANCE_OF.apply( (ValueComposite) object ); - ValueDescriptor descriptor = (ValueDescriptor) valueInstance.descriptor(); - AssociationStateHolder state = (AssociationStateHolder) valueInstance.state(); - - onObjectStart( output ); - - //noinspection ConstantConditions - if( options.getBoolean( Options.INCLUDE_TYPE_INFO ) && !rootPass ) - { - onFieldStart( output, "_type" ); - onValueStart( output ); - onValue( output, descriptor.valueType().types().findFirst().get().getName()); - onValueEnd( output ); - onFieldEnd( output ); - } - - descriptor.valueType().properties().forEach( persistentProperty -> { - Property<?> property = state.propertyFor( persistentProperty.accessor() ); - try - { - onFieldStart( output, persistentProperty.qualifiedName().name() ); - onValueStart( output ); - doSerialize( options, property.get(), output, false ); - onValueEnd( output ); - onFieldEnd( output ); - } - catch( Exception e ) - { - throw new ValueSerializationException( "Unable to serialize property " + persistentProperty, e ); - } - } ); - descriptor.valueType().associations().forEach(associationDescriptor -> { - Association<?> association = state.associationFor( associationDescriptor.accessor() ); - try - { - onFieldStart( output, associationDescriptor.qualifiedName().name() ); - onValueStart( output ); - EntityReference ref = association.reference(); - if( ref == null ) - { - onValue( output, null ); - } - else - { - onValue( output, ref.identity().toString() ); - } - onValueEnd( output ); - onFieldEnd( output ); - } - catch( Exception e ) - { - throw new ValueSerializationException( "Unable to serialize association " + associationDescriptor, e ); - } - } ); - descriptor.valueType().manyAssociations().forEach( associationDescriptor -> { - ManyAssociation<?> manyAssociation = state.manyAssociationFor( associationDescriptor.accessor() ); - try - { - onFieldStart( output, associationDescriptor.qualifiedName().name() ); - onValueStart( output ); - onArrayStart( output ); - for( Iterator<EntityReference> it = manyAssociation.references().iterator(); it.hasNext(); ) - { - onValueStart( output ); - onValue( output, it.next().identity().toString() ); - onValueEnd( output ); - } - onArrayEnd( output ); - onValueEnd( output ); - onFieldEnd( output ); - } - catch( Exception e ) - { - throw new ValueSerializationException( "Unable to serialize manyassociation " + associationDescriptor, e ); - } - }); - descriptor.valueType().namedAssociations().forEach( associationDescriptor -> { - NamedAssociation<?> namedAssociation = state.namedAssociationFor( associationDescriptor.accessor() ); - try - { - onFieldStart( output, associationDescriptor.qualifiedName().name() ); - onValueStart( output ); - onObjectStart( output ); - for( String name : namedAssociation ) - { - onFieldStart( output, name ); - onValueStart( output ); - EntityReference ref = namedAssociation.referenceOf( name ); - onValue( output, ref.identity().toString() ); - onValueEnd( output ); - onFieldEnd( output ); - } - onObjectEnd( output ); - onValueEnd( output ); - onFieldEnd( output ); - } - catch( Exception e ) - { - throw new ValueSerializationException( "Unable to serialize namedassociation " + associationDescriptor, e ); - } - } ); - - onObjectEnd( output ); - } - - private void serializeEntityComposite( Object object, OutputType output ) - throws Exception - { - onValue( output, EntityReference.entityReferenceFor( object ) ); - } - - private void serializeIterable( Options options, Object object, OutputType output ) - throws Exception - { - @SuppressWarnings( "unchecked" ) - Iterable<Object> collection = (Iterable<Object>) object; - onArrayStart( output ); - for( Object item : collection ) - { - onValueStart( output ); - doSerialize( options, item, output, false ); - onValueEnd( output ); - } - onArrayEnd( output ); - } - - private void serializeMap( Options options, Object object, OutputType output ) - throws Exception - { - @SuppressWarnings( "unchecked" ) - Map<Object, Object> map = (Map<Object, Object>) object; - //noinspection ConstantConditions - if( options.getBoolean( Options.MAP_ENTRIES_AS_OBJECTS ) ) - { - onObjectStart( output ); - for( Map.Entry<Object, Object> entry : map.entrySet() ) - { - onFieldStart( output, entry.getKey().toString() ); - onValueStart( output ); - doSerialize( options, entry.getValue(), output, false ); - onValueEnd( output ); - onFieldEnd( output ); - } - onObjectEnd( output ); - } - else - { - onArrayStart( output ); - for( Map.Entry<Object, Object> entry : map.entrySet() ) - { - onObjectStart( output ); - - onFieldStart( output, "key" ); - onValueStart( output ); - onValue( output, entry.getKey().toString() ); - onValueEnd( output ); - onFieldEnd( output ); - - onFieldStart( output, "value" ); - onValueStart( output ); - doSerialize( options, entry.getValue(), output, false ); - onValueEnd( output ); - onFieldEnd( output ); - - onObjectEnd( output ); - } - onArrayEnd( output ); - } - } - - private void serializeBase64Serializable( Object object, OutputType output ) - throws Exception - { - onValue( output, serializeBase64Serializable( object ) ); - } - - private String serializeBase64Serializable( Object object ) - throws Exception - { - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - try (ObjectOutputStream out = new ObjectOutputStream( bout )) - { - out.writeUnshared( object ); - } - byte[] bytes = Base64.getEncoder().encode( bout.toByteArray() ); - return new String( bytes, UTF_8 ); - } - - protected abstract OutputType adaptOutput( OutputStream output ) - throws Exception; - - protected void onSerializationStart( Object object, OutputType output ) - throws Exception - { - // NOOP - } - - protected void onSerializationEnd( Object object, OutputType output ) - throws Exception - { - // NOOP - } - - protected abstract void onArrayStart( OutputType output ) - throws Exception; - - protected abstract void onArrayEnd( OutputType output ) - throws Exception; - - protected abstract void onObjectStart( OutputType output ) - throws Exception; - - protected abstract void onObjectEnd( OutputType output ) - throws Exception; - - protected abstract void onFieldStart( OutputType output, String fieldName ) - throws Exception; - - protected void onFieldEnd( OutputType output ) - throws Exception - { - // NOOP - } - - protected void onValueStart( OutputType output ) - throws Exception - { - // NOOP - } - - protected abstract void onValue( OutputType output, Object value ) - throws Exception; - - protected void onValueEnd( OutputType output ) - throws Exception - { - // NOOP - } -} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/17b11697/core/spi/src/main/java/org/apache/polygene/spi/value/package.html ---------------------------------------------------------------------- diff --git a/core/spi/src/main/java/org/apache/polygene/spi/value/package.html b/core/spi/src/main/java/org/apache/polygene/spi/value/package.html deleted file mode 100644 index 936e083..0000000 --- a/core/spi/src/main/java/org/apache/polygene/spi/value/package.html +++ /dev/null @@ -1,24 +0,0 @@ -<!-- - ~ 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. - ~ - ~ - --> -<html> - <body> - <h2>Value SPI.</h2> - </body> -</html> http://git-wip-us.apache.org/repos/asf/polygene-java/blob/17b11697/core/spi/src/main/java/org/apache/polygene/valueserialization/orgjson/OrgJsonValueDeserializer.java ---------------------------------------------------------------------- diff --git a/core/spi/src/main/java/org/apache/polygene/valueserialization/orgjson/OrgJsonValueDeserializer.java b/core/spi/src/main/java/org/apache/polygene/valueserialization/orgjson/OrgJsonValueDeserializer.java deleted file mode 100644 index c543b3c..0000000 --- a/core/spi/src/main/java/org/apache/polygene/valueserialization/orgjson/OrgJsonValueDeserializer.java +++ /dev/null @@ -1,485 +0,0 @@ -/* - * 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.valueserialization.orgjson; - -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.Collection; -import java.util.Iterator; -import java.util.Map; -import java.util.function.Function; -import org.apache.polygene.api.structure.ModuleDescriptor; -import org.apache.polygene.api.value.ValueSerializationException; -import org.apache.polygene.spi.value.ValueDeserializerAdapter; -import org.json.JSONArray; -import org.json.JSONObject; -import org.json.JSONTokener; - -/** - * ValueDeserializer reading Values from JSON documents using org.json. - */ -public class OrgJsonValueDeserializer - extends ValueDeserializerAdapter<JSONTokener, Object> -{ - - @Override - protected JSONTokener adaptInput( ModuleDescriptor module, InputStream input ) - throws Exception - { - return new JSONTokener( new InputStreamReader( input, "UTF-8" ) ); - } - - @Override - protected Object readPlainValue( ModuleDescriptor module, JSONTokener input ) - throws Exception - { - Object nextValue = input.nextValue(); - if( JSONObject.NULL.equals( nextValue ) ) - { - return null; - } - else // Object or Array - if( JSONObject.class.isAssignableFrom( nextValue.getClass() ) - || JSONArray.class.isAssignableFrom( nextValue.getClass() ) ) - { - throw new ValueSerializationException( "Asked for a Value but found an Object or an Array." ); - } - return nextValue; - } - - @Override - protected <T> Collection<T> readArrayInCollection( ModuleDescriptor module, - JSONTokener input, - Function<JSONTokener, T> deserializer, - Collection<T> collection - ) - throws Exception - { - char c = input.nextClean(); - char q; - if( c == 'n' ) // null? - { - /* - * Handle unquoted text. This could be the values true, false, or - * null, or it can be a number. An implementation (such as this one) - * is allowed to also accept non-standard forms. - * - * Accumulate characters until we reach the end of the text or a - * formatting character. - */ - StringBuilder sb = new StringBuilder(); - sb.setLength( 0 ); - while( c >= ' ' && ",:]}/\\\"[{;=#".indexOf( c ) < 0 ) - { - sb.append( c ); - c = input.next(); - } - input.back(); - String s = sb.toString().trim(); - if( !"null".equals( s ) ) - { - input.syntaxError( "Unknown value: '" + s + "'" ); - } - return null; - } - else if( c == '[' ) - { - q = ']'; - } - else - { - throw input.syntaxError( "A JSONArray text must start with '['" ); - } - if( input.nextClean() == ']' ) - { - return collection; - } - input.back(); - for(; ; ) - { - if( input.nextClean() == ',' ) - { - input.back(); - collection.add( null ); - } - else - { - input.back(); - collection.add( deserializer.apply( input ) ); - } - c = input.nextClean(); - switch( c ) - { - case ';': - case ',': - if( input.nextClean() == ']' ) - { - return collection; - } - input.back(); - break; - case ']': - case ')': - if( q != c ) - { - throw input.syntaxError( "Expected a '" + Character.valueOf( q ) + "'" ); - } - return collection; - default: - throw input.syntaxError( "Expected a ',' or ']'" ); - } - } - } - - @Override - protected <K, V> Map<K, V> readMapInMap( ModuleDescriptor module, - JSONTokener input, - Function<JSONTokener, K> keyDeserializer, - Function<JSONTokener, V> valueDeserializer, - Map<K, V> map - ) - throws Exception - { - char c = input.nextClean(); - char q; - if( c == 'n' ) // null? - { - /* - * Handle unquoted text. This could be the values true, false, or - * null, or it can be a number. An implementation (such as this one) - * is allowed to also accept non-standard forms. - * - * Accumulate characters until we reach the end of the text or a - * formatting character. - */ - StringBuilder sb = new StringBuilder(); - sb.setLength( 0 ); - while( c >= ' ' && ",:]}/\\\"[{;=#".indexOf( c ) < 0 ) - { - sb.append( c ); - c = input.next(); - } - input.back(); - String s = sb.toString().trim(); - if( !"null".equals( s ) ) - { - input.syntaxError( "Unknown value: '" + s + "'" ); - } - return null; - } - else if( c == '[' ) - { - q = ']'; - } - else - { - throw input.syntaxError( "A JSONArray text must start with '['" ); - } - if( input.nextClean() == ']' ) - { - return map; - } - input.back(); - - for(; ; ) - { - if( input.nextClean() == ',' ) - { - input.back(); - } - else - { - input.back(); - // Map entry! - if( input.nextClean() != '{' ) - { - throw input.syntaxError( "A JSONObject text must begin with '{'" ); - } - - String objectKey; - K key = null; - V value = null; - - boolean breakIteration = false; - 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 ); - } - } - c = input.nextClean(); - switch( c ) - { - case ';': - case ',': - if( input.nextClean() == ']' ) - { - return map; - } - input.back(); - break; - case ']': - case ')': - if( q != c ) - { - throw input.syntaxError( "Expected a '" + Character.valueOf( q ) + "'" ); - } - return map; - default: - throw input.syntaxError( "Expected a ',' or ']'" ); - } - } - } - - // - // Deserialization - Tree parsing - // - @Override - protected JSONObject readObjectTree( ModuleDescriptor module, - JSONTokener input - ) - throws Exception - { - Object objectTree = input.nextValue(); - if( JSONObject.NULL.equals( objectTree ) ) - { - return null; - } - return (JSONObject) objectTree; - } - - @Override - protected Object asSimpleValue( ModuleDescriptor module, Object inputNode ) - throws Exception - { - if( JSONObject.NULL.equals( inputNode ) ) - { - return null; - } - if( inputNode instanceof JSONObject || inputNode instanceof JSONArray ) - { - throw new ValueSerializationException( "Expected a simple value but got " + inputNode ); - } - return inputNode; - } - - @Override - protected boolean isObjectValue( ModuleDescriptor module, Object inputNode ) - throws Exception - { - if( JSONObject.NULL.equals( inputNode ) ) - { - return false; - } - return inputNode instanceof JSONObject; - } - - @Override - protected boolean objectHasField( ModuleDescriptor module, Object inputNode, String key ) - throws Exception - { - if( JSONObject.NULL.equals( inputNode ) ) - { - return false; - } - if( !( inputNode instanceof JSONObject ) ) - { - throw new ValueSerializationException( "Expected an object but got " + inputNode ); - } - JSONObject json = (JSONObject) inputNode; - return json.has( key ); - } - - @Override - protected <T> T getObjectFieldValue( ModuleDescriptor module, - Object inputNode, - String key, - Function<Object, T> valueDeserializer - ) - throws Exception - { - JSONObject json = (JSONObject) inputNode; - Object valueNode = json.opt( key ); - if( JSONObject.NULL.equals( valueNode ) ) - { - return null; - } - T value = valueDeserializer.apply( valueNode ); - return value; - } - - @Override - protected <T> void putArrayNodeInCollection( ModuleDescriptor module, - Object inputNode, - Function<Object, T> deserializer, - Collection<T> collection - ) - throws Exception - { - if( JSONObject.NULL.equals( inputNode ) ) - { - return; - } - if( !( inputNode instanceof JSONArray ) ) - { - throw new ValueSerializationException( "Expected an array but got " + inputNode ); - } - JSONArray array = (JSONArray) inputNode; - for( int idx = 0; idx < array.length(); idx++ ) - { - Object item = array.get( idx ); - T value = deserializer.apply( item ); - collection.add( value ); - } - } - - @Override - protected <K, V> void putArrayNodeInMap( ModuleDescriptor module, - Object inputNode, - Function<Object, K> keyDeserializer, - Function<Object, V> valueDeserializer, - Map<K, V> map - ) - throws Exception - { - if( JSONObject.NULL.equals( inputNode ) ) - { - return; - } - if( !( inputNode instanceof JSONArray ) ) - { - throw new ValueSerializationException( "Expected an array but got " + inputNode ); - } - JSONArray array = (JSONArray) inputNode; - for( int idx = 0; idx < array.length(); idx++ ) - { - Object item = array.get( idx ); - if( !( item instanceof JSONObject ) ) - { - throw new ValueSerializationException( "Expected an object but got " + inputNode ); - } - JSONObject object = (JSONObject) item; - Object keyNode = object.get( "key" ); - Object valueNode = object.get( "value" ); - K key = keyDeserializer.apply( keyNode ); - V value = valueDeserializer.apply( valueNode ); - if( key != null ) - { - map.put( key, value ); - } - } - } - - @Override - protected <V> void putObjectNodeInMap( ModuleDescriptor module, - Object inputNode, - Function<Object, V> valueDeserializer, - Map<String, V> map - ) - throws Exception - { - if( JSONObject.NULL.equals( inputNode ) ) - { - return; - } - if( !( inputNode instanceof JSONObject ) ) - { - throw new ValueSerializationException( "Expected an object but got " + inputNode ); - } - JSONObject object = (JSONObject) inputNode; - - @SuppressWarnings( "unchecked" ) - Iterator<String> it = object.keys(); - while( it.hasNext() ) - { - String key = it.next(); - Object item = object.get( key ); - V valueValue = valueDeserializer.apply( item ); - if( key != null ) - { - map.put( key, valueValue ); - } - } - } -} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/17b11697/core/spi/src/main/java/org/apache/polygene/valueserialization/orgjson/OrgJsonValueSerializationService.java ---------------------------------------------------------------------- diff --git a/core/spi/src/main/java/org/apache/polygene/valueserialization/orgjson/OrgJsonValueSerializationService.java b/core/spi/src/main/java/org/apache/polygene/valueserialization/orgjson/OrgJsonValueSerializationService.java deleted file mode 100644 index 5bf3544..0000000 --- a/core/spi/src/main/java/org/apache/polygene/valueserialization/orgjson/OrgJsonValueSerializationService.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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.valueserialization.orgjson; - -import org.apache.polygene.api.mixin.Mixins; -import org.apache.polygene.api.value.ValueSerialization; - -/** - * ValueSerialization Service producing and consuming JSON documents using org.json. - */ -@Mixins( { OrgJsonValueSerializer.class, OrgJsonValueDeserializer.class } ) -public interface OrgJsonValueSerializationService - extends ValueSerialization -{ -}
