Repository: zest-java Updated Branches: refs/heads/develop 037e56a63 -> 92e5605ad
ZEST-141 - First implementation of values in @UseDefaults, however it doesn't work properly for lists and maps and complex types has not been tested yet. Removed a lot of duplicated code in CompositeAssemblyImpl and its subclasses. Project: http://git-wip-us.apache.org/repos/asf/zest-java/repo Commit: http://git-wip-us.apache.org/repos/asf/zest-java/commit/92e5605a Tree: http://git-wip-us.apache.org/repos/asf/zest-java/tree/92e5605a Diff: http://git-wip-us.apache.org/repos/asf/zest-java/diff/92e5605a Branch: refs/heads/develop Commit: 92e5605ad891ca0806f9688c14dace57b2237342 Parents: 037e56a Author: Niclas Hedhman <[email protected]> Authored: Fri Jun 10 16:05:05 2016 +0800 Committer: Niclas Hedhman <[email protected]> Committed: Fri Jun 10 16:05:05 2016 +0800 ---------------------------------------------------------------------- .../org/apache/zest/api/common/UseDefaults.java | 8 + .../MissingValueSerializationException.java | 43 +++++ .../zest/bootstrap/MetaInfoDeclaration.java | 14 +- .../bootstrap/CompositeAssemblyImpl.java | 143 +++++++++++++- .../runtime/bootstrap/EntityAssemblyImpl.java | 186 +++---------------- .../runtime/bootstrap/ServiceAssemblyImpl.java | 3 + .../bootstrap/TransientAssemblyImpl.java | 3 + .../runtime/bootstrap/ValueAssemblyImpl.java | 136 +------------- .../zest/runtime/property/PropertyModel.java | 40 +++- .../zest/runtime/defaults/UseDefaultsTest.java | 44 ++++- .../spi/value/ValueDeserializerAdapter.java | 11 +- 11 files changed, 309 insertions(+), 322 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/zest-java/blob/92e5605a/core/api/src/main/java/org/apache/zest/api/common/UseDefaults.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/zest/api/common/UseDefaults.java b/core/api/src/main/java/org/apache/zest/api/common/UseDefaults.java index d72b483..5a36824 100644 --- a/core/api/src/main/java/org/apache/zest/api/common/UseDefaults.java +++ b/core/api/src/main/java/org/apache/zest/api/common/UseDefaults.java @@ -51,6 +51,13 @@ import java.lang.annotation.Target; * is not allowed. * </p> * <p> + * The <code>@UseDefaults</code> annotation can also have a value in its declaration. This value is used, + * unless it is overridden in the assembly (see below). Java does not support generic types of annotation values, + * so it accepts String values, which are deserialized from JSON using the ValueSerialization SPI. This allows + * for (albeit somewhat tedious) any object type to have a default value declared on it. If the property type is + * String, then no value deserialization is done. + * </p> + * <p> * It is also possible to change the default values for Composites during the assembly. This is done by calling the * {@code org.apache.zest.bootstrap.ModuleAssembly#forMixin(Class)} method. * </p> @@ -81,4 +88,5 @@ import java.lang.annotation.Target; @Documented public @interface UseDefaults { + String value() default ""; } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/zest-java/blob/92e5605a/core/api/src/main/java/org/apache/zest/api/value/MissingValueSerializationException.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/zest/api/value/MissingValueSerializationException.java b/core/api/src/main/java/org/apache/zest/api/value/MissingValueSerializationException.java new file mode 100644 index 0000000..c5507ac --- /dev/null +++ b/core/api/src/main/java/org/apache/zest/api/value/MissingValueSerializationException.java @@ -0,0 +1,43 @@ +/* + * 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.zest.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/zest-java/blob/92e5605a/core/bootstrap/src/main/java/org/apache/zest/bootstrap/MetaInfoDeclaration.java ---------------------------------------------------------------------- diff --git a/core/bootstrap/src/main/java/org/apache/zest/bootstrap/MetaInfoDeclaration.java b/core/bootstrap/src/main/java/org/apache/zest/bootstrap/MetaInfoDeclaration.java index 67a0f24..2feafd3 100644 --- a/core/bootstrap/src/main/java/org/apache/zest/bootstrap/MetaInfoDeclaration.java +++ b/core/bootstrap/src/main/java/org/apache/zest/bootstrap/MetaInfoDeclaration.java @@ -144,18 +144,12 @@ public final class MetaInfoDeclaration try { return Proxy.newProxyInstance( returnType.getClassLoader(), new Class[]{ returnType }, - new InvocationHandler() - { - @Override - public Object invoke( Object o, Method method, Object[] objects ) - throws Throwable + ( o1, method1, objects1 ) -> { + if( method1.getName().equals( "set" ) ) { - if( method.getName().equals( "set" ) ) - { - methodInfo.initialValue = objects[ 0 ]; - } - return null; + methodInfo.initialValue = objects1[ 0 ]; } + return null; } ); } catch( IllegalArgumentException e ) http://git-wip-us.apache.org/repos/asf/zest-java/blob/92e5605a/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/CompositeAssemblyImpl.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/CompositeAssemblyImpl.java b/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/CompositeAssemblyImpl.java index 211b2f5..1d1f096 100755 --- a/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/CompositeAssemblyImpl.java +++ b/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/CompositeAssemblyImpl.java @@ -39,6 +39,10 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.apache.zest.api.association.Association; +import org.apache.zest.api.association.GenericAssociationInfo; +import org.apache.zest.api.association.ManyAssociation; +import org.apache.zest.api.association.NamedAssociation; import org.apache.zest.api.common.MetaInfo; import org.apache.zest.api.common.Optional; import org.apache.zest.api.common.QualifiedName; @@ -65,6 +69,12 @@ import org.apache.zest.api.util.Classes; import org.apache.zest.api.util.Fields; import org.apache.zest.bootstrap.StateDeclarations; import org.apache.zest.functional.HierarchicalVisitorAdapter; +import org.apache.zest.runtime.association.AssociationModel; +import org.apache.zest.runtime.association.AssociationsModel; +import org.apache.zest.runtime.association.ManyAssociationModel; +import org.apache.zest.runtime.association.ManyAssociationsModel; +import org.apache.zest.runtime.association.NamedAssociationModel; +import org.apache.zest.runtime.association.NamedAssociationsModel; import org.apache.zest.runtime.composite.AbstractConstraintModel; import org.apache.zest.runtime.composite.CompositeConstraintModel; import org.apache.zest.runtime.composite.CompositeMethodModel; @@ -410,9 +420,7 @@ public abstract class CompositeAssemblyImpl } ); } - protected void addStateFor( AccessibleObject accessor, - List<Class<?>> constraintClasses - ) + protected void addStateFor( AccessibleObject accessor, List<Class<?>> constraintClasses ) { String stateName = QualifiedName.fromAccessor( accessor ).name(); @@ -421,11 +429,42 @@ public abstract class CompositeAssemblyImpl return; // Skip already registered names } - if( Property.class.isAssignableFrom( Classes.RAW_CLASS.apply( typeOf( accessor ) ) ) ) + Class<?> accessorType = Classes.RAW_CLASS.apply( typeOf( accessor ) ); + if( Property.class.isAssignableFrom( accessorType ) ) { propertiesModel.addProperty( newPropertyModel( accessor, constraintClasses ) ); registeredStateNames.add( stateName ); } + else if( Association.class.isAssignableFrom( accessorType ) ) + { + associationsModel().addAssociation( newAssociationModel( accessor, constraintClasses ) ); + registeredStateNames.add( stateName ); + } + else if( ManyAssociation.class.isAssignableFrom( accessorType ) ) + { + manyAssociationsModel().addManyAssociation( newManyAssociationModel( accessor, constraintClasses ) ); + registeredStateNames.add( stateName ); + } + else if( NamedAssociation.class.isAssignableFrom( accessorType ) ) + { + namedAssociationsModel().addNamedAssociation( newNamedAssociationModel( accessor, constraintClasses ) ); + registeredStateNames.add( stateName ); + } + } + + protected AssociationsModel associationsModel() + { + return null; + } + + protected ManyAssociationsModel manyAssociationsModel() + { + return null; + } + + protected NamedAssociationsModel namedAssociationsModel() + { + return null; } protected PropertyModel newPropertyModel( AccessibleObject accessor, @@ -447,8 +486,13 @@ public abstract class CompositeAssemblyImpl valueConstraintsInstance = valueConstraintsModel.newInstance(); } MetaInfo metaInfo = stateDeclarations.metaInfoFor( accessor ); + UseDefaults useDefaultsDeclaration = metaInfo.get( UseDefaults.class ); Object initialValue = stateDeclarations.initialValueOf( accessor ); - boolean useDefaults = metaInfo.get( UseDefaults.class ) != null || stateDeclarations.useDefaults( accessor ); + if( initialValue == null && useDefaultsDeclaration != null ) + { + initialValue = useDefaultsDeclaration.value(); + } + boolean useDefaults = useDefaultsDeclaration != null || stateDeclarations.useDefaults( accessor ); boolean immutable = this.immutable || metaInfo.get( Immutable.class ) != null; return new PropertyModel( accessor, @@ -456,7 +500,8 @@ public abstract class CompositeAssemblyImpl useDefaults, valueConstraintsInstance, metaInfo, - initialValue ); + initialValue + ); } // Model @@ -710,7 +755,9 @@ public abstract class CompositeAssemblyImpl } } - private void addSideEffectOrRepositionIfExists( List<SideEffectModel> sideEffectsFor, SideEffectModel sideEffectModel ) + private void addSideEffectOrRepositionIfExists( List<SideEffectModel> sideEffectsFor, + SideEffectModel sideEffectModel + ) { // This add/remove is to allow reording of SideEffects. sideEffectsFor.remove( sideEffectModel ); @@ -795,4 +842,86 @@ public abstract class CompositeAssemblyImpl return classHierarchy( clazz ).map( Classes.RAW_CLASS ); } } + + public AssociationModel newAssociationModel( AccessibleObject accessor, + List<Class<?>> constraintClasses + ) + { + List<Annotation> annotations = Annotations.findAccessorAndTypeAnnotationsIn( accessor ); + boolean optional = annotations.stream().anyMatch( isType( Optional.class ) ); + + // Constraints for Association references + ValueConstraintsModel valueConstraintsModel = constraintsFor( annotations.stream(), GenericAssociationInfo + .associationTypeOf( accessor ), ( (Member) accessor ).getName(), optional, constraintClasses, accessor ); + ValueConstraintsInstance valueConstraintsInstance = null; + if( valueConstraintsModel.isConstrained() ) + { + valueConstraintsInstance = valueConstraintsModel.newInstance(); + } + + // Constraints for the Association itself + valueConstraintsModel = constraintsFor( annotations.stream(), Association.class, ( (Member) accessor ).getName(), optional, constraintClasses, accessor ); + ValueConstraintsInstance associationValueConstraintsInstance = null; + if( valueConstraintsModel.isConstrained() ) + { + associationValueConstraintsInstance = valueConstraintsModel.newInstance(); + } + + MetaInfo metaInfo = stateDeclarations.metaInfoFor( accessor ); + return new AssociationModel( accessor, valueConstraintsInstance, associationValueConstraintsInstance, metaInfo ); + } + + public ManyAssociationModel newManyAssociationModel( AccessibleObject accessor, + List<Class<?>> constraintClasses + ) + { + List<Annotation> annotations = Annotations.findAccessorAndTypeAnnotationsIn( accessor ); + boolean optional = annotations.stream().anyMatch( isType( Optional.class ) ); + + // Constraints for entities in ManyAssociation + ValueConstraintsModel valueConstraintsModel = constraintsFor( annotations.stream(), GenericAssociationInfo + .associationTypeOf( accessor ), ( (Member) accessor ).getName(), optional, constraintClasses, accessor ); + ValueConstraintsInstance valueConstraintsInstance = null; + if( valueConstraintsModel.isConstrained() ) + { + valueConstraintsInstance = valueConstraintsModel.newInstance(); + } + + // Constraints for the ManyAssociation itself + valueConstraintsModel = constraintsFor( annotations.stream(), ManyAssociation.class, ( (Member) accessor ).getName(), optional, constraintClasses, accessor ); + ValueConstraintsInstance manyValueConstraintsInstance = null; + if( valueConstraintsModel.isConstrained() ) + { + manyValueConstraintsInstance = valueConstraintsModel.newInstance(); + } + MetaInfo metaInfo = stateDeclarations.metaInfoFor( accessor ); + return new ManyAssociationModel( accessor, valueConstraintsInstance, manyValueConstraintsInstance, metaInfo ); + } + + public NamedAssociationModel newNamedAssociationModel( AccessibleObject accessor, + List<Class<?>> constraintClasses + ) + { + List<Annotation> annotations = Annotations.findAccessorAndTypeAnnotationsIn( accessor ); + boolean optional = annotations.stream().anyMatch( isType( Optional.class ) ); + + // Constraints for entities in NamedAssociation + ValueConstraintsModel valueConstraintsModel = constraintsFor( annotations.stream(), GenericAssociationInfo + .associationTypeOf( accessor ), ( (Member) accessor ).getName(), optional, constraintClasses, accessor ); + ValueConstraintsInstance valueConstraintsInstance = null; + if( valueConstraintsModel.isConstrained() ) + { + valueConstraintsInstance = valueConstraintsModel.newInstance(); + } + + // Constraints for the NamedAssociation itself + valueConstraintsModel = constraintsFor( annotations.stream(), NamedAssociation.class, ( (Member) accessor ).getName(), optional, constraintClasses, accessor ); + ValueConstraintsInstance namedValueConstraintsInstance = null; + if( valueConstraintsModel.isConstrained() ) + { + namedValueConstraintsInstance = valueConstraintsModel.newInstance(); + } + MetaInfo metaInfo = stateDeclarations.metaInfoFor( accessor ); + return new NamedAssociationModel( accessor, valueConstraintsInstance, namedValueConstraintsInstance, metaInfo ); + } } http://git-wip-us.apache.org/repos/asf/zest-java/blob/92e5605a/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/EntityAssemblyImpl.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/EntityAssemblyImpl.java b/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/EntityAssemblyImpl.java index d5d0834..4a775f9 100755 --- a/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/EntityAssemblyImpl.java +++ b/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/EntityAssemblyImpl.java @@ -19,36 +19,22 @@ */ package org.apache.zest.runtime.bootstrap; -import org.apache.zest.api.association.Association; -import org.apache.zest.api.association.GenericAssociationInfo; -import org.apache.zest.api.association.ManyAssociation; -import org.apache.zest.api.association.NamedAssociation; -import org.apache.zest.api.common.*; +import org.apache.zest.api.common.InvalidApplicationException; import org.apache.zest.api.entity.EntityComposite; -import org.apache.zest.api.property.GenericPropertyInfo; -import org.apache.zest.api.property.Immutable; -import org.apache.zest.api.property.Property; import org.apache.zest.api.structure.ModuleDescriptor; -import org.apache.zest.api.util.Annotations; -import org.apache.zest.api.util.Classes; -import org.apache.zest.bootstrap.*; -import org.apache.zest.runtime.association.*; +import org.apache.zest.bootstrap.AssociationDeclarations; +import org.apache.zest.bootstrap.EntityAssembly; +import org.apache.zest.bootstrap.ManyAssociationDeclarations; +import org.apache.zest.bootstrap.NamedAssociationDeclarations; +import org.apache.zest.bootstrap.StateDeclarations; +import org.apache.zest.runtime.association.AssociationsModel; +import org.apache.zest.runtime.association.ManyAssociationsModel; +import org.apache.zest.runtime.association.NamedAssociationsModel; import org.apache.zest.runtime.composite.MixinsModel; import org.apache.zest.runtime.composite.StateModel; -import org.apache.zest.runtime.composite.ValueConstraintsInstance; -import org.apache.zest.runtime.composite.ValueConstraintsModel; import org.apache.zest.runtime.entity.EntityMixinsModel; import org.apache.zest.runtime.entity.EntityModel; import org.apache.zest.runtime.entity.EntityStateModel; -import org.apache.zest.runtime.property.PropertyModel; - -import java.lang.annotation.Annotation; -import java.lang.reflect.AccessibleObject; -import java.lang.reflect.Member; -import java.util.List; - -import static org.apache.zest.api.util.Annotations.isType; -import static org.apache.zest.api.util.Classes.typeOf; /** * Declaration of a EntityComposite. @@ -81,6 +67,24 @@ public final class EntityAssemblyImpl } @Override + protected AssociationsModel associationsModel() + { + return associationsModel; + } + + @Override + protected ManyAssociationsModel manyAssociationsModel() + { + return manyAssociationsModel; + } + + @Override + protected NamedAssociationsModel namedAssociationsModel() + { + return namedAssociationsModel; + } + + @Override protected StateModel createStateModel() { return new EntityStateModel( propertiesModel, associationsModel, manyAssociationsModel, namedAssociationsModel ); @@ -114,140 +118,4 @@ public final class EntityAssemblyImpl throw new InvalidApplicationException( "Could not register " + types, e ); } } - - @Override - protected void addStateFor( AccessibleObject accessor, List<Class<?>> constraintClasses ) - { - String stateName = QualifiedName.fromAccessor( accessor ).name(); - - if( registeredStateNames.contains( stateName ) ) - { - return; // Skip already registered names - } - - Class<?> accessorType = Classes.RAW_CLASS.apply( typeOf( accessor ) ); - if( Property.class.isAssignableFrom( accessorType ) ) - { - propertiesModel.addProperty( newPropertyModel( accessor, constraintClasses ) ); - registeredStateNames.add( stateName ); - } - else if( Association.class.isAssignableFrom( accessorType ) ) - { - associationsModel.addAssociation( newAssociationModel( accessor, constraintClasses ) ); - registeredStateNames.add( stateName ); - } - else if( ManyAssociation.class.isAssignableFrom( accessorType ) ) - { - manyAssociationsModel.addManyAssociation( newManyAssociationModel( accessor, constraintClasses ) ); - registeredStateNames.add( stateName ); - } - else if( NamedAssociation.class.isAssignableFrom( accessorType ) ) - { - namedAssociationsModel.addNamedAssociation( newNamedAssociationModel( accessor, constraintClasses ) ); - registeredStateNames.add( stateName ); - } - } - - @Override - protected PropertyModel newPropertyModel( AccessibleObject accessor, - List<Class<?>> constraintClasses - ) - { - List<Annotation> annotations = Annotations.findAccessorAndTypeAnnotationsIn(accessor); - boolean optional = annotations.stream().anyMatch( isType( Optional.class ) ); - ValueConstraintsModel valueConstraintsModel = constraintsFor( annotations.stream(), GenericPropertyInfo.propertyTypeOf( accessor ), ( (Member) accessor ) - .getName(), optional, constraintClasses, accessor ); - ValueConstraintsInstance valueConstraintsInstance = null; - if( valueConstraintsModel.isConstrained() ) - { - valueConstraintsInstance = valueConstraintsModel.newInstance(); - } - MetaInfo metaInfo = stateDeclarations.metaInfoFor( accessor ); - Object defaultValue = stateDeclarations.initialValueOf( accessor ); - boolean useDefaults = metaInfo.get( UseDefaults.class ) != null || stateDeclarations.useDefaults( accessor ); - boolean immutable = this.immutable || metaInfo.get( Immutable.class ) != null; - return new PropertyModel( accessor, immutable, useDefaults, valueConstraintsInstance, metaInfo, defaultValue ); - } - - public AssociationModel newAssociationModel( AccessibleObject accessor, - Iterable<Class<?>> constraintClasses - ) - { - List<Annotation> annotations = Annotations.findAccessorAndTypeAnnotationsIn(accessor); - boolean optional = annotations.stream().anyMatch(isType(Optional.class)); - - // Constraints for Association references - ValueConstraintsModel valueConstraintsModel = constraintsFor( annotations.stream(), GenericAssociationInfo - .associationTypeOf( accessor ), ( (Member) accessor ).getName(), optional, constraintClasses, accessor ); - ValueConstraintsInstance valueConstraintsInstance = null; - if( valueConstraintsModel.isConstrained() ) - { - valueConstraintsInstance = valueConstraintsModel.newInstance(); - } - - // Constraints for the Association itself - valueConstraintsModel = constraintsFor( annotations.stream(), Association.class, ( (Member) accessor ).getName(), optional, constraintClasses, accessor ); - ValueConstraintsInstance associationValueConstraintsInstance = null; - if( valueConstraintsModel.isConstrained() ) - { - associationValueConstraintsInstance = valueConstraintsModel.newInstance(); - } - - MetaInfo metaInfo = associationDeclarations.metaInfoFor( accessor ); - return new AssociationModel( accessor, valueConstraintsInstance, associationValueConstraintsInstance, metaInfo ); - } - - public ManyAssociationModel newManyAssociationModel( AccessibleObject accessor, - List<Class<?>> constraintClasses - ) - { - List<Annotation> annotations = Annotations.findAccessorAndTypeAnnotationsIn(accessor); - boolean optional = annotations.stream().anyMatch(isType(Optional.class)); - - // Constraints for entities in ManyAssociation - ValueConstraintsModel valueConstraintsModel = constraintsFor( annotations.stream(), GenericAssociationInfo - .associationTypeOf( accessor ), ( (Member) accessor ).getName(), optional, constraintClasses, accessor ); - ValueConstraintsInstance valueConstraintsInstance = null; - if( valueConstraintsModel.isConstrained() ) - { - valueConstraintsInstance = valueConstraintsModel.newInstance(); - } - - // Constraints for the ManyAssociation itself - valueConstraintsModel = constraintsFor( annotations.stream(), ManyAssociation.class, ( (Member) accessor ).getName(), optional, constraintClasses, accessor ); - ValueConstraintsInstance manyValueConstraintsInstance = null; - if( valueConstraintsModel.isConstrained() ) - { - manyValueConstraintsInstance = valueConstraintsModel.newInstance(); - } - MetaInfo metaInfo = manyAssociationDeclarations.metaInfoFor( accessor ); - return new ManyAssociationModel( accessor, valueConstraintsInstance, manyValueConstraintsInstance, metaInfo ); - } - - public NamedAssociationModel newNamedAssociationModel( AccessibleObject accessor, - List<Class<?>> constraintClasses - ) - { - List<Annotation> annotations = Annotations.findAccessorAndTypeAnnotationsIn(accessor); - boolean optional = annotations.stream().anyMatch( isType( Optional.class ) ); - - // Constraints for entities in NamedAssociation - ValueConstraintsModel valueConstraintsModel = constraintsFor( annotations.stream(), GenericAssociationInfo - .associationTypeOf( accessor ), ( (Member) accessor ).getName(), optional, constraintClasses, accessor ); - ValueConstraintsInstance valueConstraintsInstance = null; - if( valueConstraintsModel.isConstrained() ) - { - valueConstraintsInstance = valueConstraintsModel.newInstance(); - } - - // Constraints for the NamedAssociation itself - valueConstraintsModel = constraintsFor( annotations.stream(), NamedAssociation.class, ( (Member) accessor ).getName(), optional, constraintClasses, accessor ); - ValueConstraintsInstance namedValueConstraintsInstance = null; - if( valueConstraintsModel.isConstrained() ) - { - namedValueConstraintsInstance = valueConstraintsModel.newInstance(); - } - MetaInfo metaInfo = namedAssociationDeclarations.metaInfoFor( accessor ); - return new NamedAssociationModel( accessor, valueConstraintsInstance, namedValueConstraintsInstance, metaInfo ); - } } http://git-wip-us.apache.org/repos/asf/zest-java/blob/92e5605a/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ServiceAssemblyImpl.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ServiceAssemblyImpl.java b/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ServiceAssemblyImpl.java index 7180012..6cdcaf4 100644 --- a/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ServiceAssemblyImpl.java +++ b/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ServiceAssemblyImpl.java @@ -35,6 +35,9 @@ import org.apache.zest.bootstrap.ServiceAssembly; import org.apache.zest.bootstrap.StateDeclarations; import org.apache.zest.functional.Iterables; import org.apache.zest.runtime.activation.ActivatorsModel; +import org.apache.zest.runtime.association.AssociationsModel; +import org.apache.zest.runtime.association.ManyAssociationsModel; +import org.apache.zest.runtime.association.NamedAssociationsModel; import org.apache.zest.runtime.service.ServiceModel; import org.apache.zest.runtime.structure.ModuleModel; http://git-wip-us.apache.org/repos/asf/zest-java/blob/92e5605a/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/TransientAssemblyImpl.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/TransientAssemblyImpl.java b/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/TransientAssemblyImpl.java index 52e436f..f2b531d 100644 --- a/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/TransientAssemblyImpl.java +++ b/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/TransientAssemblyImpl.java @@ -25,6 +25,9 @@ import org.apache.zest.api.composite.TransientComposite; import org.apache.zest.api.structure.ModuleDescriptor; import org.apache.zest.bootstrap.StateDeclarations; import org.apache.zest.bootstrap.TransientAssembly; +import org.apache.zest.runtime.association.AssociationsModel; +import org.apache.zest.runtime.association.ManyAssociationsModel; +import org.apache.zest.runtime.association.NamedAssociationsModel; import org.apache.zest.runtime.composite.TransientModel; /** http://git-wip-us.apache.org/repos/asf/zest-java/blob/92e5605a/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ValueAssemblyImpl.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ValueAssemblyImpl.java b/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ValueAssemblyImpl.java index f5fed54..9b8db5d 100755 --- a/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ValueAssemblyImpl.java +++ b/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ValueAssemblyImpl.java @@ -33,6 +33,7 @@ import org.apache.zest.api.common.Optional; import org.apache.zest.api.common.QualifiedName; import org.apache.zest.api.common.UseDefaults; import org.apache.zest.api.property.GenericPropertyInfo; +import org.apache.zest.api.property.Immutable; import org.apache.zest.api.property.Property; import org.apache.zest.api.structure.ModuleDescriptor; import org.apache.zest.api.util.Annotations; @@ -94,7 +95,6 @@ public final class ValueAssemblyImpl manyAssociationsModel = new ManyAssociationsModel(); namedAssociationsModel = new NamedAssociationsModel(); buildComposite( helper, stateDeclarations ); - return new ValueModel( module, types, visibility, metaInfo, mixinsModel, (ValueStateModel) stateModel, compositeMethodsModel ); } @@ -104,140 +104,18 @@ public final class ValueAssemblyImpl } } - @Override - protected void addStateFor( AccessibleObject accessor, - List<Class<?>> constraintClasses - ) + protected AssociationsModel associationsModel() { - String stateName = QualifiedName.fromAccessor( accessor ).name(); - - if( registeredStateNames.contains( stateName ) ) - { - return; // Skip already registered names - } - - Class<?> accessorType = Classes.RAW_CLASS.apply( typeOf( accessor ) ); - if( Property.class.isAssignableFrom( accessorType ) ) - { - propertiesModel.addProperty( newPropertyModel( accessor, constraintClasses ) ); - registeredStateNames.add( stateName ); - } - else if( Association.class.isAssignableFrom( accessorType ) ) - { - associationsModel.addAssociation( newAssociationModel( accessor, constraintClasses ) ); - registeredStateNames.add( stateName ); - } - else if( ManyAssociation.class.isAssignableFrom( accessorType ) ) - { - manyAssociationsModel.addManyAssociation( newManyAssociationModel( accessor, constraintClasses ) ); - registeredStateNames.add( stateName ); - } - else if( NamedAssociation.class.isAssignableFrom( accessorType ) ) - { - namedAssociationsModel.addNamedAssociation( newNamedAssociationModel( accessor, constraintClasses ) ); - registeredStateNames.add( stateName ); - } + return associationsModel; } - @Override - protected PropertyModel newPropertyModel( AccessibleObject accessor, - List<Class<?>> constraintClasses - ) + protected ManyAssociationsModel manyAssociationsModel() { - List<Annotation> annotations = Annotations.findAccessorAndTypeAnnotationsIn( accessor ); - boolean optional = annotations.stream().anyMatch( isType( Optional.class ) ); - ValueConstraintsModel valueConstraintsModel = constraintsFor( annotations.stream(), GenericPropertyInfo.propertyTypeOf( accessor ), ( (Member) accessor ) - .getName(), optional, constraintClasses, accessor ); - ValueConstraintsInstance valueConstraintsInstance = null; - if( valueConstraintsModel.isConstrained() ) - { - valueConstraintsInstance = valueConstraintsModel.newInstance(); - } - MetaInfo metaInfo = stateDeclarations.metaInfoFor( accessor ); - boolean useDefaults = metaInfo.get( UseDefaults.class ) != null || stateDeclarations.useDefaults( accessor ); - Object initialValue = stateDeclarations.initialValueOf( accessor ); - return new PropertyModel( accessor, true, useDefaults, valueConstraintsInstance, metaInfo, initialValue ); + return manyAssociationsModel; } - public AssociationModel newAssociationModel( AccessibleObject accessor, - List<Class<?>> constraintClasses - ) + protected NamedAssociationsModel namedAssociationsModel() { - List<Annotation> annotations = Annotations.findAccessorAndTypeAnnotationsIn( accessor ); - boolean optional = annotations.stream().anyMatch( isType( Optional.class ) ); - - // Constraints for Association references - ValueConstraintsModel valueConstraintsModel = constraintsFor( annotations.stream(), GenericAssociationInfo - .associationTypeOf( accessor ), ( (Member) accessor ).getName(), optional, constraintClasses, accessor ); - ValueConstraintsInstance valueConstraintsInstance = null; - if( valueConstraintsModel.isConstrained() ) - { - valueConstraintsInstance = valueConstraintsModel.newInstance(); - } - - // Constraints for the Association itself - valueConstraintsModel = constraintsFor( annotations.stream(), Association.class, ( (Member) accessor ).getName(), optional, constraintClasses, accessor ); - ValueConstraintsInstance associationValueConstraintsInstance = null; - if( valueConstraintsModel.isConstrained() ) - { - associationValueConstraintsInstance = valueConstraintsModel.newInstance(); - } - - MetaInfo metaInfo = stateDeclarations.metaInfoFor( accessor ); - return new AssociationModel( accessor, valueConstraintsInstance, associationValueConstraintsInstance, metaInfo ); - } - - public ManyAssociationModel newManyAssociationModel( AccessibleObject accessor, - List<Class<?>> constraintClasses - ) - { - List<Annotation> annotations = Annotations.findAccessorAndTypeAnnotationsIn( accessor ); - boolean optional = annotations.stream().anyMatch( isType( Optional.class ) ); - - // Constraints for entities in ManyAssociation - ValueConstraintsModel valueConstraintsModel = constraintsFor( annotations.stream(), GenericAssociationInfo - .associationTypeOf( accessor ), ( (Member) accessor ).getName(), optional, constraintClasses, accessor ); - ValueConstraintsInstance valueConstraintsInstance = null; - if( valueConstraintsModel.isConstrained() ) - { - valueConstraintsInstance = valueConstraintsModel.newInstance(); - } - - // Constraints for the ManyAssociation itself - valueConstraintsModel = constraintsFor( annotations.stream(), ManyAssociation.class, ( (Member) accessor ).getName(), optional, constraintClasses, accessor ); - ValueConstraintsInstance manyValueConstraintsInstance = null; - if( valueConstraintsModel.isConstrained() ) - { - manyValueConstraintsInstance = valueConstraintsModel.newInstance(); - } - MetaInfo metaInfo = stateDeclarations.metaInfoFor( accessor ); - return new ManyAssociationModel( accessor, valueConstraintsInstance, manyValueConstraintsInstance, metaInfo ); - } - - public NamedAssociationModel newNamedAssociationModel( AccessibleObject accessor, - List<Class<?>> constraintClasses - ) - { - List<Annotation> annotations = Annotations.findAccessorAndTypeAnnotationsIn( accessor ); - boolean optional = annotations.stream().anyMatch( isType( Optional.class ) ); - - // Constraints for entities in NamedAssociation - ValueConstraintsModel valueConstraintsModel = constraintsFor( annotations.stream(), GenericAssociationInfo - .associationTypeOf( accessor ), ( (Member) accessor ).getName(), optional, constraintClasses, accessor ); - ValueConstraintsInstance valueConstraintsInstance = null; - if( valueConstraintsModel.isConstrained() ) - { - valueConstraintsInstance = valueConstraintsModel.newInstance(); - } - - // Constraints for the NamedAssociation itself - valueConstraintsModel = constraintsFor( annotations.stream(), NamedAssociation.class, ( (Member) accessor ).getName(), optional, constraintClasses, accessor ); - ValueConstraintsInstance namedValueConstraintsInstance = null; - if( valueConstraintsModel.isConstrained() ) - { - namedValueConstraintsInstance = valueConstraintsModel.newInstance(); - } - MetaInfo metaInfo = stateDeclarations.metaInfoFor( accessor ); - return new NamedAssociationModel( accessor, valueConstraintsInstance, namedValueConstraintsInstance, metaInfo ); + return namedAssociationsModel; } } http://git-wip-us.apache.org/repos/asf/zest-java/blob/92e5605a/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyModel.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyModel.java index 981f09d..807194f 100644 --- a/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyModel.java +++ b/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyModel.java @@ -38,12 +38,14 @@ import org.apache.zest.api.property.GenericPropertyInfo; import org.apache.zest.api.property.InvalidPropertyTypeException; import org.apache.zest.api.property.Property; import org.apache.zest.api.property.PropertyDescriptor; -import org.apache.zest.api.structure.Module; +import org.apache.zest.api.service.NoSuchServiceException; import org.apache.zest.api.structure.ModuleDescriptor; import org.apache.zest.api.type.Serialization; import org.apache.zest.api.type.ValueCompositeType; import org.apache.zest.api.type.ValueType; import org.apache.zest.api.util.Classes; +import org.apache.zest.api.value.MissingValueSerializationException; +import org.apache.zest.api.value.ValueDeserializer; import org.apache.zest.bootstrap.BindingException; import org.apache.zest.functional.Visitable; import org.apache.zest.functional.Visitor; @@ -176,18 +178,44 @@ public class PropertyModel Object value = initialValue; // Check for @UseDefaults annotation - if( value == null && useDefaults ) + if( useDefaults ) { - if( valueType instanceof ValueCompositeType ) + if( value == null || ( ( value instanceof String ) && ( (String) value ).length() == 0 ) ) { - return module.instance().newValue( valueType().types().findFirst().orElse( null ) ); + if( valueType instanceof ValueCompositeType ) + { + Class<?> propertyType = valueType().types().findFirst().orElse( null ); + value = module.instance().newValue( propertyType ); + } + else + { + value = DefaultValues.getDefaultValueOf( type ); + } } else { - value = DefaultValues.getDefaultValueOf( type ); + Class<?> propertyType = valueType().types().findFirst().orElse( null ); + if( value instanceof String && !propertyType.equals( String.class ) ) + { + try + { + // here we could possibly deserialize json to other types... + ValueDeserializer deserializer = module.instance() + .serviceFinder() + .findService( ValueDeserializer.class ) + .get(); + if( deserializer != null ) + { + value = deserializer.deserialize( module, propertyType ).apply( (String) value ); + } + } + catch( NoSuchServiceException e ) + { + throw new MissingValueSerializationException( "@UseDefaults with initialization value requires that there is a visible ValueDeserializer service available.", e); + } + } } } - return value; } http://git-wip-us.apache.org/repos/asf/zest-java/blob/92e5605a/core/runtime/src/test/java/org/apache/zest/runtime/defaults/UseDefaultsTest.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/test/java/org/apache/zest/runtime/defaults/UseDefaultsTest.java b/core/runtime/src/test/java/org/apache/zest/runtime/defaults/UseDefaultsTest.java index 4354a2d..9f9ac92 100644 --- a/core/runtime/src/test/java/org/apache/zest/runtime/defaults/UseDefaultsTest.java +++ b/core/runtime/src/test/java/org/apache/zest/runtime/defaults/UseDefaultsTest.java @@ -20,15 +20,20 @@ package org.apache.zest.runtime.defaults; -import org.junit.Test; +import java.util.Collections; +import java.util.List; +import java.util.Map; import org.apache.zest.api.common.Optional; import org.apache.zest.api.common.UseDefaults; import org.apache.zest.api.composite.TransientBuilder; import org.apache.zest.api.composite.TransientComposite; import org.apache.zest.api.property.Property; +import org.apache.zest.api.value.ValueDeserializer; import org.apache.zest.bootstrap.AssemblyException; import org.apache.zest.bootstrap.ModuleAssembly; import org.apache.zest.test.AbstractZestTest; +import org.apache.zest.valueserialization.orgjson.OrgJsonValueDeserializer; +import org.junit.Test; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.nullValue; @@ -44,7 +49,8 @@ public class UseDefaultsTest throws AssemblyException { module.transients( TestComposite.class ); - module.forMixin( TestComposite.class ).declareDefaults().assemblyString(); + module.services( ValueDeserializer.class ).withMixins( OrgJsonValueDeserializer.class ); + module.forMixin( TestComposite.class ).declareDefaults().assemblyString().set( "habba" ); } @Test @@ -57,7 +63,22 @@ public class UseDefaultsTest assertThat( "zeroInt is zero", testComposite.defaultInt().get(), equalTo( 0 ) ); assertThat( "nullString is null", testComposite.nullString().get(), nullValue() ); assertThat( "defaultString is empty string", testComposite.defaultString().get(), equalTo( "" ) ); - assertThat( "assemblyString is empty string", testComposite.assemblyString().get(), equalTo( "" ) ); + assertThat( "assemblyString is empty string", testComposite.assemblyString().get(), equalTo( "habba" ) ); + } + + @Test + public void givenPropertyWithValuedUseDefaultsWhenInstantiatedExpectCorrectDefaultValues() + { + TransientBuilder<TestComposite> builder = transientBuilderFactory.newTransientBuilder( TestComposite.class ); + TestComposite testComposite = builder.newInstance(); + + assertThat( testComposite.initializedStringDefault().get(), equalTo( "abc" ) ); + assertThat( testComposite.initializedIntegerDefaultValue().get(), equalTo( 123 ) ); + assertThat( testComposite.initializedFloatDefaultValue().get(), equalTo( 123.45f ) ); + List<String> expectedList = Collections.singletonList( "abcde" ); +// assertThat( testComposite.initializedStringListDefultString().get(), equalTo( expectedList) ); + Map<String, Integer> expectedMap = Collections.singletonMap( "abcd", 345 ); +// assertThat( testComposite.initializedMapDefaultValue().get(), equalTo( expectedMap) ); } interface TestComposite @@ -78,5 +99,22 @@ public class UseDefaultsTest Property<String> defaultString(); Property<String> assemblyString(); + + @UseDefaults( "abc" ) + Property<String> initializedStringDefault(); + + @UseDefaults( "123" ) + Property<Integer> initializedIntegerDefaultValue(); + + @UseDefaults( "123.45" ) + Property<Float> initializedFloatDefaultValue(); + +// TODO: Seems that OrgJsonValueDeserializer has problem with arrays. +// @UseDefaults( "[\"abcde\"]" ) +// Property<List<String>> initializedStringListDefultString(); + +// TODO: Seems that OrgJsonValueDeserializer has problem with arrays. +// @UseDefaults( "{\"abcd\" : 345 }" ) +// Property<Map<String, Integer>> initializedMapDefaultValue(); } } http://git-wip-us.apache.org/repos/asf/zest-java/blob/92e5605a/core/spi/src/main/java/org/apache/zest/spi/value/ValueDeserializerAdapter.java ---------------------------------------------------------------------- diff --git a/core/spi/src/main/java/org/apache/zest/spi/value/ValueDeserializerAdapter.java b/core/spi/src/main/java/org/apache/zest/spi/value/ValueDeserializerAdapter.java index b46c27a..a3c72e1 100644 --- a/core/spi/src/main/java/org/apache/zest/spi/value/ValueDeserializerAdapter.java +++ b/core/spi/src/main/java/org/apache/zest/spi/value/ValueDeserializerAdapter.java @@ -188,12 +188,6 @@ public abstract class ValueDeserializerAdapter<InputType, InputNodeType> return input -> deserialize( module, valueType, input ); } -// @Override -// public final <T> BiFunction<ValueType, String, T> deserialize() -// { -// return this::deserialize; -// } - @Override public final <T> T deserialize( ModuleDescriptor module, Class<?> type, String input ) throws ValueSerializationException @@ -270,7 +264,8 @@ public abstract class ValueDeserializerAdapter<InputType, InputNodeType> { final Class<?> type = valueType.types().findFirst().orElse( null ); // Plain ValueType - if( deserializers.get( type ) != null ) + Function<Object, Object> deserializationFunction = deserializers.get( type ); + if( deserializationFunction != null ) { Scanner scanner = new Scanner( input, UTF_8 ).useDelimiter( "\\A" ); if( !scanner.hasNext() ) @@ -278,7 +273,7 @@ public abstract class ValueDeserializerAdapter<InputType, InputNodeType> return String.class.equals( type ) ? (T) "" : null; } String string = scanner.next(); - return (T) deserializers.get( type ).apply( string ); + return (T) deserializationFunction.apply( string ); } else // Array ValueType if( type.isArray() )
