You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polygene.apache.org by ni...@apache.org on 2017/04/10 03:47:36 UTC

polygene-java git commit: POLYGENE-54 - Adding a Testcase of new converter feature.

Repository: polygene-java
Updated Branches:
  refs/heads/develop 9ee911b0e -> 51c6c27c3


POLYGENE-54 - Adding a Testcase of new converter feature.


Project: http://git-wip-us.apache.org/repos/asf/polygene-java/repo
Commit: http://git-wip-us.apache.org/repos/asf/polygene-java/commit/51c6c27c
Tree: http://git-wip-us.apache.org/repos/asf/polygene-java/tree/51c6c27c
Diff: http://git-wip-us.apache.org/repos/asf/polygene-java/diff/51c6c27c

Branch: refs/heads/develop
Commit: 51c6c27c37e776b9f1fca66e020c8d2e4e3e1328
Parents: 9ee911b
Author: niclas <ni...@spicter.com>
Authored: Mon Apr 10 11:47:29 2017 +0800
Committer: niclas <ni...@spicter.com>
Committed: Mon Apr 10 11:47:29 2017 +0800

----------------------------------------------------------------------
 .../api/unitofwork/ToEntityConverter.java       |  39 ++++--
 .../api/unitofwork/ToValueConverter.java        |  40 ++++--
 .../api/unitofwork/ToEntityConversionTest.java  | 140 +++++++++++++++++++
 .../api/unitofwork/ToValueConversionTest.java   | 139 ++++++++++++++++++
 .../runtime/unitofwork/ModuleUnitOfWork.java    |  84 ++++-------
 5 files changed, 358 insertions(+), 84 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/polygene-java/blob/51c6c27c/core/api/src/main/java/org/apache/polygene/api/unitofwork/ToEntityConverter.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/unitofwork/ToEntityConverter.java b/core/api/src/main/java/org/apache/polygene/api/unitofwork/ToEntityConverter.java
index dfa1195..22096d6 100644
--- a/core/api/src/main/java/org/apache/polygene/api/unitofwork/ToEntityConverter.java
+++ b/core/api/src/main/java/org/apache/polygene/api/unitofwork/ToEntityConverter.java
@@ -31,13 +31,12 @@ import org.apache.polygene.api.usecase.Usecase;
 /**
  * MetaInfo holder for value-to-entity conversion in {@link UnitOfWork#toEntity(Class, HasIdentity)}.
  * <p>
- *     The implementation of this interface should be registered as metaInfo on the {@link Usecase}
- *     of the {@link UnitOfWork} where the conversion should take place. It is also possible to register
- *     the implementation to the {@link UnitOfWork}'s metaInfo.
+ * The implementation of this interface should be registered as metaInfo on the {@link Usecase}
+ * of the {@link UnitOfWork} where the conversion should take place. It is also possible to register
+ * the implementation to the {@link UnitOfWork}'s metaInfo.
  * </p>
  * <p>Example;</p>
- * <code><pre>
- *
+ * <pre><code>
  *     private static final Usecase USECASE_GET_USER_DETAILS = UseCaseBuilder
  *                                                                 .buildUseCase("get user details")
  *                                                                 .withMetaInfo( new UserToEntityConverter() )
@@ -56,7 +55,7 @@ import org.apache.polygene.api.usecase.Usecase;
  *     }
  *     :
  *     :
- * </pre></code>
+ * </code></pre>
  */
 public interface ToEntityConverter
 {
@@ -64,31 +63,43 @@ public interface ToEntityConverter
      * Returns the Function to convert each of the properties of the entities into the value.
      *
      * @param entityComposite the entity that is to be converted.
-     * @return The function to do the conversion, or null if the default converter should be used.
+     * @param defaultFn       The default converter function. This can be used to delegate non-special cases, or simply
+     *                        return to do all the conversions
+     * @return The function to do the conversion. It MUST NOT return null, and if no conversion is wanted, return the defaultFn.
      */
-    Function<PropertyDescriptor, Object> properties( Object entityComposite );
+    Function<PropertyDescriptor, Object> properties( Object entityComposite,
+                                                     Function<PropertyDescriptor, Object> defaultFn );
 
     /**
      * Returns the Function to convert each of the associations of the entities into the value.
      *
      * @param entityComposite the entity that is to be converted.
-     * @return The function to do the conversion, or null if the default converter should be used.
+     * @param defaultFn       The default converter function. This can be used to delegate non-special cases, or simply
+     *                        return to do all the conversions
+     * @return The function to do the conversion. It MUST NOT return null, and if no conversion is wanted, return the defaultFn.
      */
-    Function<AssociationDescriptor, EntityReference> associations( Object entityComposite );
+    Function<AssociationDescriptor, EntityReference> associations( Object entityComposite,
+                                                                   Function<AssociationDescriptor, EntityReference> defaultFn );
 
     /**
      * Returns the Function to convert each of the manyAssociations of the entities into the value.
      *
      * @param entityComposite the entity that is to be converted.
-     * @return The function to do the conversion, or null if the default converter should be used.
+     * @param defaultFn       The default converter function. This can be used to delegate non-special cases, or simply
+     *                        return to do all the conversions
+     * @return The function to do the conversion. It MUST NOT return null, and if no conversion is wanted, return the defaultFn.
      */
-    Function<AssociationDescriptor, Stream<EntityReference>> manyAssociations( Object entityComposite );
+    Function<AssociationDescriptor, Stream<EntityReference>> manyAssociations( Object entityComposite,
+                                                                               Function<AssociationDescriptor, Stream<EntityReference>> defaultFn );
 
     /**
      * Returns the Function to convert each of the NamedAssociations of the entities into the value.
      *
      * @param entityComposite the entity that is to be converted.
-     * @return The function to do the conversion, or null if the default converter should be used.
+     * @param defaultFn       The default converter function. This can be used to delegate non-special cases, or simply
+     *                        return to do all the conversions
+     * @return The function to do the conversion. It MUST NOT return null, and if no conversion is wanted, return the defaultFn.
      */
-    Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> namedAssociations( Object entityComposite );
+    Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> namedAssociations( Object entityComposite,
+                                                                                                   Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> defaultFn );
 }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/51c6c27c/core/api/src/main/java/org/apache/polygene/api/unitofwork/ToValueConverter.java
----------------------------------------------------------------------
diff --git a/core/api/src/main/java/org/apache/polygene/api/unitofwork/ToValueConverter.java b/core/api/src/main/java/org/apache/polygene/api/unitofwork/ToValueConverter.java
index 519a4c5..4afeda7 100644
--- a/core/api/src/main/java/org/apache/polygene/api/unitofwork/ToValueConverter.java
+++ b/core/api/src/main/java/org/apache/polygene/api/unitofwork/ToValueConverter.java
@@ -24,23 +24,21 @@ import java.util.function.Function;
 import java.util.stream.Stream;
 import org.apache.polygene.api.association.AssociationDescriptor;
 import org.apache.polygene.api.entity.EntityReference;
-import org.apache.polygene.api.property.PropertyDescriptor;
 import org.apache.polygene.api.identity.HasIdentity;
+import org.apache.polygene.api.property.PropertyDescriptor;
 import org.apache.polygene.api.usecase.Usecase;
 
 /**
  * MetaInfo holder for entity-to-value conversion in {@link UnitOfWork#toValue(Class, HasIdentity)}
  * <p>
- *     The implementation of this interface should be registered as metaInfo on the {@link Usecase}
- *     of the {@link UnitOfWork} where the conversion should take place.
+ * The implementation of this interface should be registered as metaInfo on the {@link Usecase}
+ * of the {@link UnitOfWork} where the conversion should take place.
  * </p>
- * <code><pre>
- *
+ * <pre><code>
  *     private static final Usecase USECASE_GET_USER_DETAILS = UseCaseBuilder
  *                                                                 .buildUseCase("get user details")
  *                                                                 .withMetaInfo( new MyToValueConverter() )
  *                                                                 .newUsecase();
- *
  *     &#64;Structure
  *     private UnitOfWorkFactory uowf;
  *     :
@@ -54,7 +52,7 @@ import org.apache.polygene.api.usecase.Usecase;
  *     }
  *     :
  *     :
- * </pre></code>
+ * </code></pre>
  */
 public interface ToValueConverter
 {
@@ -62,31 +60,43 @@ public interface ToValueConverter
      * Returns the Function to convert each of the properties of the entities into the value.
      *
      * @param entityComposite the entity that is to be converted.
-     * @return The function to do the conversion, or null if the default converter should be used.
+     * @param defaultFn       The default converter function. This can be used to delegate non-special cases, or simply
+     *                        return to do all the conversions
+     * @return The function to do the conversion. It MUST NOT return null, and if no conversion is wanted, return the defaultFn.
      */
-    Function<PropertyDescriptor, Object> properties( Object entityComposite );
+    Function<PropertyDescriptor, Object> properties( Object entityComposite,
+                                                     Function<PropertyDescriptor, Object> defaultFn );
 
     /**
      * Returns the Function to convert each of the associations of the entities into the value.
      *
      * @param entityComposite the entity that is to be converted.
-     * @return The function to do the conversion, or null if the default converter should be used.
+     * @param defaultFn       The default converter function. This can be used to delegate non-special cases, or simply
+     *                        return to do all the conversions
+     * @return The function to do the conversion. It MUST NOT return null, and if no conversion is wanted, return the defaultFn.
      */
-    Function<AssociationDescriptor, EntityReference> associations( Object entityComposite );
+    Function<AssociationDescriptor, EntityReference> associations( Object entityComposite,
+                                                                   Function<AssociationDescriptor, EntityReference> defaultFn );
 
     /**
      * Returns the Function to convert each of the manyAssociations of the entities into the value.
      *
      * @param entityComposite the entity that is to be converted.
-     * @return The function to do the conversion, or null if the default converter should be used.
+     * @param defaultFn       The default converter function. This can be used to delegate non-special cases, or simply
+     *                        return to do all the conversions
+     * @return The function to do the conversion. It MUST NOT return null, and if no conversion is wanted, return the defaultFn.
      */
-    Function<AssociationDescriptor, Stream<EntityReference>> manyAssociations( Object entityComposite );
+    Function<AssociationDescriptor, Stream<EntityReference>> manyAssociations( Object entityComposite,
+                                                                               Function<AssociationDescriptor, Stream<EntityReference>> defaultFn );
 
     /**
      * Returns the Function to convert each of the NamedAssociations of the entities into the value.
      *
      * @param entityComposite the entity that is to be converted.
-     * @return The function to do the conversion, or null if the default converter should be used.
+     * @param defaultFn       The default converter function. This can be used to delegate non-special cases, or simply
+     *                        return to do all the conversions
+     * @return The function to do the conversion. It MUST NOT return null, and if no conversion is wanted, return the defaultFn.
      */
-    Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> namedAssociations( Object entityComposite );
+    Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> namedAssociations( Object entityComposite,
+                                                                                                   Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> defaultFn );
 }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/51c6c27c/core/api/src/test/java/org/apache/polygene/api/unitofwork/ToEntityConversionTest.java
----------------------------------------------------------------------
diff --git a/core/api/src/test/java/org/apache/polygene/api/unitofwork/ToEntityConversionTest.java b/core/api/src/test/java/org/apache/polygene/api/unitofwork/ToEntityConversionTest.java
new file mode 100644
index 0000000..5f5a5b5
--- /dev/null
+++ b/core/api/src/test/java/org/apache/polygene/api/unitofwork/ToEntityConversionTest.java
@@ -0,0 +1,140 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *
+ */
+package org.apache.polygene.api.unitofwork;
+
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Stream;
+import org.apache.polygene.api.association.Association;
+import org.apache.polygene.api.association.AssociationDescriptor;
+import org.apache.polygene.api.association.ManyAssociation;
+import org.apache.polygene.api.association.NamedAssociation;
+import org.apache.polygene.api.common.Optional;
+import org.apache.polygene.api.common.QualifiedName;
+import org.apache.polygene.api.common.UseDefaults;
+import org.apache.polygene.api.entity.EntityReference;
+import org.apache.polygene.api.identity.HasIdentity;
+import org.apache.polygene.api.identity.Identity;
+import org.apache.polygene.api.identity.StringIdentity;
+import org.apache.polygene.api.injection.scope.Structure;
+import org.apache.polygene.api.property.Property;
+import org.apache.polygene.api.property.PropertyDescriptor;
+import org.apache.polygene.api.usecase.Usecase;
+import org.apache.polygene.api.usecase.UsecaseBuilder;
+import org.apache.polygene.api.value.ValueBuilder;
+import org.apache.polygene.bootstrap.AssemblyException;
+import org.apache.polygene.bootstrap.ModuleAssembly;
+import org.apache.polygene.spi.PolygeneSPI;
+import org.apache.polygene.test.AbstractPolygeneTest;
+import org.apache.polygene.test.EntityTestAssembler;
+import org.junit.Test;
+
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+
+public class ToEntityConversionTest
+    extends AbstractPolygeneTest
+{
+    @Override
+    public void assemble( ModuleAssembly module )
+        throws AssemblyException
+    {
+        new EntityTestAssembler().assemble( module );
+        module.entities( SomeType.class );
+        module.values( SomeType.class );
+    }
+
+    @Test
+    public void testPropertyConversionToEntity()
+        throws Exception
+    {
+        Identity identity = new StringIdentity( "Niclas" );
+        ValueBuilder<SomeType> vb = valueBuilderFactory.newValueBuilder( SomeType.class );
+        SomeType prototype = vb.prototype();
+        prototype.identity().set( identity );
+        prototype.name().set( "Niclas" );
+        SomeType value = vb.newInstance();
+
+        Usecase usecase = UsecaseBuilder.buildUsecase( "test case" )
+                                        .withMetaInfo( new SomeEntityConverter() )
+                                        .newUsecase();
+        try( UnitOfWork uow = unitOfWorkFactory.newUnitOfWork(usecase) )
+        {
+            SomeType entity = uow.toEntity( SomeType.class, value );
+            assertThat( entity.identity().get(), equalTo( identity ) );
+            assertThat( entity.name().get(), equalTo( "[Niclas]" ) );
+            uow.complete();
+        }
+    }
+
+    interface SomeType extends HasIdentity
+    {
+        Property<String> name();
+
+        @Optional
+        Association<String> assoc();
+
+        @UseDefaults
+        ManyAssociation<String> many();
+
+        @UseDefaults
+        NamedAssociation<String> named();
+    }
+
+    private static class SomeEntityConverter
+        implements ToEntityConverter
+    {
+        @Structure
+        private PolygeneSPI spi;
+
+        @Override
+        public Function<PropertyDescriptor, Object> properties( Object entityComposite, Function<PropertyDescriptor, Object> defaultFn )
+        {
+            return descriptor ->
+            {
+                QualifiedName name = QualifiedName.fromClass( SomeType.class, "name" );
+                Object value = defaultFn.apply( descriptor );
+                if( descriptor.qualifiedName().equals( name ) )
+                {
+                    return "[" + value + "]";
+                }
+                return value;
+            };
+        }
+
+        @Override
+        public Function<AssociationDescriptor, EntityReference> associations( Object entityComposite, Function<AssociationDescriptor, EntityReference> defaultFn )
+        {
+            return defaultFn;
+        }
+
+        @Override
+        public Function<AssociationDescriptor, Stream<EntityReference>> manyAssociations( Object entityComposite, Function<AssociationDescriptor, Stream<EntityReference>> defaultFn )
+        {
+            return defaultFn;
+        }
+
+        @Override
+        public Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> namedAssociations( Object entityComposite, Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> defaultFn )
+        {
+            return defaultFn;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/51c6c27c/core/api/src/test/java/org/apache/polygene/api/unitofwork/ToValueConversionTest.java
----------------------------------------------------------------------
diff --git a/core/api/src/test/java/org/apache/polygene/api/unitofwork/ToValueConversionTest.java b/core/api/src/test/java/org/apache/polygene/api/unitofwork/ToValueConversionTest.java
new file mode 100644
index 0000000..d091745
--- /dev/null
+++ b/core/api/src/test/java/org/apache/polygene/api/unitofwork/ToValueConversionTest.java
@@ -0,0 +1,139 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *
+ */
+package org.apache.polygene.api.unitofwork;
+
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Stream;
+import org.apache.polygene.api.association.Association;
+import org.apache.polygene.api.association.AssociationDescriptor;
+import org.apache.polygene.api.association.ManyAssociation;
+import org.apache.polygene.api.association.NamedAssociation;
+import org.apache.polygene.api.common.Optional;
+import org.apache.polygene.api.common.QualifiedName;
+import org.apache.polygene.api.common.UseDefaults;
+import org.apache.polygene.api.entity.EntityBuilder;
+import org.apache.polygene.api.entity.EntityReference;
+import org.apache.polygene.api.identity.HasIdentity;
+import org.apache.polygene.api.identity.Identity;
+import org.apache.polygene.api.identity.StringIdentity;
+import org.apache.polygene.api.injection.scope.Structure;
+import org.apache.polygene.api.property.Property;
+import org.apache.polygene.api.property.PropertyDescriptor;
+import org.apache.polygene.api.usecase.Usecase;
+import org.apache.polygene.api.usecase.UsecaseBuilder;
+import org.apache.polygene.bootstrap.AssemblyException;
+import org.apache.polygene.bootstrap.ModuleAssembly;
+import org.apache.polygene.spi.PolygeneSPI;
+import org.apache.polygene.test.AbstractPolygeneTest;
+import org.apache.polygene.test.EntityTestAssembler;
+import org.junit.Test;
+
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+
+public class ToValueConversionTest
+    extends AbstractPolygeneTest
+{
+    @Override
+    public void assemble( ModuleAssembly module )
+        throws AssemblyException
+    {
+        new EntityTestAssembler().assemble( module );
+        module.entities( SomeType.class );
+        module.values( SomeType.class );
+    }
+
+    @Test
+    public void testPropertyConversionToValue()
+        throws Exception
+    {
+        Identity identity = new StringIdentity( "Niclas" );
+        Usecase usecase = UsecaseBuilder.buildUsecase( "test case" )
+                                        .withMetaInfo( new SomeValueConverter() )
+                                        .newUsecase();
+        try( UnitOfWork uow = unitOfWorkFactory.newUnitOfWork(usecase) )
+        {
+            EntityBuilder<SomeType> builder = uow.newEntityBuilder( SomeType.class, identity );
+            builder.instance().name().set( "Niclas" );
+            SomeType entity = builder.newInstance();
+            SomeType value = uow.toValue( SomeType.class, entity );
+
+            assertThat( value.name().get(), equalTo( "[Niclas]" ) );
+            assertThat( value.identity().get(), equalTo( identity ) );
+            uow.complete();
+        }
+
+    }
+
+    interface SomeType extends HasIdentity
+    {
+        Property<String> name();
+
+        @Optional
+        Association<String> assoc();
+
+        @UseDefaults
+        ManyAssociation<String> many();
+
+        @UseDefaults
+        NamedAssociation<String> named();
+    }
+
+    private static class SomeValueConverter
+        implements ToValueConverter
+    {
+        @Structure
+        private PolygeneSPI spi;
+
+        @Override
+        public Function<PropertyDescriptor, Object> properties( Object entityComposite, Function<PropertyDescriptor, Object> defaultFn )
+        {
+            return descriptor ->
+            {
+                Object value = defaultFn.apply( descriptor );
+                QualifiedName name = QualifiedName.fromClass( SomeType.class, "name" );
+                if( name.equals( descriptor.qualifiedName() ) )
+                {
+                    return "[" + value + "]";
+                }
+                return value;
+            };
+        }
+
+        @Override
+        public Function<AssociationDescriptor, EntityReference> associations( Object entityComposite, Function<AssociationDescriptor, EntityReference> defaultFn )
+        {
+            return defaultFn;
+        }
+
+        @Override
+        public Function<AssociationDescriptor, Stream<EntityReference>> manyAssociations( Object entityComposite, Function<AssociationDescriptor, Stream<EntityReference>> defaultFn )
+        {
+            return defaultFn;
+        }
+
+        @Override
+        public Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> namedAssociations( Object entityComposite, Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> defaultFn )
+        {
+            return defaultFn;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/51c6c27c/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/ModuleUnitOfWork.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/ModuleUnitOfWork.java b/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/ModuleUnitOfWork.java
index 04508e9..122d096 100644
--- a/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/ModuleUnitOfWork.java
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/ModuleUnitOfWork.java
@@ -431,34 +431,21 @@ public class ModuleUnitOfWork
     public <T extends HasIdentity> T toValue( Class<T> primaryType, T entityComposite )
     {
         Objects.requireNonNull( primaryType );
-        Objects.requireNonNull( entityComposite );
-        Function<PropertyDescriptor, Object> propertyFunction = null;
-        Function<AssociationDescriptor, EntityReference> assocationFunction = null;
-        Function<AssociationDescriptor, Stream<EntityReference>> manyAssocFunction = null;
-        Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> namedAssocFunction = null;
-        ToValueConverter converter = getConverter( ToValueConverter.class );
-        if( converter != null )
-        {
-            propertyFunction = converter.properties( entityComposite );
-            manyAssocFunction = converter.manyAssociations( entityComposite );
-            assocationFunction = converter.associations( entityComposite );
-            namedAssocFunction = converter.namedAssociations( entityComposite );
-        }
-        if( propertyFunction == null )
-        {
-            propertyFunction = new ToValuePropertyMappingFunction( entityComposite );
-        }
-        if( assocationFunction == null )
+        if( entityComposite == null )
         {
-            assocationFunction = new ToValueAssociationMappingFunction<>( entityComposite );
+            return null;
         }
-        if( manyAssocFunction == null )
-        {
-            manyAssocFunction = new ToValueManyAssociationMappingFunction<>( entityComposite );
-        }
-        if( namedAssocFunction == null )
+        Function<PropertyDescriptor, Object> propertyFunction = new ToValuePropertyMappingFunction( entityComposite );
+        Function<AssociationDescriptor, EntityReference> assocationFunction = new ToValueAssociationMappingFunction<>( entityComposite );
+        Function<AssociationDescriptor, Stream<EntityReference>> manyAssocFunction = new ToValueManyAssociationMappingFunction<>( entityComposite );
+        Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> namedAssocFunction = new ToValueNameAssociationMappingFunction<>( entityComposite );
+        ToValueConverter converter = getConverter( ToValueConverter.class );
+        if( converter != null )
         {
-            namedAssocFunction = new ToValueNameAssociationMappingFunction<>( entityComposite );
+            propertyFunction = converter.properties( entityComposite, propertyFunction );
+            assocationFunction = converter.associations( entityComposite, assocationFunction );
+            manyAssocFunction = converter.manyAssociations( entityComposite, manyAssocFunction );
+            namedAssocFunction = converter.namedAssociations( entityComposite, namedAssocFunction );
         }
         @SuppressWarnings( "unchecked" )
         ValueBuilder<T> builder = module().instance().newValueBuilderWithState(
@@ -508,36 +495,23 @@ public class ModuleUnitOfWork
     @Override
     public <T extends HasIdentity> T toEntity( Class<T> primaryType, T valueComposite )
     {
-
-        Function<PropertyDescriptor, Object> propertyFunction = null;
-        Function<AssociationDescriptor, EntityReference> assocationFunction = null;
-        Function<AssociationDescriptor, Stream<EntityReference>> manyAssocFunction = null;
-        Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> namedAssocFunction = null;
-        ToEntityConverter converter = getConverter( ToEntityConverter.class );
-        if( converter != null )
-        {
-            propertyFunction = converter.properties( valueComposite );
-            manyAssocFunction = converter.manyAssociations( valueComposite );
-            assocationFunction = converter.associations( valueComposite );
-            namedAssocFunction = converter.namedAssociations( valueComposite );
-        }
-        if( propertyFunction == null )
-        {
-            propertyFunction = new ToEntityPropertyMappingFunction<>( valueComposite );
-        }
-        if( assocationFunction == null )
-        {
-            assocationFunction = new ToEntityAssociationMappingFunction<>( valueComposite );
-        }
-        if( manyAssocFunction == null )
+        Objects.requireNonNull( primaryType );
+        if( valueComposite == null )
         {
-            manyAssocFunction = new ToEntityManyAssociationMappingFunction<>( valueComposite );
+            return null;
         }
-        if( namedAssocFunction == null )
+        Function<PropertyDescriptor, Object> propertyFunction = new ToEntityPropertyMappingFunction<>( valueComposite );
+        Function<AssociationDescriptor, EntityReference> assocationFunction = new ToEntityAssociationMappingFunction<>( valueComposite );
+        Function<AssociationDescriptor, Stream<EntityReference>> manyAssocFunction = new ToEntityManyAssociationMappingFunction<>( valueComposite );
+        Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> namedAssocFunction = new ToEntityNameAssociationMappingFunction<>( valueComposite );
+        ToEntityConverter converter = getConverter( ToEntityConverter.class );
+        if( converter != null )
         {
-            namedAssocFunction = new ToEntityNameAssociationMappingFunction<>( valueComposite );
+            propertyFunction = converter.properties( valueComposite, propertyFunction );
+            assocationFunction = converter.associations( valueComposite, assocationFunction );
+            manyAssocFunction = converter.manyAssociations( valueComposite, manyAssocFunction );
+            namedAssocFunction = converter.namedAssociations( valueComposite, namedAssocFunction );
         }
-
         try
         {
             T entity = get( primaryType, valueComposite.identity().get() );
@@ -763,7 +737,7 @@ public class ModuleUnitOfWork
     {
         private final T value;
 
-        public ToEntityPropertyMappingFunction( T value )
+        private ToEntityPropertyMappingFunction( T value )
         {
             this.value = value;
         }
@@ -783,7 +757,7 @@ public class ModuleUnitOfWork
 
         private final T value;
 
-        public ToEntityAssociationMappingFunction( T value )
+        private ToEntityAssociationMappingFunction( T value )
         {
             this.value = value;
         }
@@ -803,7 +777,7 @@ public class ModuleUnitOfWork
 
         private final T value;
 
-        public ToEntityManyAssociationMappingFunction( T valueComposite )
+        private ToEntityManyAssociationMappingFunction( T valueComposite )
         {
             this.value = valueComposite;
         }
@@ -821,7 +795,7 @@ public class ModuleUnitOfWork
     {
         private final T value;
 
-        public ToEntityNameAssociationMappingFunction( T valueComposite )
+        private ToEntityNameAssociationMappingFunction( T valueComposite )
         {
             this.value = valueComposite;
         }