Return-Path: X-Original-To: apmail-zest-commits-archive@minotaur.apache.org Delivered-To: apmail-zest-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id B009417A53 for ; Tue, 9 Jun 2015 23:58:00 +0000 (UTC) Received: (qmail 82046 invoked by uid 500); 9 Jun 2015 23:58:00 -0000 Delivered-To: apmail-zest-commits-archive@zest.apache.org Received: (qmail 81992 invoked by uid 500); 9 Jun 2015 23:58:00 -0000 Mailing-List: contact commits-help@zest.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@zest.apache.org Delivered-To: mailing list commits@zest.apache.org Received: (qmail 81704 invoked by uid 99); 9 Jun 2015 23:57:59 -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; Tue, 09 Jun 2015 23:57:59 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id BAD1EE0329; Tue, 9 Jun 2015 23:57:59 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: niclas@apache.org To: commits@zest.apache.org Date: Tue, 09 Jun 2015 23:58:06 -0000 Message-Id: <5f3c17d2b488467badb3814573fe0fd1@git.apache.org> In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [08/14] zest-qi4j git commit: Fix for ZEST-23. + Putting the toValue() and toEntity() into the UnitOfWork instead f the SPI. + Adding access to the EntityReference in Associations. Fix for ZEST-23. + Putting the toValue() and toEntity() into the UnitOfWork instead f the SPI. + Adding access to the EntityReference in Associations. Project: http://git-wip-us.apache.org/repos/asf/zest-qi4j/repo Commit: http://git-wip-us.apache.org/repos/asf/zest-qi4j/commit/568fa2ff Tree: http://git-wip-us.apache.org/repos/asf/zest-qi4j/tree/568fa2ff Diff: http://git-wip-us.apache.org/repos/asf/zest-qi4j/diff/568fa2ff Branch: refs/heads/develop Commit: 568fa2ff3fe8abb4ff66c286e8675ed7ad285e64 Parents: e6d2d6b Author: Niclas Hedhman Authored: Wed Jun 3 12:22:31 2015 +0800 Committer: Niclas Hedhman Committed: Wed Jun 3 12:22:31 2015 +0800 ---------------------------------------------------------------------- core/api/src/main/java/org/qi4j/api/Qi4j.java | 71 ------ .../org/qi4j/api/association/Association.java | 7 + .../api/association/AssociationWrapper.java | 8 + .../qi4j/api/association/ManyAssociation.java | 11 + .../api/association/ManyAssociationWrapper.java | 7 + .../qi4j/api/association/NamedAssociation.java | 6 + .../association/NamedAssociationWrapper.java | 7 + .../org/qi4j/api/entity/EntityReference.java | 7 + .../org/qi4j/api/unitofwork/UnitOfWork.java | 74 ++++++ .../java/org/qi4j/runtime/Qi4jRuntimeImpl.java | 213 ----------------- .../AbstractAssociationInstance.java | 31 +-- .../association/AssociationInstance.java | 13 +- .../association/ManyAssociationInstance.java | 33 ++- .../association/NamedAssociationInstance.java | 35 ++- .../runtime/structure/ModuleUnitOfWork.java | 235 ++++++++++++++++++- .../unitofwork/EntityBuilderInstance.java | 11 +- .../runtime/value/ValueWithAssociationTest.java | 53 ++++- .../qi4j/spi/value/ValueSerializerAdapter.java | 129 +++++----- .../binding/internal/BoundAssociation.java | 7 + .../binding/internal/BoundManyAssociation.java | 7 + .../binding/internal/BoundNamedAssociation.java | 7 + .../swing/binding/internal/BoundProperty.java | 11 +- 22 files changed, 557 insertions(+), 426 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/568fa2ff/core/api/src/main/java/org/qi4j/api/Qi4j.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/qi4j/api/Qi4j.java b/core/api/src/main/java/org/qi4j/api/Qi4j.java index d8f2d29..0b40c4a 100644 --- a/core/api/src/main/java/org/qi4j/api/Qi4j.java +++ b/core/api/src/main/java/org/qi4j/api/Qi4j.java @@ -135,77 +135,6 @@ public interface Qi4j AssociationDescriptor associationDescriptorFor( AbstractAssociation association ); /** - * Converts the provided Entity to a Value of the same type. - * This is a convenience method to convert an EntityComposite to a ValueComposite. - *

- * All Property values are transferred across as-is, and the Association, ManyAssociation - * and NamedAssociatino values are kept in the ValueComposite as EntityReferences - * until they are dereferenced (get() and other methods), and IF a UnitOfWork is - * present at dereferencing the corresponding EntityCompoiste is retrieved from the - * EntityStore. If there is not an UnitOfWork present, an exception is thrown. - *

- * For this to work, the Composites (both Entity and Value) must not declare the - * EntityComposite and ValueComposite super types, but rely on the declaration in - * the assembly, and also extend the Identity supertype. - * - * Example; - *


-     *     public interface Person extends Identity { ... };
-     *     public class MyAssembler
-     *     {
-     *         public void assemble( ModuleAssembly module )
-     *         {
-     *             module.values( Person.class );
-     *             module.entities( Person.class );
-     *         }
-     *     }
-     * 
- * - * @param primaryType The shared type for which the properties and associations will - * be converted. Properties outside this type will be ignored. - * @param entityComposite The entity to be convered. - */ - T toValue( Class primaryType, T entityComposite ); - - /** - * Converts the provided Value to an Entity of the same type. - * This is a convenience method to convert a ValueComposite to an EntityComposite. - *

- * All Property values are transferred across as-is (no deep copy in case mutable - * types (DISCOURAGED!) are used), and the Association, ManyAssociation - * and NamedAssociatino that were in the ValueComposite as EntityReferences are - * transferred into the EntityComposite correctly, and can be dereferenced. - *

- * This method MUST be called within a UnitOfWork. - *

- * If an Entity with the Identity in the ValueComposite already exists, then that - * Entity is updated with the values from the ValueComposite. If an Entity of - * that Identity doesn't exist and new one is created. - *

- * For this to work, the Composites (both Entity and Value) must not declare the - * EntityComposite and ValueComposite super types, but rely on the declaration in - * the assembly, and also extend the Identity supertype. - * - * Example; - *


-     *     public interface Person extends Identity { ... };
-     *     public class MyAssembler
-     *     {
-     *         public void assemble( ModuleAssembly module )
-     *         {
-     *             module.values( Person.class );
-     *             module.entities( Person.class );
-     *         }
-     *     }
-     * 
- * - * @param primaryType The shared type for which the properties and associations will - * be converted. Properties outside this type will be ignored. - * @param valueComposite The Value to be convered into an Entity. - */ - T toEntity( Class primaryType, T valueComposite ); - - /** * Function that returns the CompositeDescriptor of a Composite. */ Function FUNCTION_DESCRIPTOR_FOR = new Function() http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/568fa2ff/core/api/src/main/java/org/qi4j/api/association/Association.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/qi4j/api/association/Association.java b/core/api/src/main/java/org/qi4j/api/association/Association.java index f262a8c..acd406f 100644 --- a/core/api/src/main/java/org/qi4j/api/association/Association.java +++ b/core/api/src/main/java/org/qi4j/api/association/Association.java @@ -14,6 +14,8 @@ package org.qi4j.api.association; +import org.qi4j.api.entity.EntityReference; + /** * Association to a single EntityComposite. */ @@ -36,4 +38,9 @@ public interface Association extends AbstractAssociation */ void set( T associated ) throws IllegalArgumentException, IllegalStateException; + + /** + * @return the the reference of the associated entity. + */ + EntityReference reference(); } http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/568fa2ff/core/api/src/main/java/org/qi4j/api/association/AssociationWrapper.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/qi4j/api/association/AssociationWrapper.java b/core/api/src/main/java/org/qi4j/api/association/AssociationWrapper.java index 4e907de..fd5af6f 100644 --- a/core/api/src/main/java/org/qi4j/api/association/AssociationWrapper.java +++ b/core/api/src/main/java/org/qi4j/api/association/AssociationWrapper.java @@ -1,5 +1,7 @@ package org.qi4j.api.association; +import org.qi4j.api.entity.EntityReference; + /** * If you want to catch getting and setting association, then create a GenericConcern * that wraps the Qi4j-supplied Association instance with AssociationWrappers. Override @@ -34,6 +36,12 @@ public class AssociationWrapper } @Override + public EntityReference reference() + { + return next.reference(); + } + + @Override public int hashCode() { return next.hashCode(); http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/568fa2ff/core/api/src/main/java/org/qi4j/api/association/ManyAssociation.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/qi4j/api/association/ManyAssociation.java b/core/api/src/main/java/org/qi4j/api/association/ManyAssociation.java index 707d53a..37d7211 100644 --- a/core/api/src/main/java/org/qi4j/api/association/ManyAssociation.java +++ b/core/api/src/main/java/org/qi4j/api/association/ManyAssociation.java @@ -16,12 +16,17 @@ package org.qi4j.api.association; import java.util.List; import java.util.Set; +import org.qi4j.api.entity.EntityReference; /** * Association to a collection of entities. */ public interface ManyAssociation extends Iterable, AbstractAssociation { + /** + * Returns the number of references in this association. + * @return the number of references in this association. + */ int count(); boolean contains( T entity ); @@ -37,4 +42,10 @@ public interface ManyAssociation extends Iterable, AbstractAssociation List toList(); Set toSet(); + + /** + * Returns an unmodifiable Iterable of the references to the associated entities. + * @return the references to the associated entities. + */ + Iterable references(); } http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/568fa2ff/core/api/src/main/java/org/qi4j/api/association/ManyAssociationWrapper.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/qi4j/api/association/ManyAssociationWrapper.java b/core/api/src/main/java/org/qi4j/api/association/ManyAssociationWrapper.java index 748af83..c844f0b 100644 --- a/core/api/src/main/java/org/qi4j/api/association/ManyAssociationWrapper.java +++ b/core/api/src/main/java/org/qi4j/api/association/ManyAssociationWrapper.java @@ -3,6 +3,7 @@ package org.qi4j.api.association; import java.util.Iterator; import java.util.List; import java.util.Set; +import org.qi4j.api.entity.EntityReference; /** * If you want to catch calls to ManyAssociations, then create a GenericConcern @@ -73,6 +74,12 @@ public class ManyAssociationWrapper } @Override + public Iterable references() + { + return next.references(); + } + + @Override public Iterator iterator() { return next.iterator(); http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/568fa2ff/core/api/src/main/java/org/qi4j/api/association/NamedAssociation.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/qi4j/api/association/NamedAssociation.java b/core/api/src/main/java/org/qi4j/api/association/NamedAssociation.java index e8abe32..9464eed 100644 --- a/core/api/src/main/java/org/qi4j/api/association/NamedAssociation.java +++ b/core/api/src/main/java/org/qi4j/api/association/NamedAssociation.java @@ -19,6 +19,7 @@ package org.qi4j.api.association; import java.util.Map; +import org.qi4j.api.entity.EntityReference; /** * Association to named Entities. @@ -75,4 +76,9 @@ public interface NamedAssociation */ Map toMap(); + /** + * Returns an unmodifiable Iterable of the references to the associated entities. + * @return the references to the associated entities. + */ + Iterable references(); } http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/568fa2ff/core/api/src/main/java/org/qi4j/api/association/NamedAssociationWrapper.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/qi4j/api/association/NamedAssociationWrapper.java b/core/api/src/main/java/org/qi4j/api/association/NamedAssociationWrapper.java index 581948e..7d0640e 100644 --- a/core/api/src/main/java/org/qi4j/api/association/NamedAssociationWrapper.java +++ b/core/api/src/main/java/org/qi4j/api/association/NamedAssociationWrapper.java @@ -20,6 +20,7 @@ package org.qi4j.api.association; import java.util.Iterator; import java.util.Map; +import org.qi4j.api.entity.EntityReference; /** * If you want to catch calls to NamedAssociations, then create a GenericConcern @@ -90,6 +91,12 @@ public class NamedAssociationWrapper } @Override + public Iterable references() + { + return next.references(); + } + + @Override public int hashCode() { return next.hashCode(); http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/568fa2ff/core/api/src/main/java/org/qi4j/api/entity/EntityReference.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/qi4j/api/entity/EntityReference.java b/core/api/src/main/java/org/qi4j/api/entity/EntityReference.java index 60c4d1b..967647c 100644 --- a/core/api/src/main/java/org/qi4j/api/entity/EntityReference.java +++ b/core/api/src/main/java/org/qi4j/api/entity/EntityReference.java @@ -55,6 +55,13 @@ public final class EntityReference return new EntityReference( (EntityComposite) object ); } + public static EntityReference create( Identity identity ) + { + if( identity == null ) + return null; + return new EntityReference( identity.identity().get() ); + } + private static final long serialVersionUID = 1L; private String identity; http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/568fa2ff/core/api/src/main/java/org/qi4j/api/unitofwork/UnitOfWork.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/qi4j/api/unitofwork/UnitOfWork.java b/core/api/src/main/java/org/qi4j/api/unitofwork/UnitOfWork.java index e17bc07..7721265 100644 --- a/core/api/src/main/java/org/qi4j/api/unitofwork/UnitOfWork.java +++ b/core/api/src/main/java/org/qi4j/api/unitofwork/UnitOfWork.java @@ -20,6 +20,7 @@ import org.qi4j.api.association.AssociationDescriptor; import org.qi4j.api.composite.AmbiguousTypeException; import org.qi4j.api.entity.EntityBuilder; import org.qi4j.api.entity.EntityReference; +import org.qi4j.api.entity.Identity; import org.qi4j.api.entity.LifecycleException; import org.qi4j.api.property.PropertyDescriptor; import org.qi4j.api.query.Query; @@ -348,4 +349,77 @@ public interface UnitOfWork extends MetaInfoHolder, AutoCloseable * @param callback a callback to be unregistered with this UnitOfWork */ void removeUnitOfWorkCallback( UnitOfWorkCallback callback ); + + /** + * Converts the provided Entity to a Value of the same type. + * This is a convenience method to convert an EntityComposite to a ValueComposite. + *

+ * All Property values are transferred across as-is, and the Association, ManyAssociation + * and NamedAssociatino values are kept in the ValueComposite as EntityReferences + * until they are dereferenced (get() and other methods), and IF a UnitOfWork is + * present at dereferencing the corresponding EntityCompoiste is retrieved from the + * EntityStore. If there is not an UnitOfWork present, an exception is thrown. + *

+ * For this to work, the Composites (both Entity and Value) must not declare the + * EntityComposite and ValueComposite super types, but rely on the declaration in + * the assembly, and also extend the Identity supertype. + * + * Example; + *


+     *     public interface Person extends Identity { ... };
+     *     public class MyAssembler
+     *     {
+     *         public void assemble( ModuleAssembly module )
+     *         {
+     *             module.values( Person.class );
+     *             module.entities( Person.class );
+     *         }
+     *     }
+     * 
+ * + * @param primaryType The shared type for which the properties and associations will + * be converted. Properties outside this type will be ignored. + * @param entityComposite The entity to be convered. + */ + T toValue( Class primaryType, T entityComposite ); + + /** + * Converts the provided Value to an Entity of the same type. + * This is a convenience method to convert a ValueComposite to an EntityComposite. + *

+ * All Property values are transferred across as-is (no deep copy in case mutable + * types (DISCOURAGED!) are used), and the Association, ManyAssociation + * and NamedAssociatino that were in the ValueComposite as EntityReferences are + * transferred into the EntityComposite correctly, and can be dereferenced. + *

+ * This method MUST be called within a UnitOfWork. + *

+ * If an Entity with the Identity in the ValueComposite already exists, then that + * Entity is updated with the values from the ValueComposite. If an Entity of + * that Identity doesn't exist and new one is created. + *

+ * For this to work, the Composites (both Entity and Value) must not declare the + * EntityComposite and ValueComposite super types, but rely on the declaration in + * the assembly, and also extend the Identity supertype. + * + * Example; + *


+     *     public interface Person extends Identity { ... };
+     *     public class MyAssembler
+     *     {
+     *         public void assemble( ModuleAssembly module )
+     *         {
+     *             module.values( Person.class );
+     *             module.entities( Person.class );
+     *         }
+     *     }
+     * 
+ * + * @param primaryType The shared type for which the properties and associations will + * be converted. Properties outside this type will be ignored. + * @param valueComposite The Value to be convered into an Entity. + */ + T toEntity( Class primaryType, T valueComposite ); + + } http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/568fa2ff/core/runtime/src/main/java/org/qi4j/runtime/Qi4jRuntimeImpl.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/qi4j/runtime/Qi4jRuntimeImpl.java b/core/runtime/src/main/java/org/qi4j/runtime/Qi4jRuntimeImpl.java index 9b5dce7..23ba27b 100644 --- a/core/runtime/src/main/java/org/qi4j/runtime/Qi4jRuntimeImpl.java +++ b/core/runtime/src/main/java/org/qi4j/runtime/Qi4jRuntimeImpl.java @@ -338,57 +338,6 @@ public final class Qi4jRuntimeImpl return (AssociationDescriptor) ( (AbstractAssociationInstance) association ).associationInfo(); } - @Override - public T toValue( Class primaryType, T entityComposite ) - { - EntityDescriptor entityDescriptor = entityDescriptorFor( entityComposite ); - Function propertyFunction = new ToValuePropertyMappingFunction( entityComposite ); - Function assocationFunction = new ToValueAssociationMappingFunction( entityComposite ); - Function> manyAssocFunction = new ToValueManyAssociationMappingFunction( entityComposite ); - Function> namedAssocFunction = new ToValueNameAssociationMappingFunction( entityComposite ); - - @SuppressWarnings( "unchecked" ) - ValueBuilder builder = moduleOf( entityComposite ).newValueBuilderWithState( - (Class) entityDescriptor.primaryType(), propertyFunction, assocationFunction, manyAssocFunction, namedAssocFunction ); - return builder.newInstance(); - } - - @Override - public T toEntity( Class primaryType, T valueComposite ) - { - Function propertyFunction = new ToEntityPropertyMappingFunction( valueComposite ); - Function assocationFunction = new ToEntityAssociationMappingFunction( valueComposite ); - Function> manyAssocFunction = new ToEntityManyAssociationMappingFunction( valueComposite ); - Function> namedAssocFunction = new ToEntityNameAssociationMappingFunction( valueComposite ); - - UnitOfWork uow = moduleOf( valueComposite ).currentUnitOfWork(); - String identity = valueComposite.identity().get(); - try - { - T entity = uow.get( primaryType, identity ); - // If successful, then this entity is to by modified. - EntityInstance instance = EntityInstance.entityInstanceOf( (EntityComposite) entity ); - EntityState state = instance.entityState(); - FunctionStateResolver stateResolver = new FunctionStateResolver( propertyFunction, - assocationFunction, - manyAssocFunction, - namedAssocFunction ); - EntityModel model = (EntityModel) EntityInstance.entityInstanceOf( (EntityComposite) entity ).descriptor(); - stateResolver.populateState( model, state ); - return entity; - } - catch( NoSuchEntityException e ) - { - EntityBuilder entityBuilder = uow.newEntityBuilderWithState( primaryType, - identity, - propertyFunction, - assocationFunction, - manyAssocFunction, - namedAssocFunction ); - return entityBuilder.newInstance(); - } - } - // SPI @Override public EntityState entityStateOf( EntityComposite composite ) @@ -416,166 +365,4 @@ public final class Qi4jRuntimeImpl return ( (NamedAssociationInstance) assoc ).getEntityReferences(); } - private class ToValuePropertyMappingFunction - implements Function - { - private Object entity; - - public ToValuePropertyMappingFunction( Object entity ) - { - this.entity = entity; - } - - @Override - public Object map( PropertyDescriptor propertyDescriptor ) - { - EntityState entityState = entityStateOf( (EntityComposite) entity ); - return entityState.propertyValueOf( propertyDescriptor.qualifiedName() ); - } - } - - private class ToValueAssociationMappingFunction - implements Function - { - private final T entity; - - public ToValueAssociationMappingFunction( T entity ) - { - this.entity = entity; - } - - @Override - public EntityReference map( AssociationDescriptor associationDescriptor ) - { - EntityState entityState = entityStateOf( (EntityComposite) entity ); - return entityState.associationValueOf( associationDescriptor.qualifiedName() ); - } - } - - private class ToValueManyAssociationMappingFunction - implements Function> - { - private final T entity; - - public ToValueManyAssociationMappingFunction( T entity ) - { - this.entity = entity; - } - - @Override - public Iterable map( AssociationDescriptor associationDescriptor ) - { - EntityState entityState = entityStateOf( (EntityComposite) entity ); - return entityState.manyAssociationValueOf( associationDescriptor.qualifiedName() ); - } - } - - private class ToValueNameAssociationMappingFunction - implements Function> - { - private final T entity; - - public ToValueNameAssociationMappingFunction( T entity ) - { - this.entity = entity; - } - - @Override - public Map map( AssociationDescriptor associationDescriptor ) - { - Map result = new HashMap<>(); - EntityState entityState = entityStateOf( (EntityComposite) entity ); - final NamedAssociationState state = entityState.namedAssociationValueOf( associationDescriptor.qualifiedName() ); - for( String name : state ) - { - result.put( name, state.get( name ) ); - } - return result; - } - } - - private class ToEntityPropertyMappingFunction - implements Function - { - private final T value; - - public ToEntityPropertyMappingFunction( T value ) - { - this.value = value; - } - - @Override - public Object map( PropertyDescriptor propertyDescriptor ) - { - StateHolder state = stateOf( (ValueComposite) value ); - Property property = state.propertyFor( propertyDescriptor.accessor() ); - return property.get(); - } - } - - private class ToEntityAssociationMappingFunction - implements Function - { - - private final T value; - - public ToEntityAssociationMappingFunction( T value ) - { - this.value = value; - } - - @Override - public EntityReference map( AssociationDescriptor associationDescriptor ) - { - AssociationStateHolder state = stateOf( (ValueComposite) value ); - AssociationInstance association = (AssociationInstance) state.associationFor( associationDescriptor.accessor() ); - return association.getAssociationState().get(); - } - } - - private class ToEntityManyAssociationMappingFunction - implements Function> - { - - private final T value; - - public ToEntityManyAssociationMappingFunction( T value ) - { - this.value = value; - } - - @Override - public Iterable map( AssociationDescriptor associationDescriptor ) - { - AssociationStateHolder state = stateOf( (ValueComposite) value ); - ManyAssociationInstance association = (ManyAssociationInstance) state.manyAssociationFor( associationDescriptor - .accessor() ); - return association.getManyAssociationState(); - } - } - - private class ToEntityNameAssociationMappingFunction - implements Function> - { - private final T value; - - public ToEntityNameAssociationMappingFunction( T value ) - { - this.value = value; - } - - @Override - public Map map( AssociationDescriptor associationDescriptor ) - { - AssociationStateHolder state = stateOf( (ValueComposite) value ); - NamedAssociationInstance association = (NamedAssociationInstance) state.namedAssociationFor( associationDescriptor - .accessor() ); - HashMap result = new HashMap<>(); - for( Map.Entry entry : association.getEntityReferences() ) - { - result.put( entry.getKey(), entry.getValue() ); - } - return result; - } - } } http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/568fa2ff/core/runtime/src/main/java/org/qi4j/runtime/association/AbstractAssociationInstance.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/qi4j/runtime/association/AbstractAssociationInstance.java b/core/runtime/src/main/java/org/qi4j/runtime/association/AbstractAssociationInstance.java index e42b2c5..e8de5c1 100644 --- a/core/runtime/src/main/java/org/qi4j/runtime/association/AbstractAssociationInstance.java +++ b/core/runtime/src/main/java/org/qi4j/runtime/association/AbstractAssociationInstance.java @@ -1,14 +1,10 @@ package org.qi4j.runtime.association; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Proxy; import java.lang.reflect.Type; import org.qi4j.api.association.AbstractAssociation; -import org.qi4j.api.entity.EntityComposite; import org.qi4j.api.entity.EntityReference; +import org.qi4j.api.entity.Identity; import org.qi4j.functional.Function2; -import org.qi4j.runtime.composite.ProxyReferenceInvocationHandler; -import org.qi4j.runtime.entity.EntityInstance; /** * Implementation of AbstractAssociation. Includes helper methods for subclasses @@ -55,32 +51,17 @@ public abstract class AbstractAssociationInstance return null; } - InvocationHandler handler = Proxy.getInvocationHandler( composite ); - if( handler instanceof ProxyReferenceInvocationHandler ) - { - handler = Proxy.getInvocationHandler( ( (ProxyReferenceInvocationHandler) handler ).proxy() ); - } - EntityInstance instance = (EntityInstance) handler; - return instance.identity(); + return new EntityReference( ( (Identity) composite ).identity().get() ); } protected void checkType( Object instance ) { - if( instance != null ) - { - if( !( instance instanceof EntityComposite ) ) - { - if( instance instanceof Proxy ) - { - if( Proxy.getInvocationHandler( instance ) instanceof EntityInstance ) - { - return; // It's fine - } - } - throw new IllegalArgumentException( "Object must be an EntityComposite" ); - } + if( instance instanceof Identity || instance == null ) + { + return; } + throw new IllegalArgumentException( "Object must be a subtype of org.qi4j.api.identity.Identity" ); } protected void checkImmutable() http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/568fa2ff/core/runtime/src/main/java/org/qi4j/runtime/association/AssociationInstance.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/qi4j/runtime/association/AssociationInstance.java b/core/runtime/src/main/java/org/qi4j/runtime/association/AssociationInstance.java index d5babcd..e42d8eb 100644 --- a/core/runtime/src/main/java/org/qi4j/runtime/association/AssociationInstance.java +++ b/core/runtime/src/main/java/org/qi4j/runtime/association/AssociationInstance.java @@ -19,6 +19,7 @@ import org.qi4j.api.association.Association; import org.qi4j.api.association.AssociationDescriptor; import org.qi4j.api.association.AssociationWrapper; import org.qi4j.api.entity.EntityReference; +import org.qi4j.api.entity.Identity; import org.qi4j.api.property.Property; import org.qi4j.functional.Function2; @@ -57,7 +58,13 @@ public final class AssociationInstance associationInfo.checkConstraints( newValue ); // Change association - associationState.set( getEntityReference( newValue ) ); + associationState.set( EntityReference.create( (Identity) newValue )); + } + + @Override + public EntityReference reference() + { + return associationState.get(); } public Property getAssociationState() @@ -81,10 +88,10 @@ public final class AssociationInstance @Override public int hashCode() { - int hash = associationInfo.hashCode() * 61; // Descriptor + int hash = associationInfo.hashCode() * 39; // Descriptor if( associationState.get() != null ) { - hash += associationState.get().hashCode() * 3; // State + hash = hash * 997 + associationState.get().hashCode(); // State } return hash; } http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/568fa2ff/core/runtime/src/main/java/org/qi4j/runtime/association/ManyAssociationInstance.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/qi4j/runtime/association/ManyAssociationInstance.java b/core/runtime/src/main/java/org/qi4j/runtime/association/ManyAssociationInstance.java index a946862..eafda9a 100644 --- a/core/runtime/src/main/java/org/qi4j/runtime/association/ManyAssociationInstance.java +++ b/core/runtime/src/main/java/org/qi4j/runtime/association/ManyAssociationInstance.java @@ -10,8 +10,10 @@ import org.qi4j.api.association.AssociationDescriptor; import org.qi4j.api.association.ManyAssociation; import org.qi4j.api.association.ManyAssociationWrapper; import org.qi4j.api.entity.EntityReference; +import org.qi4j.api.entity.Identity; +import org.qi4j.api.util.NullArgumentException; import org.qi4j.functional.Function2; -import org.qi4j.runtime.composite.ConstraintsCheck; +import org.qi4j.functional.Iterables; import org.qi4j.spi.entity.ManyAssociationState; /** @@ -47,10 +49,11 @@ public class ManyAssociationInstance @Override public boolean add( int i, T entity ) { + NullArgumentException.validateNotNull( "entity", entity ); checkImmutable(); checkType( entity ); - ( (ConstraintsCheck) associationInfo ).checkConstraints( entity ); - return manyAssociationState.add( i, getEntityReference( entity ) ); + associationInfo.checkConstraints( entity ); + return manyAssociationState.add( i, new EntityReference( ( (Identity) entity ).identity().get() ) ); } @Override @@ -62,10 +65,11 @@ public class ManyAssociationInstance @Override public boolean remove( T entity ) { + NullArgumentException.validateNotNull( "entity", entity ); checkImmutable(); checkType( entity ); - return manyAssociationState.remove( getEntityReference( entity ) ); + return manyAssociationState.remove( new EntityReference( ( (Identity) entity ).identity().get() ) ); } @Override @@ -77,7 +81,7 @@ public class ManyAssociationInstance @Override public List toList() { - ArrayList list = new ArrayList(); + ArrayList list = new ArrayList<>(); for( EntityReference entityReference : manyAssociationState ) { list.add( getEntity( entityReference ) ); @@ -89,7 +93,7 @@ public class ManyAssociationInstance @Override public Set toSet() { - Set set = new HashSet(); + Set set = new HashSet<>(); for( EntityReference entityReference : manyAssociationState ) { set.add( getEntity( entityReference ) ); @@ -99,6 +103,12 @@ public class ManyAssociationInstance } @Override + public Iterable references() + { + return Iterables.toList( manyAssociationState ); + } + + @Override public String toString() { return manyAssociationState.toString(); @@ -194,15 +204,4 @@ public class ManyAssociationInstance idIterator.remove(); } } - - @Override - protected void checkType( Object instance ) - { - if( instance == null ) - { - throw new NullPointerException( "Associated object may not be null" ); - } - - super.checkType( instance ); - } } http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/568fa2ff/core/runtime/src/main/java/org/qi4j/runtime/association/NamedAssociationInstance.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/qi4j/runtime/association/NamedAssociationInstance.java b/core/runtime/src/main/java/org/qi4j/runtime/association/NamedAssociationInstance.java index 284de5d..7bffb4b 100644 --- a/core/runtime/src/main/java/org/qi4j/runtime/association/NamedAssociationInstance.java +++ b/core/runtime/src/main/java/org/qi4j/runtime/association/NamedAssociationInstance.java @@ -24,12 +24,15 @@ import java.util.Iterator; import java.util.Map; import org.qi4j.api.association.NamedAssociation; import org.qi4j.api.entity.EntityReference; +import org.qi4j.api.entity.Identity; +import org.qi4j.api.util.NullArgumentException; import org.qi4j.functional.Function; import org.qi4j.functional.Function2; import org.qi4j.functional.Iterables; -import org.qi4j.runtime.composite.ConstraintsCheck; import org.qi4j.spi.entity.NamedAssociationState; +import static org.qi4j.functional.Iterables.map; + public class NamedAssociationInstance extends AbstractAssociationInstance implements NamedAssociation @@ -39,7 +42,8 @@ public class NamedAssociationInstance public NamedAssociationInstance( AssociationInfo associationInfo, Function2 associationFunction, - NamedAssociationState namedAssociationState ) + NamedAssociationState namedAssociationState + ) { super( associationInfo, associationFunction ); this.namedAssociationState = namedAssociationState; @@ -66,10 +70,11 @@ public class NamedAssociationInstance @Override public boolean put( String name, T entity ) { + NullArgumentException.validateNotNull( "entity", entity ); checkImmutable(); checkType( entity ); - ( (ConstraintsCheck) associationInfo ).checkConstraints( entity ); - return namedAssociationState.put( name, getEntityReference( entity ) ); + associationInfo.checkConstraints( entity ); + return namedAssociationState.put( name, new EntityReference( ( (Identity) entity ).identity().get() ) ); } @Override @@ -102,9 +107,22 @@ public class NamedAssociationInstance return map; } - public Iterable> getEntityReferences() + @Override + public Iterable references() { - return Iterables.map( new Function>() + return map( new Function() + { + @Override + public EntityReference map( String name ) + { + return namedAssociationState.get( name ); + } + }, namedAssociationState ); + } + + public Iterable> getEntityReferences() + { + return map( new Function>() { @Override public Map.Entry map( final String key ) @@ -133,10 +151,10 @@ public class NamedAssociationInstance @Override public boolean equals( Object o ) { - if( o instanceof Map.Entry) + if( o instanceof Map.Entry ) { Map.Entry other = (Map.Entry) o; - return key.equals(other.getKey()); + return key.equals( other.getKey() ); } return false; } @@ -150,5 +168,4 @@ public class NamedAssociationInstance } }, namedAssociationState ); } - } http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/568fa2ff/core/runtime/src/main/java/org/qi4j/runtime/structure/ModuleUnitOfWork.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/qi4j/runtime/structure/ModuleUnitOfWork.java b/core/runtime/src/main/java/org/qi4j/runtime/structure/ModuleUnitOfWork.java index dd1a830..9f63d2c 100644 --- a/core/runtime/src/main/java/org/qi4j/runtime/structure/ModuleUnitOfWork.java +++ b/core/runtime/src/main/java/org/qi4j/runtime/structure/ModuleUnitOfWork.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2009, Rickard Öberg. All Rights Reserved. - * Copyright (c) 2013, Niclas Hedhman. All Rights Reserved. + * Copyright (c) 2013-2015, Niclas Hedhman. All Rights Reserved. * Copyright (c) 2013-2015, Paul Merlin. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,9 +16,11 @@ package org.qi4j.runtime.structure; import java.util.Collections; +import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.qi4j.api.association.AssociationDescriptor; +import org.qi4j.api.association.AssociationStateHolder; import org.qi4j.api.common.QualifiedName; import org.qi4j.api.composite.Composite; import org.qi4j.api.entity.EntityBuilder; @@ -27,7 +29,9 @@ import org.qi4j.api.entity.EntityReference; import org.qi4j.api.entity.Identity; import org.qi4j.api.entity.IdentityGenerator; import org.qi4j.api.entity.LifecycleException; +import org.qi4j.api.property.Property; import org.qi4j.api.property.PropertyDescriptor; +import org.qi4j.api.property.StateHolder; import org.qi4j.api.query.Query; import org.qi4j.api.query.QueryBuilder; import org.qi4j.api.query.QueryExecutionException; @@ -42,18 +46,24 @@ import org.qi4j.api.unitofwork.UnitOfWorkCompletionException; import org.qi4j.api.unitofwork.UnitOfWorkFactory; import org.qi4j.api.usecase.Usecase; import org.qi4j.api.util.NullArgumentException; +import org.qi4j.api.value.ValueBuilder; +import org.qi4j.api.value.ValueComposite; import org.qi4j.functional.Function; import org.qi4j.functional.Iterables; import org.qi4j.functional.Specification; +import org.qi4j.runtime.association.AssociationInstance; +import org.qi4j.runtime.association.ManyAssociationInstance; +import org.qi4j.runtime.association.NamedAssociationInstance; import org.qi4j.runtime.composite.FunctionStateResolver; import org.qi4j.runtime.entity.EntityInstance; import org.qi4j.runtime.entity.EntityModel; import org.qi4j.runtime.property.PropertyModel; import org.qi4j.runtime.unitofwork.EntityBuilderInstance; import org.qi4j.runtime.unitofwork.UnitOfWorkInstance; -import org.qi4j.runtime.composite.StateResolver; -import org.qi4j.runtime.value.ValueStateModel; +import org.qi4j.runtime.value.ValueInstance; +import org.qi4j.spi.entity.EntityState; import org.qi4j.spi.entity.EntityStatus; +import org.qi4j.spi.entity.NamedAssociationState; import org.qi4j.spi.entitystore.EntityStore; import org.qi4j.spi.query.EntityFinder; import org.qi4j.spi.query.EntityFinderException; @@ -133,7 +143,7 @@ public class ModuleUnitOfWork } @Override - @SuppressWarnings( {"raw", "unchecked"} ) + @SuppressWarnings( { "raw", "unchecked" } ) public Query newQuery( QueryBuilder queryBuilder ) { QueryBuilderSPI queryBuilderSPI = (QueryBuilderSPI) queryBuilder; @@ -235,7 +245,7 @@ public class ModuleUnitOfWork EntityStore entityStore = model.module().entityStore(); - StateResolver stateResolver = new FunctionStateResolver( + FunctionStateResolver stateResolver = new FunctionStateResolver( propertyFunction, associationFunction, manyAssociationFunction, namedAssociationFunction ); @@ -314,6 +324,7 @@ public class ModuleUnitOfWork } } + @SuppressWarnings( "DuplicateThrows" ) @Override public void complete() throws UnitOfWorkCompletionException, ConcurrentEntityModificationException @@ -332,7 +343,7 @@ public class ModuleUnitOfWork { discard(); } - + @Override public boolean isOpen() { @@ -403,6 +414,55 @@ public class ModuleUnitOfWork uow.addEntity( instance ); } + @Override + public T toValue( Class primaryType, T entityComposite ) + { + Function propertyFunction = new ToValuePropertyMappingFunction( entityComposite ); + Function assocationFunction = new ToValueAssociationMappingFunction<>( entityComposite ); + Function> manyAssocFunction = new ToValueManyAssociationMappingFunction<>( entityComposite ); + Function> namedAssocFunction = new ToValueNameAssociationMappingFunction<>( entityComposite ); + + @SuppressWarnings( "unchecked" ) + ValueBuilder builder = module().newValueBuilderWithState( + primaryType, propertyFunction, assocationFunction, manyAssocFunction, namedAssocFunction ); + return builder.newInstance(); + } + + @Override + public T toEntity( Class primaryType, T valueComposite ) + { + Function propertyFunction = new ToEntityPropertyMappingFunction<>( valueComposite ); + Function assocationFunction = new ToEntityAssociationMappingFunction<>( valueComposite ); + Function> manyAssocFunction = new ToEntityManyAssociationMappingFunction<>( valueComposite ); + Function> namedAssocFunction = new ToEntityNameAssociationMappingFunction<>( valueComposite ); + + String identity = valueComposite.identity().get(); + try + { + T entity = get( primaryType, identity ); + // If successful, then this entity is to by modified. + EntityInstance instance = EntityInstance.entityInstanceOf( (EntityComposite) entity ); + EntityState state = instance.entityState(); + FunctionStateResolver stateResolver = new FunctionStateResolver( propertyFunction, + assocationFunction, + manyAssocFunction, + namedAssocFunction ); + EntityModel model = (EntityModel) EntityInstance.entityInstanceOf( (EntityComposite) entity ).descriptor(); + stateResolver.populateState( model, state ); + return entity; + } + catch( NoSuchEntityException e ) + { + EntityBuilder entityBuilder = newEntityBuilderWithState( primaryType, + identity, + propertyFunction, + assocationFunction, + manyAssocFunction, + namedAssocFunction ); + return entityBuilder.newInstance(); + } + } + private static class UoWQuerySource implements QuerySource { private final ModuleUnitOfWork moduleUnitOfWork; @@ -533,4 +593,167 @@ public class ModuleUnitOfWork return "UnitOfWork( " + moduleUnitOfWork.usecase().name() + " )"; } } + + private class ToValuePropertyMappingFunction + implements Function + { + private Object entity; + + public ToValuePropertyMappingFunction( Object entity ) + { + this.entity = entity; + } + + @Override + public Object map( PropertyDescriptor propertyDescriptor ) + { + EntityState entityState = EntityInstance.entityInstanceOf( (EntityComposite) entity ).entityState(); + return entityState.propertyValueOf( propertyDescriptor.qualifiedName() ); + } + } + + private class ToValueAssociationMappingFunction + implements Function + { + private final T entity; + + public ToValueAssociationMappingFunction( T entity ) + { + this.entity = entity; + } + + @Override + public EntityReference map( AssociationDescriptor associationDescriptor ) + { + EntityState entityState = EntityInstance.entityInstanceOf( (EntityComposite) entity ).entityState(); + return entityState.associationValueOf( associationDescriptor.qualifiedName() ); + } + } + + private class ToValueManyAssociationMappingFunction + implements Function> + { + private final T entity; + + public ToValueManyAssociationMappingFunction( T entity ) + { + this.entity = entity; + } + + @Override + public Iterable map( AssociationDescriptor associationDescriptor ) + { + EntityState entityState = EntityInstance.entityInstanceOf( (EntityComposite) entity ).entityState(); + return entityState.manyAssociationValueOf( associationDescriptor.qualifiedName() ); + } + } + + private class ToValueNameAssociationMappingFunction + implements Function> + { + private final T entity; + + public ToValueNameAssociationMappingFunction( T entity ) + { + this.entity = entity; + } + + @Override + public Map map( AssociationDescriptor associationDescriptor ) + { + Map result = new HashMap<>(); + EntityState entityState = EntityInstance.entityInstanceOf( (EntityComposite) entity ).entityState(); + final NamedAssociationState state = entityState.namedAssociationValueOf( associationDescriptor.qualifiedName() ); + for( String name : state ) + { + result.put( name, state.get( name ) ); + } + return result; + } + } + + private class ToEntityPropertyMappingFunction + implements Function + { + private final T value; + + public ToEntityPropertyMappingFunction( T value ) + { + this.value = value; + } + + @Override + public Object map( PropertyDescriptor propertyDescriptor ) + { + StateHolder state = ValueInstance.valueInstanceOf( (ValueComposite) value ).state(); + Property property = state.propertyFor( propertyDescriptor.accessor() ); + return property.get(); + } + } + + private class ToEntityAssociationMappingFunction + implements Function + { + + private final T value; + + public ToEntityAssociationMappingFunction( T value ) + { + this.value = value; + } + + @Override + public EntityReference map( AssociationDescriptor associationDescriptor ) + { + AssociationStateHolder state = ValueInstance.valueInstanceOf( (ValueComposite) value ).state(); + AssociationInstance association = (AssociationInstance) state.associationFor( associationDescriptor.accessor() ); + return association.getAssociationState().get(); + } + } + + private class ToEntityManyAssociationMappingFunction + implements Function> + { + + private final T value; + + public ToEntityManyAssociationMappingFunction( T value ) + { + this.value = value; + } + + @Override + public Iterable map( AssociationDescriptor associationDescriptor ) + { + AssociationStateHolder state = ValueInstance.valueInstanceOf( (ValueComposite) value ).state(); + ManyAssociationInstance association = + (ManyAssociationInstance) state.manyAssociationFor( associationDescriptor.accessor() ); + return association.getManyAssociationState(); + } + } + + private class ToEntityNameAssociationMappingFunction + implements Function> + { + private final T value; + + public ToEntityNameAssociationMappingFunction( T value ) + { + this.value = value; + } + + @Override + public Map map( AssociationDescriptor associationDescriptor ) + { + AssociationStateHolder state = ValueInstance.valueInstanceOf( (ValueComposite) value ).state(); + NamedAssociationInstance association = + (NamedAssociationInstance) state.namedAssociationFor( associationDescriptor.accessor() ); + HashMap result = new HashMap<>(); + for( Map.Entry entry : association.getEntityReferences() ) + { + result.put( entry.getKey(), entry.getValue() ); + } + return result; + } + } } http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/568fa2ff/core/runtime/src/main/java/org/qi4j/runtime/unitofwork/EntityBuilderInstance.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/qi4j/runtime/unitofwork/EntityBuilderInstance.java b/core/runtime/src/main/java/org/qi4j/runtime/unitofwork/EntityBuilderInstance.java index 95c2e92..eae69b1 100644 --- a/core/runtime/src/main/java/org/qi4j/runtime/unitofwork/EntityBuilderInstance.java +++ b/core/runtime/src/main/java/org/qi4j/runtime/unitofwork/EntityBuilderInstance.java @@ -16,23 +16,16 @@ */ package org.qi4j.runtime.unitofwork; -import java.util.Map; -import org.qi4j.api.association.AssociationDescriptor; import org.qi4j.api.common.QualifiedName; import org.qi4j.api.entity.EntityBuilder; import org.qi4j.api.entity.EntityReference; import org.qi4j.api.entity.Identity; import org.qi4j.api.entity.LifecycleException; -import org.qi4j.api.property.PropertyDescriptor; -import org.qi4j.runtime.association.ManyAssociationModel; -import org.qi4j.runtime.association.NamedAssociationModel; import org.qi4j.runtime.composite.FunctionStateResolver; import org.qi4j.runtime.entity.EntityInstance; import org.qi4j.runtime.entity.EntityModel; import org.qi4j.runtime.structure.ModelModule; import org.qi4j.runtime.structure.ModuleUnitOfWork; -import org.qi4j.runtime.composite.StateResolver; -import org.qi4j.runtime.value.ValueStateModel; import org.qi4j.spi.entity.EntityState; import org.qi4j.spi.entitystore.EntityStoreUnitOfWork; @@ -80,7 +73,7 @@ public final class EntityBuilderInstance ModuleUnitOfWork uow, EntityStoreUnitOfWork store, String identity, - StateResolver stateResolver + FunctionStateResolver stateResolver ) { this.model = model; @@ -92,7 +85,7 @@ public final class EntityBuilderInstance model.model().initState( model.module(), entityState ); if( stateResolver != null ) { - (( FunctionStateResolver) stateResolver).populateState( model.model(), entityState ); + stateResolver.populateState( model.model(), entityState ); } entityState.setPropertyValue( IDENTITY_STATE_NAME, identity ); prototypeInstance = model.model().newInstance( uow, model.module(), entityState ); http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/568fa2ff/core/runtime/src/test/java/org/qi4j/runtime/value/ValueWithAssociationTest.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/test/java/org/qi4j/runtime/value/ValueWithAssociationTest.java b/core/runtime/src/test/java/org/qi4j/runtime/value/ValueWithAssociationTest.java index 5d699d5..4f6b375 100644 --- a/core/runtime/src/test/java/org/qi4j/runtime/value/ValueWithAssociationTest.java +++ b/core/runtime/src/test/java/org/qi4j/runtime/value/ValueWithAssociationTest.java @@ -33,6 +33,7 @@ public class ValueWithAssociationTest extends AbstractQi4jTest { module.entities( SimpleName.class ); module.entities( DualFaced.class ); + module.values( SimpleName.class ); module.values( DualFaced.class ); module.services( MemoryEntityStoreService.class ); module.services( UuidIdentityGeneratorService.class ); @@ -61,7 +62,7 @@ public class ValueWithAssociationTest extends AbstractQi4jTest proto.namedSimples().put( "niclas", simpleEntity ); DualFaced faced = builder2.newInstance(); identity2 = faced.identity().get(); - value = spi.toValue( DualFaced.class, faced ); + value = uow.toValue( DualFaced.class, faced ); assertThat( value.identity().get(), equalTo( identity2 ) ); uow.complete(); } @@ -83,7 +84,7 @@ public class ValueWithAssociationTest extends AbstractQi4jTest .next() .getValue(), equalTo( EntityReference.parseEntityReference( identity1 ) ) ); - DualFaced resurrected = spi.toEntity( DualFaced.class, value ); + DualFaced resurrected = uow.toEntity( DualFaced.class, value ); assertThat( resurrected.simple(), equalTo( entity.simple() ) ); assertThat( resurrected.simples(), equalTo( entity.simples() ) ); assertThat( resurrected.namedSimples(), equalTo( entity.namedSimples() ) ); @@ -101,7 +102,7 @@ public class ValueWithAssociationTest extends AbstractQi4jTest try (UnitOfWork uow = module.newUnitOfWork()) { - spi.toEntity( DualFaced.class, value ); + uow.toEntity( DualFaced.class, value ); uow.complete(); } @@ -114,6 +115,52 @@ public class ValueWithAssociationTest extends AbstractQi4jTest } } + @Test + public void givenValueWithIdentityAlreadyInStoreWhenConvertingToEntityExpectExistingEntityToBeUpdated() + throws UnitOfWorkCompletionException + { + String identity1; + String identity2; + DualFaced value; + try (UnitOfWork uow = module.newUnitOfWork()) + { + EntityBuilder builder1 = uow.newEntityBuilder( SimpleName.class ); + builder1.instance().name().set( "Niclas" ); + SimpleName simpleEntity = builder1.newInstance(); + identity1 = simpleEntity.identity().get(); + + EntityBuilder builder2 = uow.newEntityBuilder( DualFaced.class ); + DualFaced proto = builder2.instance(); + proto.name().set( "Hedhman" ); + proto.simple().set( simpleEntity ); + proto.simples().add( simpleEntity ); + proto.namedSimples().put( "niclas", simpleEntity ); + DualFaced faced = builder2.newInstance(); + identity2 = faced.identity().get(); + uow.complete(); + } + ValueBuilder vb1 = module.newValueBuilder( SimpleName.class ); + vb1.prototype().identity().set( identity1 ); + vb1.prototype().name().set( "Paul" ); + SimpleName simpleValue = vb1.newInstance(); + + ValueBuilder vb2 = module.newValueBuilder( DualFaced.class ); + vb2.prototype().identity().set(identity2); + vb2.prototype().name().set("Merlin"); + vb2.prototype().simple().set( simpleValue ); + vb2.prototype().simples().add( simpleValue ); + vb2.prototype().namedSimples().put( "paul", simpleValue ); + DualFaced dualValue = vb2.newInstance(); + + try (UnitOfWork uow = module.newUnitOfWork()) + { + DualFaced dualEntity = uow.toEntity( DualFaced.class, dualValue ); + assertThat( dualEntity.name().get(), equalTo( "Merlin")); + assertThat( dualEntity.simple().get().name().get(), equalTo( "Niclas")); + assertThat( dualEntity.simple().get().name().get(), equalTo( "Paul")); + } + } + public interface SimpleName extends Identity { Property name(); http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/568fa2ff/core/spi/src/main/java/org/qi4j/spi/value/ValueSerializerAdapter.java ---------------------------------------------------------------------- diff --git a/core/spi/src/main/java/org/qi4j/spi/value/ValueSerializerAdapter.java b/core/spi/src/main/java/org/qi4j/spi/value/ValueSerializerAdapter.java index 8b6246f..5345414 100644 --- a/core/spi/src/main/java/org/qi4j/spi/value/ValueSerializerAdapter.java +++ b/core/spi/src/main/java/org/qi4j/spi/value/ValueSerializerAdapter.java @@ -48,6 +48,7 @@ import org.qi4j.api.value.ValueSerializationException; import org.qi4j.api.value.ValueSerializer; import org.qi4j.functional.Function; import org.qi4j.functional.Function2; +import org.qi4j.spi.Qi4jSPI; import static org.qi4j.functional.Iterables.first; @@ -55,29 +56,29 @@ import static org.qi4j.functional.Iterables.first; * Adapter for pull-parsing capable ValueSerializers. * *

- * Among Plain values (see {@link ValueSerializer}) some are considered primitives to underlying serialization - * mechanisms and by so handed/come without conversion to/from implementations. Primitive values can be one of: + * Among Plain values (see {@link ValueSerializer}) some are considered primitives to underlying serialization + * mechanisms and by so handed/come without conversion to/from implementations. Primitive values can be one of: *

*
    - *
  • 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.
  • + *
  • 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.
  • *
*

- * Some other Plain values are transformed before being handed to implementations: + * Some other Plain values are transformed before being handed to implementations: *

*
    - *
  • BigInteger and BigDecimal depends on ValueSerializer.{@link Options};
  • - *
  • Date as a ISO-8601 UTC String;
  • - *
  • DateTime (JodaTime) as a ISO-8601 String with timezone offset or Z for UTC;
  • - *
  • LocalDateTime (JodaTime) as a ISO-8601 String with no timezone offset;
  • - *
  • LocalDate (JodaTime) as a ISO-8601 String with no time info;
  • + *
  • BigInteger and BigDecimal depends on ValueSerializer.{@link Options};
  • + *
  • Date as a ISO-8601 UTC String;
  • + *
  • DateTime (JodaTime) as a ISO-8601 String with timezone offset or Z for UTC;
  • + *
  • LocalDateTime (JodaTime) as a ISO-8601 String with no timezone offset;
  • + *
  • LocalDate (JodaTime) as a ISO-8601 String with no time info;
  • *
* * @param Implementor output type @@ -112,8 +113,8 @@ public abstract class ValueSerializerAdapter /** * Register a Plain Value type serialization Function. * - * @param Plain Value parametrized Type - * @param type Plain Value Type + * @param Plain Value parametrized Type + * @param type Plain Value Type * @param serializer Serialization Function */ @SuppressWarnings( "unchecked" ) @@ -125,8 +126,8 @@ public abstract class ValueSerializerAdapter /** * Register a Complex Value type serialization Function. * - * @param Complex Value parametrized Type - * @param type Complex Value Type + * @param Complex Value parametrized Type + * @param type Complex Value Type * @param serializer Serialization Function */ @SuppressWarnings( "unchecked" ) @@ -364,48 +365,48 @@ public abstract class ValueSerializerAdapter onValue( output, null ); } else // Registered serializer - if( serializers.get( object.getClass() ) != null ) - { - onValue( output, serializers.get( object.getClass() ).map( options, object ) ); - } - else if( complexSerializers.get( object.getClass() ) != null ) - { - complexSerializers.get( object.getClass() ).serialize( options, object, output ); - } - else // ValueComposite - if( ValueComposite.class.isAssignableFrom( object.getClass() ) ) - { - serializeValueComposite( options, object, output, rootPass ); - } - else // EntityComposite - if( EntityComposite.class.isAssignableFrom( object.getClass() ) ) - { - serializeEntityComposite( object, output ); - } - else // Collection - Iterable - if( Iterable.class.isAssignableFrom( object.getClass() ) ) - { - serializeIterable( options, object, output ); - } - else // Array - QUID Remove this and use java serialization for arrays? - if( object.getClass().isArray() ) - { - serializeBase64Serializable( object, output ); - } - else // Map - if( Map.class.isAssignableFrom( object.getClass() ) ) - { - serializeMap( options, object, output ); - } - else // Enum - if( object.getClass().isEnum() ) - { - onValue( output, object.toString() ); - } - else // Fallback to Base64 encoded Java Serialization - { - serializeBase64Serializable( object, output ); - } + if( serializers.get( object.getClass() ) != null ) + { + onValue( output, serializers.get( object.getClass() ).map( options, object ) ); + } + else if( complexSerializers.get( object.getClass() ) != null ) + { + complexSerializers.get( object.getClass() ).serialize( options, object, output ); + } + else // ValueComposite + if( ValueComposite.class.isAssignableFrom( object.getClass() ) ) + { + serializeValueComposite( options, object, output, rootPass ); + } + else // EntityComposite + if( EntityComposite.class.isAssignableFrom( object.getClass() ) ) + { + serializeEntityComposite( object, output ); + } + else // Collection - Iterable + if( Iterable.class.isAssignableFrom( object.getClass() ) ) + { + serializeIterable( options, object, output ); + } + else // Array - QUID Remove this and use java serialization for arrays? + if( object.getClass().isArray() ) + { + serializeBase64Serializable( object, output ); + } + else // Map + if( Map.class.isAssignableFrom( object.getClass() ) ) + { + serializeMap( options, object, output ); + } + else // Enum + if( object.getClass().isEnum() ) + { + onValue( output, object.toString() ); + } + else // Fallback to Base64 encoded Java Serialization + { + serializeBase64Serializable( object, output ); + } } private void serializeValueComposite( Options options, Object object, OutputType output, boolean rootPass ) @@ -548,7 +549,7 @@ public abstract class ValueSerializerAdapter throws Exception { ByteArrayOutputStream bout = new ByteArrayOutputStream(); - try( ObjectOutputStream out = new ObjectOutputStream( bout ) ) + try (ObjectOutputStream out = new ObjectOutputStream( bout )) { out.writeUnshared( object ); } http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/568fa2ff/samples/swing/src/main/java/org/qi4j/lib/swing/binding/internal/BoundAssociation.java ---------------------------------------------------------------------- diff --git a/samples/swing/src/main/java/org/qi4j/lib/swing/binding/internal/BoundAssociation.java b/samples/swing/src/main/java/org/qi4j/lib/swing/binding/internal/BoundAssociation.java index 5c0daf0..b927cc3 100644 --- a/samples/swing/src/main/java/org/qi4j/lib/swing/binding/internal/BoundAssociation.java +++ b/samples/swing/src/main/java/org/qi4j/lib/swing/binding/internal/BoundAssociation.java @@ -18,6 +18,7 @@ package org.qi4j.lib.swing.binding.internal; import org.qi4j.api.association.Association; +import org.qi4j.api.entity.EntityReference; import org.qi4j.api.injection.scope.Service; import org.qi4j.api.injection.scope.Structure; import org.qi4j.api.injection.scope.Uses; @@ -82,4 +83,10 @@ public final class BoundAssociation extends AbstractBinding { //To change body of implemented methods use File | Settings | File Templates. } + + @Override + public EntityReference reference() + { + return actual.reference(); + } } http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/568fa2ff/samples/swing/src/main/java/org/qi4j/lib/swing/binding/internal/BoundManyAssociation.java ---------------------------------------------------------------------- diff --git a/samples/swing/src/main/java/org/qi4j/lib/swing/binding/internal/BoundManyAssociation.java b/samples/swing/src/main/java/org/qi4j/lib/swing/binding/internal/BoundManyAssociation.java index a7dcb0f..892a3d5 100644 --- a/samples/swing/src/main/java/org/qi4j/lib/swing/binding/internal/BoundManyAssociation.java +++ b/samples/swing/src/main/java/org/qi4j/lib/swing/binding/internal/BoundManyAssociation.java @@ -5,6 +5,7 @@ import java.util.Iterator; import java.util.List; import java.util.Set; import org.qi4j.api.association.ManyAssociation; +import org.qi4j.api.entity.EntityReference; import org.qi4j.api.injection.scope.Service; import org.qi4j.api.injection.scope.Structure; import org.qi4j.api.injection.scope.Uses; @@ -59,6 +60,12 @@ public class BoundManyAssociation extends AbstractBinding } @Override + public Iterable references() + { + return actualAssociations.references(); + } + + @Override public int count() { return actualAssociations.count(); http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/568fa2ff/samples/swing/src/main/java/org/qi4j/lib/swing/binding/internal/BoundNamedAssociation.java ---------------------------------------------------------------------- diff --git a/samples/swing/src/main/java/org/qi4j/lib/swing/binding/internal/BoundNamedAssociation.java b/samples/swing/src/main/java/org/qi4j/lib/swing/binding/internal/BoundNamedAssociation.java index 8e9f187..7becd24 100644 --- a/samples/swing/src/main/java/org/qi4j/lib/swing/binding/internal/BoundNamedAssociation.java +++ b/samples/swing/src/main/java/org/qi4j/lib/swing/binding/internal/BoundNamedAssociation.java @@ -4,6 +4,7 @@ import java.lang.reflect.Method; import java.util.Iterator; import java.util.Map; import org.qi4j.api.association.NamedAssociation; +import org.qi4j.api.entity.EntityReference; import org.qi4j.api.injection.scope.Service; import org.qi4j.api.injection.scope.Structure; import org.qi4j.api.injection.scope.Uses; @@ -75,6 +76,12 @@ public class BoundNamedAssociation } @Override + public Iterable references() + { + return actualAssociations.references(); + } + + @Override public Iterator iterator() { return actualAssociations.iterator(); http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/568fa2ff/samples/swing/src/main/java/org/qi4j/lib/swing/binding/internal/BoundProperty.java ---------------------------------------------------------------------- diff --git a/samples/swing/src/main/java/org/qi4j/lib/swing/binding/internal/BoundProperty.java b/samples/swing/src/main/java/org/qi4j/lib/swing/binding/internal/BoundProperty.java index 30a88d6..7d22b44 100644 --- a/samples/swing/src/main/java/org/qi4j/lib/swing/binding/internal/BoundProperty.java +++ b/samples/swing/src/main/java/org/qi4j/lib/swing/binding/internal/BoundProperty.java @@ -17,19 +17,17 @@ */ package org.qi4j.lib.swing.binding.internal; +import java.awt.event.FocusListener; +import java.lang.reflect.Method; +import javax.swing.JComponent; import org.qi4j.api.injection.scope.Service; import org.qi4j.api.injection.scope.Structure; import org.qi4j.api.injection.scope.Uses; import org.qi4j.api.object.ObjectFactory; -import org.qi4j.api.property.GenericPropertyInfo; import org.qi4j.api.property.Property; import org.qi4j.lib.swing.binding.Binding; import org.qi4j.lib.swing.binding.SwingAdapter; -import javax.swing.*; -import java.awt.event.FocusListener; -import java.lang.reflect.Method; - public final class BoundProperty extends AbstractBinding implements Property, Binding { @@ -44,7 +42,8 @@ public final class BoundProperty extends AbstractBinding * @throws IllegalArgumentException Thrown if the specified {@code aMethod} is {@code null}. */ public BoundProperty( @Uses Method propertyMethod, @Structure ObjectFactory objectBuilderFactory, - @Service Iterable allAdapters ) + @Service Iterable allAdapters + ) throws IllegalArgumentException { super( propertyMethod, objectBuilderFactory, allAdapters );