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 28D51200C4A for ; Sun, 2 Apr 2017 19:45:47 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 27A25160B9A; Sun, 2 Apr 2017 17:45:47 +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 D1867160BB3 for ; Sun, 2 Apr 2017 19:45:43 +0200 (CEST) Received: (qmail 14051 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 13302 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 55A60E08AC; 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:45:58 -0000 Message-Id: <64f9662ddfd94de5b81be877f9a8b109@git.apache.org> In-Reply-To: <0088a29e2e0d476a907e84190e3d8c97@git.apache.org> References: <0088a29e2e0d476a907e84190e3d8c97@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [18/51] [abbrv] polygene-java git commit: New (de)serialization API and SPI & new implementations archived-at: Sun, 02 Apr 2017 17:45:47 -0000 http://git-wip-us.apache.org/repos/asf/polygene-java/blob/17b11697/core/api/src/main/java/org/apache/polygene/api/type/HasTypesCollectors.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/polygene/api/type/HasTypesCollectors.java b/core/api/src/main/java/org/apache/polygene/api/type/HasTypesCollectors.java new file mode 100644 index 0000000..ef6274e --- /dev/null +++ b/core/api/src/main/java/org/apache/polygene/api/type/HasTypesCollectors.java @@ -0,0 +1,408 @@ +package org.apache.polygene.api.type; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.Supplier; +import java.util.stream.Collector; + +/** + * Collectors for HasTypes. + */ +public class HasTypesCollectors +{ + private static final String EQUAL_KEY = "equal"; + private static final String EQUAL_TYPE_KEY = "equalType"; + private static final String ASSIGNABLE_TYPE_KEY = "assignableType"; + + public static Collector> matchingType( T hasTypes ) + { + return hasTypesFindFirstCollector( hasTypes, new HasAssignableFromType<>( hasTypes ) ); + } + + public static Collector> closestType( T hasTypes ) + { + return hasTypesFindFirstCollector( hasTypes, new HasAssignableToType<>( hasTypes ) ); + } + + private static Collector> + hasTypesFindFirstCollector( T hasTypes, Predicate assignableTypePredicate ) + { + Predicate equalPredicate = o -> Objects.equals( o, hasTypes ); + Predicate equalTypePredicate = new HasEqualType<>( hasTypes ); + return new Collector>, Optional>() + { + @Override + public Supplier>> supplier() + { + return () -> new HashMap>( 3 ) + {{ + put( EQUAL_KEY, new LinkedHashSet<>( 1 ) ); + put( EQUAL_TYPE_KEY, new LinkedHashSet<>( 1 ) ); + put( ASSIGNABLE_TYPE_KEY, new LinkedHashSet<>() ); + }}; + } + + @Override + public BiConsumer>, T> accumulator() + { + return ( map, candidate ) -> + { + Set equalObjects = map.get( EQUAL_KEY ); + if( equalObjects.isEmpty() ) + { + if( equalPredicate.test( candidate ) ) + { + equalObjects.add( candidate ); + } + else + { + Set equalTypes = map.get( EQUAL_TYPE_KEY ); + if( equalTypes.isEmpty() ) + { + if( equalTypePredicate.test( candidate ) ) + { + equalTypes.add( candidate ); + } + else if( assignableTypePredicate.test( candidate ) ) + { + map.get( ASSIGNABLE_TYPE_KEY ).add( candidate ); + } + } + } + } + }; + } + + @Override + public BinaryOperator>> combiner() + { + return ( left, right ) -> + { + left.get( EQUAL_KEY ).addAll( right.get( EQUAL_KEY ) ); + left.get( EQUAL_TYPE_KEY ).addAll( right.get( EQUAL_TYPE_KEY ) ); + left.get( ASSIGNABLE_TYPE_KEY ).addAll( right.get( ASSIGNABLE_TYPE_KEY ) ); + return left; + }; + } + + @Override + public Function>, Optional> finisher() + { + return map -> + { + Set equalObjects = map.get( EQUAL_KEY ); + if( !equalObjects.isEmpty() ) + { + return Optional.of( equalObjects.iterator().next() ); + } + Set equalTypes = map.get( EQUAL_TYPE_KEY ); + if( !equalTypes.isEmpty() ) + { + return Optional.of( equalTypes.iterator().next() ); + } + Set assignableTypes = map.get( ASSIGNABLE_TYPE_KEY ); + if( !assignableTypes.isEmpty() ) + { + return Optional.of( assignableTypes.iterator().next() ); + } + return Optional.empty(); + }; + } + + @Override + public Set characteristics() + { + return Collections.emptySet(); + } + }; + } + + + public static Collector> matchingTypes( T hasTypes ) + { + return hasTypesToListCollector( hasTypes, new HasAssignableFromType<>( hasTypes ) ); + } + + public static Collector> closestTypes( T hasTypes ) + { + return hasTypesToListCollector( hasTypes, new HasAssignableToType<>( hasTypes ) ); + } + + private static Collector> + hasTypesToListCollector( T hasTypes, Predicate assignableTypePredicate ) + { + Predicate equalPredicate = o -> Objects.equals( o, hasTypes ); + Predicate equalTypePredicate = new HasEqualType<>( hasTypes ); + return new Collector>, List>() + { + @Override + public Supplier>> supplier() + { + return () -> new HashMap>( 3 ) + {{ + put( EQUAL_KEY, new LinkedHashSet<>() ); + put( EQUAL_TYPE_KEY, new LinkedHashSet<>() ); + put( ASSIGNABLE_TYPE_KEY, new LinkedHashSet<>() ); + }}; + } + + @Override + public BiConsumer>, T> accumulator() + { + return ( map, candidate ) -> + { + Set equalObjects = map.get( EQUAL_KEY ); + if( equalObjects.isEmpty() ) + { + if( equalPredicate.test( candidate ) ) + { + equalObjects.add( candidate ); + } + else + { + Set equalTypes = map.get( EQUAL_TYPE_KEY ); + if( equalTypes.isEmpty() ) + { + if( equalTypePredicate.test( candidate ) ) + { + equalTypes.add( candidate ); + } + else if( assignableTypePredicate.test( candidate ) ) + { + map.get( ASSIGNABLE_TYPE_KEY ).add( candidate ); + } + } + } + } + }; + } + + @Override + public BinaryOperator>> combiner() + { + return ( left, right ) -> + { + left.get( EQUAL_KEY ).addAll( right.get( EQUAL_KEY ) ); + left.get( EQUAL_TYPE_KEY ).addAll( right.get( EQUAL_TYPE_KEY ) ); + left.get( ASSIGNABLE_TYPE_KEY ).addAll( right.get( ASSIGNABLE_TYPE_KEY ) ); + return left; + }; + } + + @Override + public Function>, List> finisher() + { + return map -> + { + Set equalObjects = map.get( EQUAL_KEY ); + Set equalSet = map.get( EQUAL_TYPE_KEY ); + Set assignableSet = map.get( ASSIGNABLE_TYPE_KEY ); + List list = new ArrayList<>( equalObjects.size() + equalSet.size() + assignableSet.size() ); + list.addAll( equalObjects ); + list.addAll( equalSet ); + list.addAll( assignableSet ); + return list; + }; + } + + @Override + public Set characteristics() + { + return Collections.emptySet(); + } + }; + } + + + /** + * Collect a single matching HasTypes. + * + * TODO Detail + * + * @param type type to match + * @param type of HasTypes + * @return an optional best matching HasTypes + */ + public static Collector> matchingType( Type type ) + { + return typeFindFirstCollector( type, new HasAssignableFromType<>( type ) ); + } + + public static Collector> closestType( Type type ) + { + return typeFindFirstCollector( type, new HasAssignableToType( type ) ); + } + + private static Collector> + typeFindFirstCollector( Type type, Predicate assignableTypePredicate ) + { + Predicate equalTypePredicate = new HasEqualType<>( type ); + return new Collector>, Optional>() + { + @Override + public Supplier>> supplier() + { + return () -> new HashMap>( 2 ) + {{ + put( EQUAL_TYPE_KEY, new LinkedHashSet<>( 1 ) ); + put( ASSIGNABLE_TYPE_KEY, new LinkedHashSet<>() ); + }}; + } + + @Override + public BiConsumer>, T> accumulator() + { + return ( map, candidate ) -> + { + Set equalSet = map.get( EQUAL_TYPE_KEY ); + if( equalSet.isEmpty() ) + { + if( equalTypePredicate.test( candidate ) ) + { + equalSet.add( candidate ); + } + else if( assignableTypePredicate.test( candidate ) ) + { + map.get( ASSIGNABLE_TYPE_KEY ).add( candidate ); + } + } + }; + } + + @Override + public BinaryOperator>> combiner() + { + return ( left, right ) -> + { + left.get( EQUAL_TYPE_KEY ).addAll( right.get( EQUAL_TYPE_KEY ) ); + left.get( ASSIGNABLE_TYPE_KEY ).addAll( right.get( ASSIGNABLE_TYPE_KEY ) ); + return left; + }; + } + + @Override + public Function>, Optional> finisher() + { + return map -> + { + Set equalSet = map.get( EQUAL_TYPE_KEY ); + if( !equalSet.isEmpty() ) + { + return Optional.of( equalSet.iterator().next() ); + } + Set assignableSet = map.get( ASSIGNABLE_TYPE_KEY ); + if( !assignableSet.isEmpty() ) + { + return Optional.of( assignableSet.iterator().next() ); + } + return Optional.empty(); + }; + } + + @Override + public final Set characteristics() + { + return Collections.emptySet(); + } + }; + } + + /** + * Collect all matching HasTypes. + * + * First the ones with at least on equal type. + * Then the ones with at least one type assignable from {@literal type}. + * + * @param type type to match + * @param type of HasTypes + * @return an optional best matching HasTypes + */ + public static Collector> matchingTypes( Type type ) + { + return typeToListCollector( type, new HasAssignableFromType<>( type ) ); + } + + public static Collector> closestTypes( Type type ) + { + return typeToListCollector( type, new HasAssignableToType<>( type ) ); + } + + private static Collector> + typeToListCollector( Type type, Predicate assignableTypePredicate ) + { + Predicate equalTypePredicate = new HasEqualType<>( type ); + return new Collector>, List>() + { + @Override + public Supplier>> supplier() + { + return () -> new HashMap>( 2 ) + {{ + put( EQUAL_TYPE_KEY, new LinkedHashSet<>() ); + put( ASSIGNABLE_TYPE_KEY, new LinkedHashSet<>() ); + }}; + } + + @Override + public BiConsumer>, T> accumulator() + { + return ( map, candidate ) -> + { + if( equalTypePredicate.test( candidate ) ) + { + map.get( EQUAL_TYPE_KEY ).add( candidate ); + } + else if( assignableTypePredicate.test( candidate ) ) + { + map.get( ASSIGNABLE_TYPE_KEY ).add( candidate ); + } + }; + } + + @Override + public BinaryOperator>> combiner() + { + return ( left, right ) -> + { + left.get( EQUAL_TYPE_KEY ).addAll( right.get( EQUAL_TYPE_KEY ) ); + left.get( ASSIGNABLE_TYPE_KEY ).addAll( right.get( ASSIGNABLE_TYPE_KEY ) ); + return left; + }; + } + + @Override + public Function>, List> finisher() + { + return map -> + { + Set equalSet = map.get( EQUAL_TYPE_KEY ); + Set assignableSet = map.get( ASSIGNABLE_TYPE_KEY ); + List list = new ArrayList<>( equalSet.size() + assignableSet.size() ); + list.addAll( equalSet ); + list.addAll( assignableSet ); + return list; + }; + } + + @Override + public final Set characteristics() + { + return Collections.emptySet(); + } + }; + } + + private HasTypesCollectors() {} +} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/17b11697/core/api/src/main/java/org/apache/polygene/api/type/HasTypesPredicate.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/polygene/api/type/HasTypesPredicate.java b/core/api/src/main/java/org/apache/polygene/api/type/HasTypesPredicate.java new file mode 100644 index 0000000..fd91a3a --- /dev/null +++ b/core/api/src/main/java/org/apache/polygene/api/type/HasTypesPredicate.java @@ -0,0 +1,60 @@ +package org.apache.polygene.api.type; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.WildcardType; +import java.util.List; +import java.util.function.Predicate; + +import static org.apache.polygene.api.util.Classes.interfacesOf; + +public abstract class HasTypesPredicate implements Predicate +{ + protected final List matchTypes; + + protected HasTypesPredicate( List types ) + { + matchTypes = types; + } + + @Override + public final boolean test( T hasTypes ) + { + for( Type matchType : matchTypes ) + { + if( matchType instanceof Class ) + { + if( hasTypes.types().anyMatch( matchPredicate( matchType ) ) ) + { + return true; + } + } + else + { + if( matchType instanceof ParameterizedType ) + { + // Foo check + // First check Foo + ParameterizedType parameterizedType = (ParameterizedType) matchType; + Type rawType = parameterizedType.getRawType(); + + if( hasTypes.types().anyMatch( matchPredicate( rawType ) ) ) + { + // Then check Bar + if( interfacesOf( hasTypes.types() ).anyMatch( intf -> intf.equals( matchType ) ) ) + { + return true; + } + } + } + else if( matchType instanceof WildcardType ) + { + return true; + } + } + } + return false; + } + + protected abstract Predicate matchPredicate( Type candidate ); +} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/17b11697/core/api/src/main/java/org/apache/polygene/api/type/MapType.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/polygene/api/type/MapType.java b/core/api/src/main/java/org/apache/polygene/api/type/MapType.java index 4046628..23124eb 100644 --- a/core/api/src/main/java/org/apache/polygene/api/type/MapType.java +++ b/core/api/src/main/java/org/apache/polygene/api/type/MapType.java @@ -21,6 +21,7 @@ package org.apache.polygene.api.type; import java.lang.reflect.Type; import java.util.Map; +import java.util.Objects; import org.apache.polygene.api.util.Classes; /** @@ -30,38 +31,40 @@ import org.apache.polygene.api.util.Classes; public final class MapType extends ValueType { - - private ValueType keyType; - private ValueType valueType; - private final Serialization.Variant variant; - public static boolean isMap( Type type ) { Class cl = Classes.RAW_CLASS.apply( type ); return Map.class.isAssignableFrom( cl ); } - public static MapType of( Class keyType, Class valueType ) + public static MapType of( Class mapType, ValueType keyType, ValueType valueType ) { - return new MapType( Map.class, ValueType.of( keyType ), ValueType.of( valueType ) ); + return new MapType( mapType, keyType, valueType ); } - public static MapType of( Class keyType, Class valueType, Serialization.Variant variant ) + public static MapType of( Class mapType, Class keyType, Class valueType ) { - return new MapType( Map.class, ValueType.of( keyType ), ValueType.of( valueType ), variant ); + return of( mapType, ValueType.of( keyType ), ValueType.of( valueType ) ); } - public MapType( Class type, ValueType keyType, ValueType valueType ) + public static MapType of( ValueType keyType, ValueType valueType ) { - this( type, keyType, valueType, Serialization.Variant.entry ); + return new MapType( Map.class, keyType, valueType ); } - public MapType( Class type, ValueType keyType, ValueType valueType, Serialization.Variant variant ) + public static MapType of( Class keyType, Class valueType ) + { + return of( ValueType.of( keyType ), ValueType.of( valueType ) ); + } + + private ValueType keyType; + private ValueType valueType; + + public MapType( Class type, ValueType keyType, ValueType valueType ) { super( type ); this.keyType = keyType; this.valueType = valueType; - this.variant = variant; if( !isMap( type ) ) { throw new IllegalArgumentException( type + " is not a Map." ); @@ -78,9 +81,21 @@ public final class MapType return valueType; } - public Serialization.Variant variant() + @Override + public boolean equals( final Object o ) + { + if( this == o ) { return true; } + if( o == null || getClass() != o.getClass() ) { return false; } + if( !super.equals( o ) ) { return false; } + MapType mapType = (MapType) o; + return Objects.equals( keyType, mapType.keyType ) && + Objects.equals( valueType, mapType.valueType ); + } + + @Override + public int hashCode() { - return variant; + return Objects.hash( super.hashCode(), keyType, valueType ); } @Override http://git-wip-us.apache.org/repos/asf/polygene-java/blob/17b11697/core/api/src/main/java/org/apache/polygene/api/type/MatchTypeSpecification.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/polygene/api/type/MatchTypeSpecification.java b/core/api/src/main/java/org/apache/polygene/api/type/MatchTypeSpecification.java deleted file mode 100644 index 8d8ff92..0000000 --- a/core/api/src/main/java/org/apache/polygene/api/type/MatchTypeSpecification.java +++ /dev/null @@ -1,51 +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.api.type; - -import java.util.function.Predicate; - -/** - * Match Type Specification for HasTypes. - */ -public class MatchTypeSpecification - implements Predicate -{ - private final Class matchType; - - public MatchTypeSpecification( Class matchType ) - { - this.matchType = matchType; - } - - @Override - public boolean test( HasTypes item ) - { - return item.types().anyMatch( matchType::isAssignableFrom ); -// for( Class type : item.types() ) -// { -// if( matchType.isAssignableFrom( type ) ) -// { -// return true; -// } -// } -// return false; - } -} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/17b11697/core/api/src/main/java/org/apache/polygene/api/type/Serialization.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/polygene/api/type/Serialization.java b/core/api/src/main/java/org/apache/polygene/api/type/Serialization.java deleted file mode 100644 index 981ab00..0000000 --- a/core/api/src/main/java/org/apache/polygene/api/type/Serialization.java +++ /dev/null @@ -1,62 +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.api.type; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Serialization options for Property intstances. - *

- * The {@code entry} type represents the explicit key=keyValue, value=valueValue. For JSON serialization; - *

- *
- *     [
- *         { "key1" : "value1" },
- *         { "key2" : "value2" }
- *     ]
- * 
- *

- * For XML serialization; - *

- *
- *     <object>
- *         <
- *     </object>
- * 
- *

- * The {@code object} type represents the explicit keyValue=valueValue. - *

- */ -@Retention( RetentionPolicy.RUNTIME ) -@Target( { ElementType.TYPE, ElementType.METHOD } ) -@Documented -public @interface Serialization -{ - Variant value(); - - enum Variant - { - entry, object - } -} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/17b11697/core/api/src/main/java/org/apache/polygene/api/type/ValueCompositeType.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/polygene/api/type/ValueCompositeType.java b/core/api/src/main/java/org/apache/polygene/api/type/ValueCompositeType.java index 4cf86a6..9190e68 100644 --- a/core/api/src/main/java/org/apache/polygene/api/type/ValueCompositeType.java +++ b/core/api/src/main/java/org/apache/polygene/api/type/ValueCompositeType.java @@ -20,7 +20,7 @@ package org.apache.polygene.api.type; import java.lang.reflect.Type; -import java.util.stream.Collectors; +import java.util.Objects; import java.util.stream.Stream; import org.apache.polygene.api.association.AssociationDescriptor; import org.apache.polygene.api.property.PropertyDescriptor; @@ -28,22 +28,28 @@ import org.apache.polygene.api.util.Classes; import org.apache.polygene.api.value.ValueComposite; import org.apache.polygene.api.value.ValueDescriptor; +import static java.util.stream.Collectors.toList; + /** * ValueComposite ValueType. */ -public final class ValueCompositeType - extends ValueType +public final class ValueCompositeType extends ValueType { - private final ValueDescriptor model; + public static ValueCompositeType of( ValueDescriptor model ) + { + return new ValueCompositeType( model ); + } public static boolean isValueComposite( Type type ) { return ValueComposite.class.isAssignableFrom( Classes.RAW_CLASS.apply( type ) ); } + private final ValueDescriptor model; + public ValueCompositeType( ValueDescriptor model ) { - super( model.types().collect( Collectors.toList() ) ); + super( model.types().collect( toList() ) ); this.model = model; } @@ -66,4 +72,20 @@ public final class ValueCompositeType { return model.state().namedAssociations(); } + + @Override + public boolean equals( final Object o ) + { + if( this == o ) { return true; } + if( o == null || getClass() != o.getClass() ) { return false; } + if( !super.equals( o ) ) { return false; } + ValueCompositeType that = (ValueCompositeType) o; + return Objects.equals( model, that.model ); + } + + @Override + public int hashCode() + { + return Objects.hash( super.hashCode(), model ); + } } http://git-wip-us.apache.org/repos/asf/polygene-java/blob/17b11697/core/api/src/main/java/org/apache/polygene/api/type/ValueType.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/polygene/api/type/ValueType.java b/core/api/src/main/java/org/apache/polygene/api/type/ValueType.java index fee41cb..d457d81 100644 --- a/core/api/src/main/java/org/apache/polygene/api/type/ValueType.java +++ b/core/api/src/main/java/org/apache/polygene/api/type/ValueType.java @@ -19,10 +19,21 @@ */ package org.apache.polygene.api.type; -import java.util.Collections; +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.Arrays; import java.util.List; import java.util.Objects; import java.util.stream.Stream; +import org.apache.polygene.api.entity.EntityReference; import org.apache.polygene.api.identity.Identity; import static java.util.stream.Collectors.joining; @@ -30,105 +41,44 @@ import static java.util.stream.Collectors.joining; /** * Base class for types of values in ValueComposites and Properties. */ -public class ValueType - implements HasTypes +public class ValueType implements HasTypes { + public static final ValueType OBJECT = ValueType.of( Object.class ); + public static final ValueType STRING = ValueType.of( String.class ); + public static final ValueType CHARACTER = ValueType.of( Character.class, char.class ); + public static final ValueType BOOLEAN = ValueType.of( Boolean.class, boolean.class ); + public static final ValueType INTEGER = ValueType.of( Integer.class, int.class ); + public static final ValueType LONG = ValueType.of( Long.class, long.class ); + public static final ValueType SHORT = ValueType.of( Short.class, short.class ); + public static final ValueType BYTE = ValueType.of( Byte.class, byte.class ); + public static final ValueType FLOAT = ValueType.of( Float.class, float.class ); + public static final ValueType DOUBLE = ValueType.of( Double.class, double.class ); + public static final ValueType BIG_DECIMAL = ValueType.of( BigDecimal.class ); + public static final ValueType BIG_INTEGER = ValueType.of( BigInteger.class ); + public static final ValueType INSTANT = ValueType.of( Instant.class ); + public static final ValueType ZONED_DATE_TIME = ValueType.of( ZonedDateTime.class ); + public static final ValueType OFFSET_DATE_TIME = ValueType.of( OffsetDateTime.class ); + public static final ValueType LOCAL_DATE_TIME = ValueType.of( LocalDateTime.class ); + public static final ValueType LOCAL_DATE = ValueType.of( LocalDate.class ); + public static final ValueType LOCAL_TIME = ValueType.of( LocalTime.class ); + public static final ValueType DURATION = ValueType.of( Duration.class ); + public static final ValueType PERIOD = ValueType.of( Period.class ); + public static final ValueType IDENTITY = ValueType.of( Identity.class ); + public static final ValueType ENTITY_REFERENCE = ValueType.of( EntityReference.class ); - public static ValueType of( Class type ) + public static ValueType of( Class... types ) { - return new ValueType( type ); + return new ValueType( types ); } - /** - * Check if a non-null object is of any of the Primitive Value Types or an array of them. - *

- * String, Boolean, Integer, Double, Float, Long, Byte, Short and Character and their Java primitive types - * counterparts are considered as Primitive Value Types. - *

- *

- * Date, BigInteger, BigDecimal and JodaTime types are not considered as Primitive Value Types. - *

- * - * @param object Object - * @return true if object is a primitive value or an array of primitive values - * @throws IllegalArgumentException if object is null - */ - public static boolean isPrimitiveValue( Object object ) - { - Objects.requireNonNull( object, "object" ); - if( object instanceof String - || object instanceof Character - || object instanceof Boolean - || object instanceof Integer - || object instanceof Double - || object instanceof Float - || object instanceof Long - || object instanceof Byte - || object instanceof Short ) - { - return true; - } - if( object.getClass().isArray() ) - { - return isArrayOfPrimitiveValues( object ); - } - return false; - } - - public static boolean isIdentity( Object object ) - { - return object instanceof Identity; - } - - private static boolean isArrayOfPrimitiveValues( Object array ) - { - if( array instanceof String[] - || array instanceof char[] || array instanceof Character[] - || array instanceof boolean[] || array instanceof Boolean[] - || array instanceof int[] || array instanceof Integer[] - || array instanceof double[] || array instanceof Double[] - || array instanceof float[] || array instanceof Float[] - || array instanceof long[] || array instanceof Long[] - || array instanceof byte[] || array instanceof Byte[] - || array instanceof short[] || array instanceof Short[] ) - { - return true; - } - return false; - } - - public static boolean isPrimitiveValueType( ValueType valueType ) - { - return isPrimitiveValueType( valueType.primaryType() ); - } - - /** - * @see ValueType#isPrimitiveValue(java.lang.Object) - * @param type Type - * @return true if object is a primitive value or an array of primitive values - */ - public static boolean isPrimitiveValueType( Class type ) - { - Objects.requireNonNull( type, "type" ); - if( String.class.isAssignableFrom( type ) ) - { - return true; - } - if( type.isArray() ) - { - return isPrimitiveValueType( type.getComponentType() ); - } - return false; - } protected final List> types; - public ValueType( Class type ) + protected ValueType( Class... types ) { - this( Collections.singletonList( type ) ); + this( Arrays.asList( types ) ); } - @SuppressWarnings( "unchecked" ) - public ValueType( List> types ) + protected ValueType( List> types ) { this.types = types; } @@ -145,6 +95,21 @@ public class ValueType } @Override + public boolean equals( Object o ) + { + if( this == o ) { return true; } + if( o == null || getClass() != o.getClass() ) { return false; } + ValueType valueType = (ValueType) o; + return Objects.equals( types, valueType.types ); + } + + @Override + public int hashCode() + { + return Objects.hash( types ); + } + + @Override public String toString() { String name = types.stream().map( Class::getName ).collect( joining( "," ) ); http://git-wip-us.apache.org/repos/asf/polygene-java/blob/17b11697/core/api/src/main/java/org/apache/polygene/api/util/Collectors.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/polygene/api/util/Collectors.java b/core/api/src/main/java/org/apache/polygene/api/util/Collectors.java index e419b21..906b062 100644 --- a/core/api/src/main/java/org/apache/polygene/api/util/Collectors.java +++ b/core/api/src/main/java/org/apache/polygene/api/util/Collectors.java @@ -17,6 +17,7 @@ */ package org.apache.polygene.api.util; +import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.function.BinaryOperator; @@ -24,13 +25,18 @@ import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collector; +/** + * Implementations of {@link Collector} missing from the JDK. + */ public class Collectors { /** * Collect a single element. + * + * The Collector throws {@link IllegalArgumentException} if no or more than one element. + * * @param Element type - * @return The single element - * @throws IllegalArgumentException if no or more than one element + * @return The single element collector */ public static Collector single() @@ -46,13 +52,14 @@ public class Collectors /** * Eventually collect a single element. + * + * The Collector throws {@link IllegalArgumentException} if more than one element. + * * @param Element type - * @return The single element, optional - * @throws IllegalArgumentException if more than one element + * @return The optional single element collector */ public static Collector> singleOrEmpty() - throws IllegalArgumentException { return java.util.stream.Collectors.reducing( ( left, right ) -> @@ -69,6 +76,59 @@ public class Collectors } ); } + /** + * Collect map entries into a {@link HashMap}. + * + * The Collector throws {@link NullPointerException} if one entry has a {@literal null} value. + * The Collector throws {@link IllegalStateException} if duplicate keys are found. + * + * @param the Map entry type + * @param the collected map key type + * @param the collected map value type + * @return a {@code Collector} which collects elements into a {@code Map} + */ + public static , K, U> + Collector> toMap() + { + return toMap( Map.Entry::getKey, Map.Entry::getValue, HashMap::new ); + } + + /** + * Collect map entries into a map. + * + * The Collector throws {@link NullPointerException} if one entry has a {@literal null} value. + * The Collector throws {@link IllegalStateException} if duplicate keys are found. + * + * @param the type of the resulting {@code Map} + * @param the Map entry type + * @param the collected map key type + * @param the collected map value type + * @param mapSupplier a function which returns a new, empty {@code Map} into + * which the results will be inserted + * @return The map collector + */ + public static , K, U, M extends Map> + Collector toMap( Supplier mapSupplier ) + { + return toMap( Map.Entry::getKey, Map.Entry::getValue, mapSupplier ); + } + + /** + * Collect map entries into a map. + * + * The Collector throws {@link NullPointerException} if one entry has a {@literal null} value. + * The Collector throws {@link IllegalStateException} if duplicate keys are found. + * + * @param the type of the resulting {@code Map} + * @param the Map entry type + * @param the collected map key type + * @param the collected map value type + * @param keyMapper a mapping function to produce keys + * @param valueMapper a mapping function to produce values + * @param mapSupplier a function which returns a new, empty {@code Map} into + * which the results will be inserted + * @return The map collector + */ public static > Collector toMap( Function keyMapper, Function valueMapper, @@ -80,17 +140,86 @@ public class Collectors mapSupplier ); } - + /** + * Collect map entries into a {@link HashMap}, allowing null values. + * + * The Collector throws {@link IllegalStateException} if duplicate keys are found. + * + * See https://bugs.openjdk.java.net/browse/JDK-8148463 + * + * @param the Map entry type + * @param the collected map key type + * @param the collected map value type + * @return The map collector + */ public static , K, U> - Collector> toMap() + Collector> toMapWithNullValues() { - return java.util.stream.Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue ); + return toMapWithNullValues( Map.Entry::getKey, Map.Entry::getValue, HashMap::new ); } + /** + * Collect map entries into a map, allowing null values. + * + * The Collector throws {@link IllegalStateException} if duplicate keys are found. + * + * See https://bugs.openjdk.java.net/browse/JDK-8148463 + * + * @param the type of the resulting {@code Map} + * @param the Map entry type + * @param the collected map key type + * @param the collected map value type + * @param mapSupplier a function which returns a new, empty {@code Map} into + * which the results will be inserted + * @return The map collector + */ public static , K, U, M extends Map> - Collector toMap( Supplier mapSupplier ) + Collector toMapWithNullValues( Supplier mapSupplier ) { - return toMap( Map.Entry::getKey, Map.Entry::getValue, mapSupplier ); + return toMapWithNullValues( Map.Entry::getKey, Map.Entry::getValue, mapSupplier ); + } + + /** + * Collect map entries into a map, allowing null values. + * + * The Collector throws {@link IllegalStateException} if duplicate keys are found. + * + * See https://bugs.openjdk.java.net/browse/JDK-8148463 + * + * @param the type of the resulting {@code Map} + * @param the Map entry type + * @param the collected map key type + * @param the collected map value type + * @param keyMapper a mapping function to produce keys + * @param valueMapper a mapping function to produce values + * @param mapSupplier a function which returns a new, empty {@code Map} into + * which the results will be inserted + * @return The map collector + */ + public static > + Collector toMapWithNullValues( Function keyMapper, + Function valueMapper, + Supplier mapSupplier ) + { + return java.util.stream.Collector + .of( mapSupplier, + ( map, entry ) -> map.put( keyMapper.apply( entry ), + valueMapper.apply( entry ) ), + ( left, right ) -> + { + M result = mapSupplier.get(); + result.putAll( left ); + for( Map.Entry entry : right.entrySet() ) + { + K key = entry.getKey(); + if( result.containsKey( key ) ) + { + throw new IllegalStateException( String.format( "Duplicate key %s", key ) ); + } + result.put( key, entry.getValue() ); + } + return result; + } ); } private static BinaryOperator throwingMerger() http://git-wip-us.apache.org/repos/asf/polygene-java/blob/17b11697/core/api/src/main/java/org/apache/polygene/api/value/MissingValueSerializationException.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/polygene/api/value/MissingValueSerializationException.java b/core/api/src/main/java/org/apache/polygene/api/value/MissingValueSerializationException.java deleted file mode 100644 index 00b1af7..0000000 --- a/core/api/src/main/java/org/apache/polygene/api/value/MissingValueSerializationException.java +++ /dev/null @@ -1,43 +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.api.value; - -public class MissingValueSerializationException extends ValueSerializationException -{ - public MissingValueSerializationException() - { - } - - public MissingValueSerializationException( String message ) - { - super( message ); - } - - public MissingValueSerializationException( String message, Throwable cause ) - { - super( message, cause ); - } - - public MissingValueSerializationException( Throwable cause ) - { - super( cause ); - } -} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/17b11697/core/api/src/main/java/org/apache/polygene/api/value/ValueDescriptor.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/polygene/api/value/ValueDescriptor.java b/core/api/src/main/java/org/apache/polygene/api/value/ValueDescriptor.java index b9b3f54..8407fa9 100644 --- a/core/api/src/main/java/org/apache/polygene/api/value/ValueDescriptor.java +++ b/core/api/src/main/java/org/apache/polygene/api/value/ValueDescriptor.java @@ -20,19 +20,15 @@ package org.apache.polygene.api.value; -import org.apache.polygene.api.association.AssociationStateDescriptor; import org.apache.polygene.api.composite.CompositeDescriptor; -import org.apache.polygene.api.composite.StatefulCompositeDescriptor; +import org.apache.polygene.api.composite.StatefulAssociationCompositeDescriptor; import org.apache.polygene.api.type.ValueCompositeType; /** * Descriptor for ValueComposites. */ public interface ValueDescriptor - extends CompositeDescriptor, StatefulCompositeDescriptor + extends CompositeDescriptor, StatefulAssociationCompositeDescriptor { ValueCompositeType valueType(); - - @Override - AssociationStateDescriptor state(); } http://git-wip-us.apache.org/repos/asf/polygene-java/blob/17b11697/core/api/src/main/java/org/apache/polygene/api/value/ValueDeserializer.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/polygene/api/value/ValueDeserializer.java b/core/api/src/main/java/org/apache/polygene/api/value/ValueDeserializer.java deleted file mode 100644 index 88afc3a..0000000 --- a/core/api/src/main/java/org/apache/polygene/api/value/ValueDeserializer.java +++ /dev/null @@ -1,172 +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.api.value; - -import java.io.InputStream; -import java.util.function.Function; -import org.apache.polygene.api.structure.ModuleDescriptor; -import org.apache.polygene.api.type.ValueType; - -/** - * Use a ValueDeserializer to create new values instances from serialized state. - * - *

- * Serialized state must be one of: - *

- *
    - *
  • a ValueComposite,
  • - *
  • an EntityReference,
  • - *
  • a Collection,
  • - *
  • a Map,
  • - *
  • a Plain Value.
  • - *
- *

- * Nested plain values, EntityReferences, Collections, Maps, ValueComposites are supported. - * EntityReferences are deserialized as their reference string. - *

- *

- * Plain values can be one of: - *

- *
    - *
  • String,
  • - *
  • Character or char,
  • - *
  • Boolean or boolean,
  • - *
  • Integer or int,
  • - *
  • Long or long,
  • - *
  • Short or short,
  • - *
  • Byte or byte,
  • - *
  • Float or float,
  • - *
  • Double or double,
  • - *
  • BigInteger,
  • - *
  • BigDecimal,
  • - *
  • Date,
  • - *
  • DateTime (JodaTime),
  • - *
  • LocalDateTime (JodaTime),
  • - *
  • LocalDate (JodaTime).
  • - *
- *

- * Values of unknown types and all arrays are considered as {@link java.io.Serializable} and by so are deserialized - * from base64 encoded bytes using pure Java serialization. If it happens that the input is invalid, a - * ValueSerializationException is thrown. - *

- *

- * Having type information in the serialized payload allows to keep actual ValueComposite types and by so - * circumvent {@link org.apache.polygene.api.composite.AmbiguousTypeException} when deserializing. - *

- */ -public interface ValueDeserializer -{ - - /** - * Factory method for a typed deserialize function. - * - *

The returned Function may throw {@link ValueSerializationException}.

- * - * @param the parametrized function return type - * @param module the module - * @param type the value type - * - * @return a deserialization function - */ - Function deserialize( ModuleDescriptor module, Class type ); - - /** - * Factory method for a typed deserialize function. - * - *

The returned Function may throw {@link ValueSerializationException}.

- * - * @param the parametrized function return type - * @param module the module - * @param valueType the value type - * - * @return a deserialization function - */ - Function deserialize( ModuleDescriptor module, ValueType valueType ); - - /** - * Factory method for an untyped deserialize function. - * - *

The returned Function may throw {@link ValueSerializationException}.

- * - * @param the parametrized function return type - * @return a deserialization function - */ -// BiFunction deserialize(); - - /** - * Deserialize a value from a state. - * - * @param the parametrized returned type - * @param module the module - * @param type the value type - * @param input the state - * - * @return the value - * - * @throws ValueSerializationException if the deserialization failed - */ - T deserialize( ModuleDescriptor module, Class type, String input ) - throws ValueSerializationException; - - /** - * Deserialize a value from a state. - * - * @param the parametrized returned type - * @param module the module - * @param valueType the value type - * @param input the state - * - * @return the value - * - * @throws ValueSerializationException if the deserialization failed - */ - T deserialize( ModuleDescriptor module, ValueType valueType, String input ) - throws ValueSerializationException; - - /** - * Deserialize a value from a state. - * - * @param the parametrized returned type - * @param module the module - * @param type the value type - * @param input the state stream - * - * @return the value - * - * @throws ValueSerializationException if the deserialization failed - */ - T deserialize( ModuleDescriptor module, Class type, InputStream input ) - throws ValueSerializationException; - - /** - * Deserialize a value from a state. - * - * @param the parametrized returned type - * @param module the module - * @param valueType the value type - * @param input the state stream - * - * @return the value - * - * @throws ValueSerializationException if the deserialization failed - */ - T deserialize( ModuleDescriptor module, ValueType valueType, InputStream input ) - throws ValueSerializationException; -} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/17b11697/core/api/src/main/java/org/apache/polygene/api/value/ValueSerialization.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/polygene/api/value/ValueSerialization.java b/core/api/src/main/java/org/apache/polygene/api/value/ValueSerialization.java deleted file mode 100644 index 91c1081..0000000 --- a/core/api/src/main/java/org/apache/polygene/api/value/ValueSerialization.java +++ /dev/null @@ -1,56 +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.api.value; - -/** - * ValueSerialization API. - * - * See {@link ValueSerializer} and {@link ValueDeserializer}. - */ -public interface ValueSerialization - extends ValueSerializer, ValueDeserializer -{ - - /** - * Serialization format @Service tags. - * - *

- * ValueSerialization implementations should be tagged with theses at assembly time so that consumers can - * specify which format they need. - *

- */ - interface Formats - { - - /** - * Tag a ValueSerialization service that support the JSON format. - */ - String JSON = "json"; - /** - * Tag a ValueSerialization service that support the XML format. - */ - String XML = "xml"; - /** - * Tag a ValueSerialization service that support the YAML format. - */ - String YAML = "yaml"; - } - -} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/17b11697/core/api/src/main/java/org/apache/polygene/api/value/ValueSerializationException.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/polygene/api/value/ValueSerializationException.java b/core/api/src/main/java/org/apache/polygene/api/value/ValueSerializationException.java deleted file mode 100644 index 62faa75..0000000 --- a/core/api/src/main/java/org/apache/polygene/api/value/ValueSerializationException.java +++ /dev/null @@ -1,50 +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.api.value; - -/** - * Thrown when an error occur during value state (de)serialization. - */ -public class ValueSerializationException - extends RuntimeException -{ - - private static final long serialVersionUID = 1L; - - public ValueSerializationException() - { - super(); - } - - public ValueSerializationException( String message ) - { - super( message ); - } - - public ValueSerializationException( String message, Throwable cause ) - { - super( message, cause ); - } - - public ValueSerializationException( Throwable cause ) - { - super( cause.getClass().getName() + ": " + cause.getMessage(), cause ); - } -} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/17b11697/core/api/src/main/java/org/apache/polygene/api/value/ValueSerializer.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/polygene/api/value/ValueSerializer.java b/core/api/src/main/java/org/apache/polygene/api/value/ValueSerializer.java deleted file mode 100644 index 736df9d..0000000 --- a/core/api/src/main/java/org/apache/polygene/api/value/ValueSerializer.java +++ /dev/null @@ -1,293 +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.api.value; - -import java.io.OutputStream; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Function; -import org.apache.polygene.api.composite.AmbiguousTypeException; - -/** - * Use a ValueSerializer to serialize values state. - * - *

- * Serialized object must be one of: - *

- *
    - *
  • a ValueComposite,
  • - *
  • an EntityComposite or EntityReference,
  • - *
  • an Iterable,
  • - *
  • a Map,
  • - *
  • a Plain Value.
  • - *
- *

- * Nested plain values, EntityReferences, Iterables, Maps, ValueComposites and EntityComposites are supported. - * EntityComposites and EntityReferences are serialized as their reference string. - *

- *

- * Plain values can be one of: - *

- *
    - *
  • String,
  • - *
  • Character or char,
  • - *
  • Boolean or boolean,
  • - *
  • Integer or int,
  • - *
  • Long or long,
  • - *
  • Short or short,
  • - *
  • Byte or byte,
  • - *
  • Float or float,
  • - *
  • Double or double,
  • - *
  • BigInteger,
  • - *
  • BigDecimal,
  • - *
  • Date,
  • - *
  • DateTime (JodaTime),
  • - *
  • LocalDateTime (JodaTime),
  • - *
  • LocalDate (JodaTime).
  • - *
- *

- * Values of unknown types and all arrays are considered as {@link java.io.Serializable} and by so are serialized to - * base64 encoded bytes using pure Java serialization. If it happens that the value is not Serializable, a - * ValueSerializationException is thrown. - *

- *

- * Having type information in the serialized payload allows to keep actual ValueComposite types and by so - * circumvent {@link AmbiguousTypeException} when deserializing. - *

- */ -public interface ValueSerializer -{ - - /** - * Factory method for a serialize function. - * - * @param the parametrized function input type - * @return a serialization function. - */ - Function serialize(); - - /** - * Factory method for a serialize function. - * - * @param the parametrized function input type - * @param options ValueSerializer Options - * @return a serialization function. - */ - Function serialize( Options options ); - - /** - * Serialize the state of a value with type information. - * - * @param object an Object to serialize - * @return the state - * @throws ValueSerializationException if the Value serialization failed - */ - String serialize( Object object ) - throws ValueSerializationException; - - /** - * Serialize the state of a value. - * - * @param options ValueSerializer Options - * @param object an Object to serialize - * @return the state - * @throws ValueSerializationException if the Value serialization failed - */ - String serialize( Options options, Object object ) - throws ValueSerializationException; - - /** - * Serialize the state of a value with type information. - * - * @param object an Object to serialize - * @param output that will be used as output - * @throws ValueSerializationException if the Value serialization failed - */ - void serialize( Object object, OutputStream output ) - throws ValueSerializationException; - - /** - * Serialize the state of a value. - * - * @param options ValueSerializer Options - * @param object an Object to serialize - * @param output that will be used as output - * @throws ValueSerializationException if the Value serialization failed - */ - void serialize( Options options, Object object, OutputStream output ) - throws ValueSerializationException; - - /** - * Serialization options. - */ - final class Options - { - /** - * Boolean flag to include type information. - * Default to TRUE. - */ - public static final String INCLUDE_TYPE_INFO = "includeTypeInfo"; - public static final String MAP_ENTRIES_AS_OBJECTS = "mapentriesasobjects"; - private final Map options = new HashMap<>(); - - /** - * Create new default ValueSerializer Options. - */ - public Options() - { - this.options.put( INCLUDE_TYPE_INFO, "true" ); - this.options.put( MAP_ENTRIES_AS_OBJECTS, "false" ); - } - - /** - * Set {@link #INCLUDE_TYPE_INFO} option to TRUE. - * @return This - */ - public Options withTypeInfo() - { - return put( INCLUDE_TYPE_INFO, true ); - } - - /** - * Set {@link #INCLUDE_TYPE_INFO} option to FALSE. - * @return This - */ - public Options withoutTypeInfo() - { - return put( INCLUDE_TYPE_INFO, false ); - } - - public Options withMapEntriesAsObjects() - { - return put( MAP_ENTRIES_AS_OBJECTS, true ); - } - - public Options withMapEntriesAsKeyValuePairs() - { - return put( MAP_ENTRIES_AS_OBJECTS, false ); - } - - /** - * Get Boolean option value. - * @param option The option - * @return The boolean value of the option, or null if absent - */ - public Boolean getBoolean( String option ) - { - if( !options.containsKey( option ) ) - { - return null; - } - return Boolean.valueOf( options.get( option ) ); - } - - /** - * Get Integer option value. - * @param option The option - * @return The integer value of the option, or null if absent - */ - public Integer getInteger( String option ) - { - if( !options.containsKey( option ) ) - { - return null; - } - return Integer.valueOf( options.get( option ) ); - } - - /** - * Get String option value. - * @param option The option - * @return The string value of the option, or null if absent - */ - public String getString( String option ) - { - return options.get( option ); - } - - /** - * Put an option String value. - * @param option The option - * @param value The value - * @return This Options instance - */ - public Options put( String option, String value ) - { - if( value == null ) - { - return remove( option ); - } - options.put( option, value ); - return this; - } - - /** - * Put an option boolean value. - * @param option The option - * @param value The value - * @return This Options instance - */ - public Options put( String option, Boolean value ) - { - if( value == null ) - { - return remove( option ); - } - options.put( option, Boolean.toString( value ) ); - return this; - } - - /** - * Put an option Integer value. - * @param option The option - * @param value The value - * @return This Options instance - */ - public Options put( String option, Integer value ) - { - if( value == null ) - { - return remove( option ); - } - options.put( option, value.toString() ); - return this; - } - - /** - * Remove an option value. - * @param option The option - * @return This Options instance - */ - public Options remove( String option ) - { - options.remove( option ); - return this; - } - - /** - * Get all defined options as a Map. - * @return All defined options in a new Map - */ - public Map toMap() - { - return new HashMap<>( options ); - } - } -} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/17b11697/core/api/src/test/java/org/apache/polygene/api/type/HasTypesCollectorsTest.java ---------------------------------------------------------------------- diff --git a/core/api/src/test/java/org/apache/polygene/api/type/HasTypesCollectorsTest.java b/core/api/src/test/java/org/apache/polygene/api/type/HasTypesCollectorsTest.java new file mode 100644 index 0000000..0e92245 --- /dev/null +++ b/core/api/src/test/java/org/apache/polygene/api/type/HasTypesCollectorsTest.java @@ -0,0 +1,131 @@ +package org.apache.polygene.api.type; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import org.apache.polygene.api.identity.Identity; +import org.apache.polygene.api.identity.StringIdentity; +import org.junit.Test; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +public class HasTypesCollectorsTest +{ + @Test + public void selectMatchingTypes() + { + List valueTypes = Arrays.asList( + ValueType.of( String.class ), + ValueType.of( Integer.class ), + ValueType.of( Number.class ) + ); + + List number = valueTypes.stream().collect( HasTypesCollectors.matchingTypes( Number.class ) ); + assertThat( number.size(), is( 2 ) ); + assertThat( number.get( 0 ), equalTo( ValueType.of( Number.class ) ) ); + assertThat( number.get( 1 ), equalTo( ValueType.of( Integer.class ) ) ); + + List integer = valueTypes.stream().collect( HasTypesCollectors.matchingTypes( Integer.class ) ); + assertThat( integer.size(), is( 1 ) ); + assertThat( integer.get( 0 ), equalTo( ValueType.of( Integer.class ) ) ); + } + + @Test + public void selectMatchingType() + { + List valueTypes = Arrays.asList( + ValueType.of( String.class ), + ValueType.of( Double.class ), + ValueType.of( Integer.class ) + ); + + Optional number = valueTypes.stream() + .collect( HasTypesCollectors.matchingType( Number.class ) ); + assertTrue( number.isPresent() ); + assertThat( number.get(), equalTo( ValueType.of( Double.class ) ) ); + + Optional integer = valueTypes.stream() + .collect( HasTypesCollectors.matchingType( Integer.class ) ); + assertTrue( integer.isPresent() ); + assertThat( integer.get(), equalTo( ValueType.of( Integer.class ) ) ); + } + + @Test + public void selectMatchingValueTypes() + { + List valueTypes = Arrays.asList( + ValueType.of( String.class ), + ValueType.of( Number.class, Integer.class ), + ValueType.of( Integer.class ), + ValueType.of( Number.class ) + ); + + List number = valueTypes.stream() + .collect( HasTypesCollectors.matchingTypes( ValueType.of( Number.class ) ) ); + System.out.println( number ); + assertThat( number.size(), is( 2 ) ); + assertThat( number.get( 0 ), equalTo( ValueType.of( Number.class ) ) ); + assertThat( number.get( 1 ), equalTo( ValueType.of( Number.class, Integer.class ) ) ); + + List integer = valueTypes.stream() + .collect( + HasTypesCollectors.matchingTypes( ValueType.of( Integer.class ) ) ); + assertThat( integer.size(), is( 2 ) ); + assertThat( integer.get( 0 ), equalTo( ValueType.of( Integer.class ) ) ); + assertThat( integer.get( 1 ), equalTo( ValueType.of( Number.class, Integer.class ) ) ); + + List both = valueTypes.stream() + .collect( HasTypesCollectors.matchingTypes( ValueType.of( Number.class, + Integer.class ) ) ); + assertThat( both.size(), is( 1 ) ); + assertThat( both.get( 0 ), equalTo( ValueType.of( Number.class, Integer.class ) ) ); + } + + @Test + public void selectMatchingValueType() + { + List valueTypes = Arrays.asList( + ValueType.of( String.class ), + ValueType.of( Number.class, Integer.class ), + ValueType.of( Integer.class ), + ValueType.of( Number.class ) + ); + + Optional number = valueTypes.stream() + .collect( + HasTypesCollectors.matchingType( ValueType.of( Number.class ) ) ); + assertTrue( number.isPresent() ); + assertThat( number.get(), equalTo( ValueType.of( Number.class ) ) ); + + Optional integer = valueTypes.stream() + .collect( + HasTypesCollectors.matchingType( ValueType.of( Integer.class ) ) ); + assertTrue( integer.isPresent() ); + assertThat( integer.get(), equalTo( ValueType.of( Integer.class ) ) ); + + Optional both = valueTypes.stream() + .collect( HasTypesCollectors.matchingType( ValueType.of( Number.class, + Integer.class ) ) ); + assertTrue( both.isPresent() ); + assertThat( both.get(), equalTo( ValueType.of( Number.class, Integer.class ) ) ); + } + + @Test + public void selectClosestValueTypes() + { + List list = new ArrayList() + {{ + add( ValueType.of( String.class ) ); + add( ValueType.of( Identity.class ) ); + }}; + + List result = list.stream() + .collect( HasTypesCollectors.closestTypes( StringIdentity.class ) ); + assertThat( result.size(), is( 1 ) ); + assertThat( result.get( 0 ), equalTo( ValueType.of( Identity.class ) ) ); + } +} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/17b11697/core/api/src/test/java/org/apache/polygene/api/type/HasTypesPredicatesTest.java ---------------------------------------------------------------------- diff --git a/core/api/src/test/java/org/apache/polygene/api/type/HasTypesPredicatesTest.java b/core/api/src/test/java/org/apache/polygene/api/type/HasTypesPredicatesTest.java new file mode 100644 index 0000000..fc87ae6 --- /dev/null +++ b/core/api/src/test/java/org/apache/polygene/api/type/HasTypesPredicatesTest.java @@ -0,0 +1,54 @@ +package org.apache.polygene.api.type; + +import java.time.LocalDate; +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class HasTypesPredicatesTest +{ + @Test + public void hasEqualTypePredicate() + { + assertTrue( new HasEqualType<>( Integer.class ) + .test( ValueType.of( Integer.class ) ) ); + assertTrue( new HasEqualType<>( Integer.class ) + .test( ValueType.of( String.class, Integer.class ) ) ); + assertFalse( new HasEqualType<>( Number.class ) + .test( ValueType.of( String.class, Integer.class ) ) ); + assertFalse( new HasEqualType<>( String.class ) + .test( ValueType.of( LocalDate.class, Integer.class ) ) ); + + assertTrue( new HasEqualType<>( ValueType.of( Integer.class ) ) + .test( ValueType.of( Integer.class ) ) ); + assertTrue( new HasEqualType<>( ValueType.of( Integer.class ) ) + .test( ValueType.of( String.class, Integer.class ) ) ); + assertFalse( new HasEqualType<>( ValueType.of( Number.class ) ) + .test( ValueType.of( String.class, Integer.class ) ) ); + assertFalse( new HasEqualType<>( ValueType.of( String.class ) ) + .test( ValueType.of( LocalDate.class, Integer.class ) ) ); + } + + @Test + public void hasAssignableTypePredicate() + { + assertTrue( new HasAssignableFromType<>( Number.class ) + .test( ValueType.of( String.class, Integer.class ) ) ); + assertFalse( new HasAssignableFromType<>( Integer.class ) + .test( ValueType.of( Integer.class ) ) ); + assertFalse( new HasAssignableFromType<>( String.class ) + .test( ValueType.of( LocalDate.class, Integer.class ) ) ); + } + + @Test + public void hasEqualOrAssignablePredicate() + { + assertTrue( new HasEqualOrAssignableFromType<>( Number.class ) + .test( ValueType.of( String.class, Integer.class ) ) ); + assertTrue( new HasEqualOrAssignableFromType<>( Integer.class ) + .test( ValueType.of( Integer.class ) ) ); + assertFalse( new HasEqualOrAssignableFromType<>( String.class ) + .test( ValueType.of( LocalDate.class, Integer.class ) ) ); + } +} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/17b11697/core/api/src/test/java/org/apache/polygene/api/type/ValueTypeFactoryTest.java ---------------------------------------------------------------------- diff --git a/core/api/src/test/java/org/apache/polygene/api/type/ValueTypeFactoryTest.java b/core/api/src/test/java/org/apache/polygene/api/type/ValueTypeFactoryTest.java new file mode 100644 index 0000000..5b70078 --- /dev/null +++ b/core/api/src/test/java/org/apache/polygene/api/type/ValueTypeFactoryTest.java @@ -0,0 +1,105 @@ +package org.apache.polygene.api.type; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.TimeUnit; +import org.apache.polygene.api.common.UseDefaults; +import org.apache.polygene.api.property.Property; +import org.apache.polygene.api.value.ValueDescriptor; +import org.apache.polygene.bootstrap.ModuleAssembly; +import org.apache.polygene.spi.module.ModuleSpi; +import org.apache.polygene.spi.type.ValueTypeFactory; +import org.apache.polygene.test.AbstractPolygeneTest; +import org.junit.Before; +import org.junit.Test; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.instanceOf; +import static org.junit.Assert.assertThat; + +public class ValueTypeFactoryTest extends AbstractPolygeneTest +{ + private ValueTypeFactory valueTypeFactory; + + @Override + public void assemble( ModuleAssembly module ) + { + module.values( SomeValue.class ); + } + + interface SomeValue + { + @UseDefaults + Property> list(); + + @UseDefaults + Property> map(); + } + + @Before + public void setup() + { + valueTypeFactory = ( (ModuleSpi) module.instance() ).valueTypeFactory(); + } + + @Test + public void plainValues() + { + assertThat( valueTypeFactory.valueTypeOf( module, String.class ), equalTo( ValueType.STRING ) ); + assertThat( valueTypeFactory.valueTypeOf( module, "" ), equalTo( ValueType.STRING ) ); + } + + @Test + public void enums() + { + assertThat( valueTypeFactory.valueTypeOf( module, TimeUnit.class ), instanceOf( EnumType.class ) ); + assertThat( valueTypeFactory.valueTypeOf( module, TimeUnit.DAYS ), instanceOf( EnumType.class ) ); + } + + @Test + public void collections() + { + assertThat( valueTypeFactory.valueTypeOf( module, LinkedHashSet.class ), + instanceOf( CollectionType.class ) ); + + List list = new ArrayList<>(); + ValueType listValueType = valueTypeFactory.valueTypeOf( module, list ); + assertThat( listValueType, instanceOf( CollectionType.class ) ); + assertThat( ( (CollectionType) listValueType ).collectedType(), equalTo( ValueType.OBJECT ) ); + } + + @Test + public void maps() + { + assertThat( valueTypeFactory.valueTypeOf( module, TreeMap.class ), instanceOf( MapType.class ) ); + + HashMap map = new HashMap<>(); + ValueType mapValueType = valueTypeFactory.valueTypeOf( module, map ); + assertThat( mapValueType, instanceOf( MapType.class ) ); + assertThat( ( (MapType) mapValueType ).keyType(), equalTo( ValueType.OBJECT ) ); + assertThat( ( (MapType) mapValueType ).valueType(), equalTo( ValueType.OBJECT ) ); + } + + @Test + public void valueComposites() + { + assertThat( valueTypeFactory.valueTypeOf( module, SomeValue.class ), + instanceOf( ValueCompositeType.class ) ); + assertThat( valueTypeFactory.valueTypeOf( module, valueBuilderFactory.newValue( SomeValue.class ) ), + instanceOf( ValueCompositeType.class ) ); + } + + @Test + public void genericsAreResolvedOnValueCompositeProperties() + { + ValueDescriptor descriptor = module.typeLookup().lookupValueModel( SomeValue.class ); + assertThat( descriptor.state().findPropertyModelByName( "list" ).valueType(), + equalTo( CollectionType.listOf( ValueType.STRING ) ) ); + assertThat( descriptor.state().findPropertyModelByName( "map" ).valueType(), + equalTo( MapType.of( ValueType.STRING, ValueType.INTEGER ) ) ); + } +} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/17b11697/core/api/src/test/java/org/apache/polygene/api/util/CollectorsTest.java ---------------------------------------------------------------------- diff --git a/core/api/src/test/java/org/apache/polygene/api/util/CollectorsTest.java b/core/api/src/test/java/org/apache/polygene/api/util/CollectorsTest.java index 5521b93..1beb26a 100644 --- a/core/api/src/test/java/org/apache/polygene/api/util/CollectorsTest.java +++ b/core/api/src/test/java/org/apache/polygene/api/util/CollectorsTest.java @@ -17,59 +17,99 @@ */ package org.apache.polygene.api.util; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.Optional; import java.util.stream.Stream; import org.junit.Test; +import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; public class CollectorsTest { - @Test - public void single() +@Test +public void single() +{ + assertThat( Stream.of( 1L ).collect( Collectors.single() ), is( 1L ) ); + + try + { + Stream.of().collect( Collectors.single() ); + fail( "Should have failed" ); + } + catch( IllegalArgumentException ex ) {} + try { - assertThat( Stream.of( 1L ).collect( Collectors.single() ), is( 1L ) ); + Stream.of( 1, 1 ).collect( Collectors.single() ); + fail( "Should have failed" ); + } + catch( IllegalArgumentException ex ) {} + try + { + Stream.of( 1, 1, 1 ).collect( Collectors.single() ); + fail( "Should have failed" ); + } + catch( IllegalArgumentException ex ) {} +} - try - { - Stream.of().collect( Collectors.single() ); - fail( "Should have failed" ); - } - catch( IllegalArgumentException ex ) {} - try - { - Stream.of( 1, 1 ).collect( Collectors.single() ); - fail( "Should have failed" ); - } - catch( IllegalArgumentException ex ) {} - try - { - Stream.of( 1, 1, 1 ).collect( Collectors.single() ); - fail( "Should have failed" ); - } - catch( IllegalArgumentException ex ) {} +@Test +public void singleOrEmpty() +{ + assertEquals( Optional.empty(), Stream.of().collect( Collectors.singleOrEmpty() ) ); + assertEquals( Optional.of( 1 ), Stream.of( 1 ).collect( Collectors.singleOrEmpty() ) ); + + try + { + Stream.of( 1, 1 ).collect( Collectors.singleOrEmpty() ); + fail( "Should have failed" ); } + catch( IllegalArgumentException ex ) {} + try + { + Stream.of( 1, 1, 1 ).collect( Collectors.singleOrEmpty() ); + fail( "Should have failed" ); + } + catch( IllegalArgumentException ex ) {} +} @Test - public void singleOrEmpty() + public void toMap() { - assertEquals( Optional.empty(), Stream.of().collect( Collectors.singleOrEmpty() ) ); - assertEquals( Optional.of( 1 ), Stream.of( 1 ).collect( Collectors.singleOrEmpty() ) ); + Map input = new LinkedHashMap<>(); + input.put( "foo", "bar" ); + input.put( "bazar", "cathedral" ); + Map output = input.entrySet().stream().collect( Collectors.toMap() ); + assertThat( output.get( "foo" ), equalTo( "bar" ) ); + assertThat( output.get( "bazar" ), equalTo( "cathedral" ) ); + } + @Test + public void toMapRejectNullValues() + { + Map input = new LinkedHashMap<>(); + input.put( "foo", "bar" ); + input.put( "bazar", null ); try { - Stream.of( 1, 1 ).collect( Collectors.singleOrEmpty() ); - fail( "Should have failed" ); - } - catch( IllegalArgumentException ex ) {} - try - { - Stream.of( 1, 1, 1 ).collect( Collectors.singleOrEmpty() ); - fail( "Should have failed" ); + input.entrySet().stream().collect( Collectors.toMap() ); + fail( "Should have failed, that's the default Map::merge behaviour" ); } - catch( IllegalArgumentException ex ) {} + catch( NullPointerException expected ) {} + } + + @Test + public void toMapWithNullValues() + { + Map input = new LinkedHashMap<>(); + input.put( "foo", "bar" ); + input.put( "bazar", null ); + Map output = input.entrySet().stream().collect( Collectors.toMapWithNullValues() ); + assertThat( output.get( "foo" ), equalTo( "bar" ) ); + assertThat( output.get( "bazar" ), nullValue() ); } }