polygene-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From nic...@apache.org
Subject [1/6] zest-qi4j git commit: Implemented ZEST-22, but still have a test failure. This failure seems unrelated.
Date Thu, 21 May 2015 10:25:00 GMT
Repository: zest-qi4j
Updated Branches:
  refs/heads/ZEST-22_toEntity-toValue [created] 591562568


Implemented ZEST-22, but still have a test failure. This failure seems unrelated.


Project: http://git-wip-us.apache.org/repos/asf/zest-qi4j/repo
Commit: http://git-wip-us.apache.org/repos/asf/zest-qi4j/commit/a36aba1f
Tree: http://git-wip-us.apache.org/repos/asf/zest-qi4j/tree/a36aba1f
Diff: http://git-wip-us.apache.org/repos/asf/zest-qi4j/diff/a36aba1f

Branch: refs/heads/ZEST-22_toEntity-toValue
Commit: a36aba1fe72f9009bd6a76294617355f930d4f6e
Parents: e691796
Author: Niclas Hedhman <niclas@hedhman.org>
Authored: Sat May 16 10:45:40 2015 +0800
Committer: Niclas Hedhman <niclas@hedhman.org>
Committed: Sat May 16 10:45:40 2015 +0800

----------------------------------------------------------------------
 core/api/src/main/java/org/qi4j/api/Qi4j.java   |  84 +++++-
 .../java/org/qi4j/runtime/Qi4jRuntimeImpl.java  | 257 ++++++++++++++++++-
 .../association/NamedAssociationInstance.java   |  51 ++++
 .../composite/FunctionStateResolver.java        |  33 +++
 .../unitofwork/EntityBuilderInstance.java       |  26 +-
 .../runtime/value/ValueWithAssociationTest.java | 132 ++++++++++
 .../spi/src/main/java/org/qi4j/spi/Qi4jSPI.java |  30 +++
 .../qi4j/spi/entity/NamedAssociationState.java  |   1 -
 8 files changed, 585 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/a36aba1f/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 317153c..d8f2d29 100644
--- a/core/api/src/main/java/org/qi4j/api/Qi4j.java
+++ b/core/api/src/main/java/org/qi4j/api/Qi4j.java
@@ -25,6 +25,7 @@ import org.qi4j.api.composite.InvalidCompositeException;
 import org.qi4j.api.composite.ModelDescriptor;
 import org.qi4j.api.composite.TransientDescriptor;
 import org.qi4j.api.entity.EntityDescriptor;
+import org.qi4j.api.entity.Identity;
 import org.qi4j.api.property.Property;
 import org.qi4j.api.property.PropertyDescriptor;
 import org.qi4j.api.service.ServiceDescriptor;
@@ -42,8 +43,9 @@ public interface Qi4j
      * then that reference must be dereferenced using this method
      * before handing it out for others to use.
      *
-     * @param <T> Parameterized type of the Composite
+     * @param <T>       Parameterized type of the Composite
      * @param composite instance reference injected in Modified using @This
+     *
      * @return the dereferenced Composite
      */
     <T> T dereference( T composite );
@@ -53,6 +55,7 @@ public interface Qi4j
      *
      * @param compositeOrUow The Composite (Service, Value, Entity or Transient) or UnitOfWork
to lookup the Module it
      *                       belongs to.
+     *
      * @return The Module instance where the Composite or UnitOfWork belongs to.
      */
     Module moduleOf( Object compositeOrUow );
@@ -62,6 +65,7 @@ public interface Qi4j
      *
      * @param compositeOrServiceReference The Composite (Service, Value, Entity or Transient)
for which to lookup the
      *                                    ModelDescriptor
+     *
      * @return The ModelDescriptor of the Composite
      */
     ModelDescriptor modelDescriptorFor( Object compositeOrServiceReference );
@@ -71,6 +75,7 @@ public interface Qi4j
      *
      * @param compositeOrServiceReference The Composite (Service, Value, Entity or Transient)
for which to lookup the
      *                                    CompositeDescriptor
+     *
      * @return The CompositeDescriptor of the Composite
      */
     CompositeDescriptor compositeDescriptorFor( Object compositeOrServiceReference );
@@ -79,6 +84,7 @@ public interface Qi4j
      * Returns the TransientDescriptor of the TransientComposite.
      *
      * @param transsient The TransientComposite for which to lookup the TransientDescriptor
+     *
      * @return The TransientDescriptor of the TransientComposite
      */
     TransientDescriptor transientDescriptorFor( Object transsient );
@@ -87,6 +93,7 @@ public interface Qi4j
      * Returns the EntityDescriptor of the EntityComposite.
      *
      * @param entity The EntityComposite for which to lookup the EntityDescriptor
+     *
      * @return The EntityDescriptor of the EntityComposite
      */
     EntityDescriptor entityDescriptorFor( Object entity );
@@ -95,6 +102,7 @@ public interface Qi4j
      * Returns the ValueDescriptor of the ValueComposite.
      *
      * @param value The ValueComposite for which to lookup the ValueDescriptor
+     *
      * @return The ValueDescriptor of the ValueComposite
      */
     ValueDescriptor valueDescriptorFor( Object value );
@@ -103,6 +111,7 @@ public interface Qi4j
      * Returns the ServiceDescriptor of the ServiceComposite.
      *
      * @param service The ServiceComposite for which to lookup the ServiceDescriptor
+     *
      * @return The ServiceDescriptor of the ServiceComposite
      */
     ServiceDescriptor serviceDescriptorFor( Object service );
@@ -111,6 +120,7 @@ public interface Qi4j
      * Returns the PropertyDescriptor of the Property.
      *
      * @param property The Property for which to lookup the PropertyDescriptor
+     *
      * @return The PropertyDescriptor of the Property
      */
     PropertyDescriptor propertyDescriptorFor( Property<?> property );
@@ -119,11 +129,83 @@ public interface Qi4j
      * Returns the AssociationDescriptor of the Association.
      *
      * @param association The Association for which to lookup the AssociationDescriptor
+     *
      * @return The AssociationDescriptor of the Association
      */
     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.
+     * <p/>
+     * 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.
+     * <p/>
+     * 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;
+     * <pre><code>
+     *     public interface Person extends Identity { ... };
+     *     public class MyAssembler
+     *     {
+     *         public void assemble( ModuleAssembly module )
+     *         {
+     *             module.values( Person.class );
+     *             module.entities( Person.class );
+     *         }
+     *     }
+     * </code></pre>
+     *
+     * @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 extends Identity> T toValue( Class<T> 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.
+     * <p/>
+     * 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.
+     * <p/>
+     * This method MUST be called within a UnitOfWork.
+     * <p/>
+     * 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.
+     * <p/>
+     * 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;
+     * <pre><code>
+     *     public interface Person extends Identity { ... };
+     *     public class MyAssembler
+     *     {
+     *         public void assemble( ModuleAssembly module )
+     *         {
+     *             module.values( Person.class );
+     *             module.entities( Person.class );
+     *         }
+     *     }
+     * </code></pre>
+     *
+     * @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 extends Identity> T toEntity( Class<T> primaryType, T valueComposite );
+
+    /**
      * Function that returns the CompositeDescriptor of a Composite.
      */
     Function<Composite, CompositeDescriptor> FUNCTION_DESCRIPTOR_FOR = new Function<Composite,
CompositeDescriptor>()

http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/a36aba1f/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 737e6bd..9b5dce7 100644
--- a/core/runtime/src/main/java/org/qi4j/runtime/Qi4jRuntimeImpl.java
+++ b/core/runtime/src/main/java/org/qi4j/runtime/Qi4jRuntimeImpl.java
@@ -15,12 +15,17 @@ package org.qi4j.runtime;
 
 import java.lang.reflect.InvocationHandler;
 import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
 import org.qi4j.api.Qi4j;
 import org.qi4j.api.association.AbstractAssociation;
+import org.qi4j.api.association.Association;
 import org.qi4j.api.association.AssociationDescriptor;
 import org.qi4j.api.association.AssociationStateHolder;
 import org.qi4j.api.association.AssociationWrapper;
+import org.qi4j.api.association.ManyAssociation;
 import org.qi4j.api.association.ManyAssociationWrapper;
+import org.qi4j.api.association.NamedAssociation;
 import org.qi4j.api.association.NamedAssociationWrapper;
 import org.qi4j.api.composite.Composite;
 import org.qi4j.api.composite.CompositeDescriptor;
@@ -28,8 +33,11 @@ import org.qi4j.api.composite.CompositeInstance;
 import org.qi4j.api.composite.ModelDescriptor;
 import org.qi4j.api.composite.TransientComposite;
 import org.qi4j.api.composite.TransientDescriptor;
+import org.qi4j.api.entity.EntityBuilder;
 import org.qi4j.api.entity.EntityComposite;
 import org.qi4j.api.entity.EntityDescriptor;
+import org.qi4j.api.entity.EntityReference;
+import org.qi4j.api.entity.Identity;
 import org.qi4j.api.property.Property;
 import org.qi4j.api.property.PropertyDescriptor;
 import org.qi4j.api.property.PropertyWrapper;
@@ -38,18 +46,26 @@ import org.qi4j.api.service.ServiceComposite;
 import org.qi4j.api.service.ServiceDescriptor;
 import org.qi4j.api.service.ServiceReference;
 import org.qi4j.api.structure.Module;
+import org.qi4j.api.unitofwork.NoSuchEntityException;
 import org.qi4j.api.unitofwork.UnitOfWork;
+import org.qi4j.api.value.ValueBuilder;
 import org.qi4j.api.value.ValueComposite;
 import org.qi4j.api.value.ValueDescriptor;
 import org.qi4j.bootstrap.ApplicationAssemblyFactory;
 import org.qi4j.bootstrap.ApplicationModelFactory;
 import org.qi4j.bootstrap.Qi4jRuntime;
+import org.qi4j.functional.Function;
 import org.qi4j.runtime.association.AbstractAssociationInstance;
+import org.qi4j.runtime.association.AssociationInstance;
+import org.qi4j.runtime.association.ManyAssociationInstance;
+import org.qi4j.runtime.association.NamedAssociationInstance;
 import org.qi4j.runtime.bootstrap.ApplicationAssemblyFactoryImpl;
 import org.qi4j.runtime.bootstrap.ApplicationModelFactoryImpl;
+import org.qi4j.runtime.composite.FunctionStateResolver;
 import org.qi4j.runtime.composite.ProxyReferenceInvocationHandler;
 import org.qi4j.runtime.composite.TransientInstance;
 import org.qi4j.runtime.entity.EntityInstance;
+import org.qi4j.runtime.entity.EntityModel;
 import org.qi4j.runtime.property.PropertyInstance;
 import org.qi4j.runtime.service.ImportedServiceReferenceInstance;
 import org.qi4j.runtime.service.ServiceInstance;
@@ -58,6 +74,7 @@ import org.qi4j.runtime.structure.ModuleUnitOfWork;
 import org.qi4j.runtime.value.ValueInstance;
 import org.qi4j.spi.Qi4jSPI;
 import org.qi4j.spi.entity.EntityState;
+import org.qi4j.spi.entity.NamedAssociationState;
 
 import static java.lang.reflect.Proxy.getInvocationHandler;
 import static org.qi4j.runtime.composite.TransientInstance.compositeInstanceOf;
@@ -160,7 +177,7 @@ public final class Qi4jRuntimeImpl
         else if( compositeOrServiceReferenceOrUow instanceof ImportedServiceReferenceInstance
)
         {
             ImportedServiceReferenceInstance<?> importedServiceReference
-                                                = (ImportedServiceReferenceInstance<?>)
compositeOrServiceReferenceOrUow;
+                = (ImportedServiceReferenceInstance<?>) compositeOrServiceReferenceOrUow;
             return importedServiceReference.module();
         }
         throw new IllegalArgumentException( "Wrong type. Must be one of "
@@ -205,7 +222,7 @@ public final class Qi4jRuntimeImpl
         else if( compositeOrServiceReference instanceof ImportedServiceReferenceInstance
)
         {
             ImportedServiceReferenceInstance<?> importedServiceReference
-                                                = (ImportedServiceReferenceInstance<?>)
compositeOrServiceReference;
+                = (ImportedServiceReferenceInstance<?>) compositeOrServiceReference;
             return importedServiceReference.serviceDescriptor();
         }
         throw new IllegalArgumentException( "Wrong type. Must be one of "
@@ -312,7 +329,7 @@ public final class Qi4jRuntimeImpl
         {
             association = ( (ManyAssociationWrapper) association ).next();
         }
-        
+
         while( association instanceof NamedAssociationWrapper )
         {
             association = ( (NamedAssociationWrapper) association ).next();
@@ -321,10 +338,244 @@ public final class Qi4jRuntimeImpl
         return (AssociationDescriptor) ( (AbstractAssociationInstance) association ).associationInfo();
     }
 
+    @Override
+    public <T extends Identity> T toValue( Class<T> primaryType, T entityComposite
)
+    {
+        EntityDescriptor entityDescriptor = entityDescriptorFor( entityComposite );
+        Function<PropertyDescriptor, Object> propertyFunction = new ToValuePropertyMappingFunction<T>(
entityComposite );
+        Function<AssociationDescriptor, EntityReference> assocationFunction = new ToValueAssociationMappingFunction<T>(
entityComposite );
+        Function<AssociationDescriptor, Iterable<EntityReference>> manyAssocFunction
= new ToValueManyAssociationMappingFunction<T>( entityComposite );
+        Function<AssociationDescriptor, Map<String, EntityReference>> namedAssocFunction
= new ToValueNameAssociationMappingFunction<T>( entityComposite );
+
+        @SuppressWarnings( "unchecked" )
+        ValueBuilder<T> builder = moduleOf( entityComposite ).newValueBuilderWithState(
+            (Class<T>) entityDescriptor.primaryType(), propertyFunction, assocationFunction,
manyAssocFunction, namedAssocFunction );
+        return builder.newInstance();
+    }
+
+    @Override
+    public <T extends Identity> T toEntity( Class<T> primaryType, T valueComposite
)
+    {
+        Function<PropertyDescriptor, Object> propertyFunction = new ToEntityPropertyMappingFunction<T>(
valueComposite );
+        Function<AssociationDescriptor, EntityReference> assocationFunction = new ToEntityAssociationMappingFunction<T>(
valueComposite );
+        Function<AssociationDescriptor, Iterable<EntityReference>> manyAssocFunction
= new ToEntityManyAssociationMappingFunction<T>( valueComposite );
+        Function<AssociationDescriptor, Map<String, EntityReference>> namedAssocFunction
= new ToEntityNameAssociationMappingFunction<T>( 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<T> entityBuilder = uow.newEntityBuilderWithState( primaryType,
+                                                                            identity,
+                                                                            propertyFunction,
+                                                                            assocationFunction,
+                                                                            manyAssocFunction,
+                                                                            namedAssocFunction
);
+            return entityBuilder.newInstance();
+        }
+    }
+
     // SPI
     @Override
     public EntityState entityStateOf( EntityComposite composite )
     {
         return EntityInstance.entityInstanceOf( composite ).entityState();
     }
+
+    @Override
+    public EntityReference entityReferenceOf( Association assoc )
+    {
+        @SuppressWarnings( "unchecked" )
+        Property<EntityReference> associationState = ( (AssociationInstance) assoc
).getAssociationState();
+        return associationState.get();
+    }
+
+    @Override
+    public Iterable<EntityReference> entityReferenceOf( ManyAssociation assoc )
+    {
+        return ( (ManyAssociationInstance) assoc ).getManyAssociationState();
+    }
+
+    @Override
+    public Iterable<Map.Entry<String, EntityReference>> entityReferenceOf( NamedAssociation
assoc )
+    {
+        return ( (NamedAssociationInstance) assoc ).getEntityReferences();
+    }
+
+    private class ToValuePropertyMappingFunction<T>
+        implements Function<PropertyDescriptor, Object>
+    {
+        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<T>
+        implements Function<AssociationDescriptor, EntityReference>
+    {
+        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<T>
+        implements Function<AssociationDescriptor, Iterable<EntityReference>>
+    {
+        private final T entity;
+
+        public ToValueManyAssociationMappingFunction( T entity )
+        {
+            this.entity = entity;
+        }
+
+        @Override
+        public Iterable<EntityReference> map( AssociationDescriptor associationDescriptor
)
+        {
+            EntityState entityState = entityStateOf( (EntityComposite) entity );
+            return entityState.manyAssociationValueOf( associationDescriptor.qualifiedName()
);
+        }
+    }
+
+    private class ToValueNameAssociationMappingFunction<T>
+        implements Function<AssociationDescriptor, Map<String, EntityReference>>
+    {
+        private final T entity;
+
+        public ToValueNameAssociationMappingFunction( T entity )
+        {
+            this.entity = entity;
+        }
+
+        @Override
+        public Map<String, EntityReference> map( AssociationDescriptor associationDescriptor
)
+        {
+            Map<String, EntityReference> 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<T>
+        implements Function<PropertyDescriptor, Object>
+    {
+        private final T value;
+
+        public ToEntityPropertyMappingFunction( T value )
+        {
+            this.value = value;
+        }
+
+        @Override
+        public Object map( PropertyDescriptor propertyDescriptor )
+        {
+            StateHolder state = stateOf( (ValueComposite) value );
+            Property<Object> property = state.propertyFor( propertyDescriptor.accessor()
);
+            return property.get();
+        }
+    }
+
+    private class ToEntityAssociationMappingFunction<T>
+        implements Function<AssociationDescriptor, EntityReference>
+    {
+
+        private final T value;
+
+        public ToEntityAssociationMappingFunction( T value )
+        {
+            this.value = value;
+        }
+
+        @Override
+        public EntityReference map( AssociationDescriptor associationDescriptor )
+        {
+            AssociationStateHolder state = stateOf( (ValueComposite) value );
+            AssociationInstance<T> association = (AssociationInstance<T>) state.associationFor(
associationDescriptor.accessor() );
+            return association.getAssociationState().get();
+        }
+    }
+
+    private class ToEntityManyAssociationMappingFunction<T>
+        implements Function<AssociationDescriptor, Iterable<EntityReference>>
+    {
+
+        private final T value;
+
+        public ToEntityManyAssociationMappingFunction( T value )
+        {
+            this.value = value;
+        }
+
+        @Override
+        public Iterable<EntityReference> map( AssociationDescriptor associationDescriptor
)
+        {
+            AssociationStateHolder state = stateOf( (ValueComposite) value );
+            ManyAssociationInstance<T> association = (ManyAssociationInstance<T>)
state.manyAssociationFor( associationDescriptor
+                                                                                        
                   .accessor() );
+            return association.getManyAssociationState();
+        }
+    }
+
+    private class ToEntityNameAssociationMappingFunction<T>
+        implements Function<AssociationDescriptor, Map<String, EntityReference>>
+    {
+        private final T value;
+
+        public ToEntityNameAssociationMappingFunction( T value )
+        {
+            this.value = value;
+        }
+
+        @Override
+        public Map<String, EntityReference> map( AssociationDescriptor associationDescriptor
)
+        {
+            AssociationStateHolder state = stateOf( (ValueComposite) value );
+            NamedAssociationInstance<T> association = (NamedAssociationInstance<T>)
state.namedAssociationFor( associationDescriptor
+                                                                                        
                     .accessor() );
+            HashMap<String, EntityReference> result = new HashMap<>();
+            for( Map.Entry<String, EntityReference> entry : association.getEntityReferences()
)
+            {
+                result.put( entry.getKey(), entry.getValue() );
+            }
+            return result;
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/a36aba1f/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 4ca67b2..284de5d 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,7 +24,9 @@ import java.util.Iterator;
 import java.util.Map;
 import org.qi4j.api.association.NamedAssociation;
 import org.qi4j.api.entity.EntityReference;
+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;
 
@@ -100,4 +102,53 @@ public class NamedAssociationInstance<T>
         return map;
     }
 
+    public Iterable<Map.Entry<String,EntityReference>> getEntityReferences()
+    {
+        return Iterables.map( new Function<String, Map.Entry<String,EntityReference>>()
+        {
+            @Override
+            public Map.Entry<String, EntityReference> map( final String key )
+            {
+                final EntityReference value = namedAssociationState.get( key );
+                return new Map.Entry<String, EntityReference>()
+                {
+                    @Override
+                    public String getKey()
+                    {
+                        return key;
+                    }
+
+                    @Override
+                    public EntityReference getValue()
+                    {
+                        return value;
+                    }
+
+                    @Override
+                    public EntityReference setValue( EntityReference value )
+                    {
+                        throw new UnsupportedOperationException( "Immutable Map" );
+                    }
+
+                    @Override
+                    public boolean equals( Object o )
+                    {
+                        if( o instanceof Map.Entry)
+                        {
+                            Map.Entry other = (Map.Entry) o;
+                            return key.equals(other.getKey());
+                        }
+                        return false;
+                    }
+
+                    @Override
+                    public int hashCode()
+                    {
+                        return 997 * key.hashCode() + 981813497;
+                    }
+                };
+            }
+        }, namedAssociationState );
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/a36aba1f/core/runtime/src/main/java/org/qi4j/runtime/composite/FunctionStateResolver.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/qi4j/runtime/composite/FunctionStateResolver.java
b/core/runtime/src/main/java/org/qi4j/runtime/composite/FunctionStateResolver.java
index 284929d..0217ed0 100644
--- a/core/runtime/src/main/java/org/qi4j/runtime/composite/FunctionStateResolver.java
+++ b/core/runtime/src/main/java/org/qi4j/runtime/composite/FunctionStateResolver.java
@@ -22,6 +22,10 @@ import org.qi4j.api.entity.EntityReference;
 import org.qi4j.api.property.PropertyDescriptor;
 import org.qi4j.functional.Function;
 import org.qi4j.functional.Iterables;
+import org.qi4j.runtime.association.ManyAssociationModel;
+import org.qi4j.runtime.association.NamedAssociationModel;
+import org.qi4j.runtime.entity.EntityModel;
+import org.qi4j.spi.entity.EntityState;
 
 /**
  * Function based StateResolver.
@@ -68,4 +72,33 @@ public class FunctionStateResolver
     {
         return namedAssociationFunction.map( associationDescriptor );
     }
+
+    public void populateState( EntityModel model, EntityState state )
+    {
+        for( PropertyDescriptor propDesc : model.state().properties() )
+        {
+            Object value = getPropertyState( propDesc );
+            state.setPropertyValue( propDesc.qualifiedName(), value );
+        }
+        for( AssociationDescriptor assDesc : model.state().associations() )
+        {
+            EntityReference ref = getAssociationState( assDesc );
+            state.setAssociationValue( assDesc.qualifiedName(), ref );
+        }
+        for( ManyAssociationModel manyAssDesc : model.state().manyAssociations() )
+        {
+            for( EntityReference ref : getManyAssociationState( manyAssDesc ) )
+            {
+                state.manyAssociationValueOf( manyAssDesc.qualifiedName() ).add( 0, ref );
+            }
+        }
+        for( NamedAssociationModel namedAssDesc : model.state().namedAssociations() )
+        {
+            for( Map.Entry<String, EntityReference> entry : getNamedAssociationState(
namedAssDesc ).entrySet() )
+            {
+                state.namedAssociationValueOf( namedAssDesc.qualifiedName() ).put( entry.getKey(),
entry.getValue() );
+            }
+        }
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/a36aba1f/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 8bb0ffd..95c2e92 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
@@ -26,6 +26,7 @@ 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;
@@ -91,30 +92,7 @@ public final class EntityBuilderInstance<T>
         model.model().initState( model.module(), entityState );
         if( stateResolver != null )
         {
-            for( PropertyDescriptor propDesc : model.model().state().properties() )
-            {
-                Object value = stateResolver.getPropertyState( propDesc );
-                entityState.setPropertyValue( propDesc.qualifiedName(), value );
-            }
-            for( AssociationDescriptor assDesc : model.model().state().associations() )
-            {
-                EntityReference ref = stateResolver.getAssociationState( assDesc );
-                entityState.setAssociationValue( assDesc.qualifiedName(), ref );
-            }
-            for( ManyAssociationModel manyAssDesc : model.model().state().manyAssociations()
)
-            {
-                for( EntityReference ref : stateResolver.getManyAssociationState( manyAssDesc
) )
-                {
-                    entityState.manyAssociationValueOf( manyAssDesc.qualifiedName() ).add(
0, ref );
-                }
-            }
-            for( NamedAssociationModel namedAssDesc : model.model().state().namedAssociations()
)
-            {
-                for( Map.Entry<String, EntityReference> entry : stateResolver.getNamedAssociationState(
namedAssDesc ).entrySet() )
-                {
-                    entityState.namedAssociationValueOf( namedAssDesc.qualifiedName() ).put(
entry.getKey(), entry.getValue() );
-                }
-            }
+            (( FunctionStateResolver) 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/a36aba1f/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
new file mode 100644
index 0000000..2f0fd2c
--- /dev/null
+++ b/core/runtime/src/test/java/org/qi4j/runtime/value/ValueWithAssociationTest.java
@@ -0,0 +1,132 @@
+package org.qi4j.runtime.value;
+
+import org.junit.Ignore;
+import org.junit.Test;
+import org.qi4j.api.association.Association;
+import org.qi4j.api.association.AssociationStateHolder;
+import org.qi4j.api.association.ManyAssociation;
+import org.qi4j.api.association.NamedAssociation;
+import org.qi4j.api.entity.EntityBuilder;
+import org.qi4j.api.entity.EntityComposite;
+import org.qi4j.api.entity.EntityReference;
+import org.qi4j.api.entity.Identity;
+import org.qi4j.api.property.Property;
+import org.qi4j.api.unitofwork.UnitOfWork;
+import org.qi4j.api.unitofwork.UnitOfWorkCompletionException;
+import org.qi4j.api.value.ValueBuilder;
+import org.qi4j.api.value.ValueSerialization;
+import org.qi4j.bootstrap.AssemblyException;
+import org.qi4j.bootstrap.ModuleAssembly;
+import org.qi4j.entitystore.memory.MemoryEntityStoreService;
+import org.qi4j.spi.uuid.UuidIdentityGeneratorService;
+import org.qi4j.test.AbstractQi4jTest;
+import org.qi4j.valueserialization.orgjson.OrgJsonValueSerializationService;
+
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+
+public class ValueWithAssociationTest extends AbstractQi4jTest
+{
+    @Override
+    public void assemble( ModuleAssembly module )
+        throws AssemblyException
+    {
+        module.entities( SimpleEntity.class );
+        module.entities( DualFaced.class );
+        module.values( DualFaced.class );
+        module.services( MemoryEntityStoreService.class );
+        module.services( UuidIdentityGeneratorService.class );
+        module.services( OrgJsonValueSerializationService.class ).taggedWith( ValueSerialization.Formats.JSON
);
+    }
+
+    @Test  @Ignore
+    public void givenEntityInStoreWhenFetchEntityReferenceExpectSuccess()
+        throws UnitOfWorkCompletionException
+    {
+        String identity1;
+        String identity2;
+        DualFaced value;
+        try (UnitOfWork uow = module.newUnitOfWork())
+        {
+            EntityBuilder<SimpleEntity> builder1 = uow.newEntityBuilder( SimpleEntity.class
);
+            builder1.instance().name().set( "Niclas" );
+            SimpleEntity simpleEntity = builder1.newInstance();
+            identity1 = simpleEntity.identity().get();
+
+            EntityBuilder<DualFaced> 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();
+            value = spi.toValue( DualFaced.class, faced );
+            assertThat( value.identity().get(), equalTo( identity2 ) );
+            uow.complete();
+        }
+
+        try (UnitOfWork uow = module.newUnitOfWork())
+        {
+            DualFaced entity = uow.get( DualFaced.class, identity2 );
+            AssociationStateHolder holder = spi.stateOf( (EntityComposite) entity );
+            Association<?> simple = holder.allAssociations().iterator().next();
+            ManyAssociation<?> simples = holder.allManyAssociations().iterator().next();
+            NamedAssociation<?> namedSimples = holder.allNamedAssociations().iterator().next();
+
+            assertThat( spi.entityReferenceOf( simple ), equalTo( EntityReference.parseEntityReference(
identity1 ) ) );
+            assertThat( spi.entityReferenceOf( simples )
+                            .iterator()
+                            .next(), equalTo( EntityReference.parseEntityReference( identity1
) ) );
+            assertThat( spi.entityReferenceOf( namedSimples )
+                            .iterator()
+                            .next()
+                            .getValue(), equalTo( EntityReference.parseEntityReference( identity1
) ) );
+
+            DualFaced resurrected = spi.toEntity( DualFaced.class, value );
+            assertThat( resurrected.simple(), equalTo( entity.simple() ) );
+            assertThat( resurrected.simples(), equalTo( entity.simples() ) );
+            assertThat( resurrected.namedSimples(), equalTo( entity.namedSimples() ) );
+        }
+    }
+
+    @Test
+    public void givenNewValueWhenConvertingToEntityExpectNewEntityInStore()
+        throws UnitOfWorkCompletionException
+    {
+        ValueBuilder<DualFaced> builder = module.newValueBuilder( DualFaced.class );
+        builder.prototype().identity().set( "1234" );
+        builder.prototype().name().set( "Hedhman" );
+        DualFaced value = builder.newInstance();
+
+        try (UnitOfWork uow = module.newUnitOfWork())
+        {
+            spi.toEntity( DualFaced.class, value );
+            uow.complete();
+        }
+
+        try (UnitOfWork uow = module.newUnitOfWork())
+        {
+            DualFaced entity = uow.get( DualFaced.class, "1234" );
+            assertThat( entity.identity().get(), equalTo( "1234" ) );
+            assertThat( entity.name().get(), equalTo( "Hedhman" ) );
+            uow.complete();
+        }
+    }
+
+    public interface SimpleEntity extends Identity
+    {
+        Property<String> name();
+    }
+
+    public interface DualFaced extends Identity
+    {
+        Property<String> name();
+
+        Association<SimpleEntity> simple();
+
+        ManyAssociation<SimpleEntity> simples();
+
+        NamedAssociation<SimpleEntity> namedSimples();
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/a36aba1f/core/spi/src/main/java/org/qi4j/spi/Qi4jSPI.java
----------------------------------------------------------------------
diff --git a/core/spi/src/main/java/org/qi4j/spi/Qi4jSPI.java b/core/spi/src/main/java/org/qi4j/spi/Qi4jSPI.java
index 2586d95..cff2507 100644
--- a/core/spi/src/main/java/org/qi4j/spi/Qi4jSPI.java
+++ b/core/spi/src/main/java/org/qi4j/spi/Qi4jSPI.java
@@ -14,10 +14,15 @@
 
 package org.qi4j.spi;
 
+import java.util.Map;
 import org.qi4j.api.Qi4j;
+import org.qi4j.api.association.Association;
 import org.qi4j.api.association.AssociationStateHolder;
+import org.qi4j.api.association.ManyAssociation;
+import org.qi4j.api.association.NamedAssociation;
 import org.qi4j.api.composite.TransientComposite;
 import org.qi4j.api.entity.EntityComposite;
+import org.qi4j.api.entity.EntityReference;
 import org.qi4j.api.property.StateHolder;
 import org.qi4j.api.value.ValueComposite;
 import org.qi4j.spi.entity.EntityState;
@@ -36,4 +41,29 @@ public interface Qi4jSPI
 
     // Entities
     EntityState entityStateOf( EntityComposite composite );
+
+    /**
+     * Fetches the EntityReference without loading the referenced entity.
+     *
+     * @param assoc The Association for which we want to obtain the EntityReference
+     * @return The EntityReference of the given Association.
+     */
+    EntityReference entityReferenceOf( Association assoc );
+
+    /**
+     * Fetches the EntityReferences without loading the referenced entities.
+     *
+     * @param assoc The ManyAssociation for which we want to obtain the EntityReferences.
+     * @return An Iteranble of all the EntityReferences of the given ManyAssociation.
+     */
+    Iterable<EntityReference> entityReferenceOf( ManyAssociation assoc );
+
+    /**
+     * Fetches the EntityReferences without loading the referenced entities.
+     *
+     * @param assoc The NamedAssociation for which we want to obtain the EntityReference
+     * @return An Iteranble of Map.Entry with the name and EntityReference of the given NamedAssociation.
+     */
+    Iterable<Map.Entry<String,EntityReference>> entityReferenceOf( NamedAssociation
assoc );
+
 }

http://git-wip-us.apache.org/repos/asf/zest-qi4j/blob/a36aba1f/core/spi/src/main/java/org/qi4j/spi/entity/NamedAssociationState.java
----------------------------------------------------------------------
diff --git a/core/spi/src/main/java/org/qi4j/spi/entity/NamedAssociationState.java b/core/spi/src/main/java/org/qi4j/spi/entity/NamedAssociationState.java
index 5cf3257..584feee 100644
--- a/core/spi/src/main/java/org/qi4j/spi/entity/NamedAssociationState.java
+++ b/core/spi/src/main/java/org/qi4j/spi/entity/NamedAssociationState.java
@@ -40,5 +40,4 @@ public interface NamedAssociationState
     EntityReference get( String name );
 
     String nameOf( EntityReference entityReference );
-
 }


Mime
View raw message