You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polygene.apache.org by pa...@apache.org on 2017/02/03 07:58:08 UTC

[07/19] polygene-java git commit: Serialization 3 step 1

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/e4cca11e/extensions/indexing-rdf/src/main/java/org/apache/polygene/index/rdf/assembly/RdfRdbmsSesameStoreAssembler.java
----------------------------------------------------------------------
diff --git a/extensions/indexing-rdf/src/main/java/org/apache/polygene/index/rdf/assembly/RdfRdbmsSesameStoreAssembler.java b/extensions/indexing-rdf/src/main/java/org/apache/polygene/index/rdf/assembly/RdfRdbmsSesameStoreAssembler.java
index 4f10706..7a6c22a 100644
--- a/extensions/indexing-rdf/src/main/java/org/apache/polygene/index/rdf/assembly/RdfRdbmsSesameStoreAssembler.java
+++ b/extensions/indexing-rdf/src/main/java/org/apache/polygene/index/rdf/assembly/RdfRdbmsSesameStoreAssembler.java
@@ -20,7 +20,6 @@
 package org.apache.polygene.index.rdf.assembly;
 
 import org.apache.polygene.api.common.Visibility;
-import org.apache.polygene.api.value.ValueSerialization;
 import org.apache.polygene.bootstrap.Assembler;
 import org.apache.polygene.bootstrap.AssemblyException;
 import org.apache.polygene.bootstrap.ModuleAssembly;
@@ -29,7 +28,6 @@ import org.apache.polygene.index.rdf.query.RdfQueryParserFactory;
 import org.apache.polygene.library.rdf.entity.EntityStateSerializer;
 import org.apache.polygene.library.rdf.entity.EntityTypeSerializer;
 import org.apache.polygene.library.rdf.repository.RdbmsRepositoryService;
-import org.apache.polygene.valueserialization.orgjson.OrgJsonValueSerializationService;
 
 public class RdfRdbmsSesameStoreAssembler
     implements Assembler
@@ -63,7 +61,6 @@ public class RdfRdbmsSesameStoreAssembler
             .visibleIn( indexingVisibility )
             .instantiateOnStartup();
         module.services( RdfQueryParserFactory.class ).visibleIn( indexingVisibility );
-        module.services( OrgJsonValueSerializationService.class ).taggedWith( ValueSerialization.Formats.JSON );
         module.objects( EntityStateSerializer.class, EntityTypeSerializer.class );
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/e4cca11e/extensions/indexing-rdf/src/main/java/org/apache/polygene/index/rdf/query/RdfQueryParserFactory.java
----------------------------------------------------------------------
diff --git a/extensions/indexing-rdf/src/main/java/org/apache/polygene/index/rdf/query/RdfQueryParserFactory.java b/extensions/indexing-rdf/src/main/java/org/apache/polygene/index/rdf/query/RdfQueryParserFactory.java
index 8f11649..d351649 100644
--- a/extensions/indexing-rdf/src/main/java/org/apache/polygene/index/rdf/query/RdfQueryParserFactory.java
+++ b/extensions/indexing-rdf/src/main/java/org/apache/polygene/index/rdf/query/RdfQueryParserFactory.java
@@ -20,17 +20,15 @@
 
 package org.apache.polygene.index.rdf.query;
 
-import org.openrdf.query.QueryLanguage;
 import org.apache.polygene.api.injection.scope.Service;
 import org.apache.polygene.api.injection.scope.Structure;
 import org.apache.polygene.api.mixin.Mixins;
 import org.apache.polygene.api.service.ServiceComposite;
-import org.apache.polygene.api.service.qualifier.Tagged;
-import org.apache.polygene.api.value.ValueSerialization;
-import org.apache.polygene.api.value.ValueSerializer;
 import org.apache.polygene.index.rdf.UnsupportedLanguageException;
 import org.apache.polygene.index.rdf.query.internal.RdfQueryParserImpl;
 import org.apache.polygene.spi.PolygeneSPI;
+import org.apache.polygene.spi.serialization.JsonSerializer;
+import org.openrdf.query.QueryLanguage;
 
 @Mixins( RdfQueryParserFactory.RdfQueryParserFactoryMixin.class )
 public interface RdfQueryParserFactory
@@ -44,15 +42,14 @@ public interface RdfQueryParserFactory
         @Structure
         private PolygeneSPI spi;
         @Service
-        @Tagged( ValueSerialization.Formats.JSON )
-        private ValueSerializer valueSerializer;
+        private JsonSerializer stateSerializer;
 
         @Override
         public RdfQueryParser newQueryParser( QueryLanguage language )
         {
             if( language.equals( QueryLanguage.SPARQL ) )
             {
-                return new RdfQueryParserImpl( spi, valueSerializer );
+                return new RdfQueryParserImpl( spi, stateSerializer );
             }
             throw new UnsupportedLanguageException( language );
         }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/e4cca11e/extensions/indexing-rdf/src/main/java/org/apache/polygene/index/rdf/query/internal/RdfQueryParserImpl.java
----------------------------------------------------------------------
diff --git a/extensions/indexing-rdf/src/main/java/org/apache/polygene/index/rdf/query/internal/RdfQueryParserImpl.java b/extensions/indexing-rdf/src/main/java/org/apache/polygene/index/rdf/query/internal/RdfQueryParserImpl.java
index d176dd3..c0bec0d 100644
--- a/extensions/indexing-rdf/src/main/java/org/apache/polygene/index/rdf/query/internal/RdfQueryParserImpl.java
+++ b/extensions/indexing-rdf/src/main/java/org/apache/polygene/index/rdf/query/internal/RdfQueryParserImpl.java
@@ -47,15 +47,14 @@ import org.apache.polygene.api.query.grammar.NePredicate;
 import org.apache.polygene.api.query.grammar.Notpredicate;
 import org.apache.polygene.api.query.grammar.OrPredicate;
 import org.apache.polygene.api.query.grammar.OrderBy;
-import org.apache.polygene.api.query.grammar.PropertyFunction;
 import org.apache.polygene.api.query.grammar.PropertyNotNullPredicate;
 import org.apache.polygene.api.query.grammar.PropertyNullPredicate;
 import org.apache.polygene.api.query.grammar.QuerySpecification;
 import org.apache.polygene.api.query.grammar.Variable;
-import org.apache.polygene.api.value.ValueSerializer;
-import org.apache.polygene.api.value.ValueSerializer.Options;
+import org.apache.polygene.api.serialization.Serializer;
 import org.apache.polygene.index.rdf.query.RdfQueryParser;
 import org.apache.polygene.spi.PolygeneSPI;
+import org.apache.polygene.spi.serialization.JsonSerializer;
 import org.slf4j.LoggerFactory;
 
 import static java.lang.String.format;
@@ -72,7 +71,7 @@ public class RdfQueryParserImpl
     private final Namespaces namespaces = new Namespaces();
     private final Triples triples = new Triples( namespaces );
     private final PolygeneSPI spi;
-    private final ValueSerializer valueSerializer;
+    private final JsonSerializer stateSerializer;
     private Map<String, Object> variables;
 
     static
@@ -90,10 +89,10 @@ public class RdfQueryParserImpl
         ) );
     }
 
-    public RdfQueryParserImpl( PolygeneSPI spi, ValueSerializer valueSerializer )
+    public RdfQueryParserImpl( PolygeneSPI spi, JsonSerializer stateSerializer )
     {
         this.spi = spi;
-        this.valueSerializer = valueSerializer;
+        this.stateSerializer = stateSerializer;
     }
 
     @Override
@@ -328,7 +327,8 @@ public class RdfQueryParserImpl
 
     private String createAndEscapeJSONString( Object value )
     {
-        return escapeJSONString( valueSerializer.serialize( new Options().withoutTypeInfo(), value ) );
+        String serialized = stateSerializer.serialize( Serializer.Options.NO_TYPE_INFO, value );
+        return escapeJSONString( serialized );
     }
 
     private String createRegexStringForContaining( String valueVariable, String containedString )
@@ -376,7 +376,7 @@ public class RdfQueryParserImpl
             String jsonStr = "";
             if( item != null )
             {
-                String serialized = valueSerializer.serialize( new Options().withoutTypeInfo(), item );
+                String serialized = stateSerializer.serialize( Serializer.Options.NO_TYPE_INFO, item );
                 if( item instanceof String )
                 {
                     serialized = "\"" + StringEscapeUtils.escapeJava( serialized ) + "\"";
@@ -424,7 +424,7 @@ public class RdfQueryParserImpl
         if( predicate instanceof ComparisonPredicate )
         {
             ComparisonPredicate<?> comparisonPredicate = (ComparisonPredicate<?>) predicate;
-            Triples.Triple triple = triples.addTriple( (PropertyFunction) comparisonPredicate.property(), false );
+            Triples.Triple triple = triples.addTriple( comparisonPredicate.property(), false );
 
             // Don't use FILTER for equals-comparison. Do direct match instead
             if( predicate instanceof EqPredicate && allowInline )

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/e4cca11e/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/ContainsAllTest.java
----------------------------------------------------------------------
diff --git a/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/ContainsAllTest.java b/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/ContainsAllTest.java
index 0db4bd0..3d7fb36 100644
--- a/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/ContainsAllTest.java
+++ b/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/ContainsAllTest.java
@@ -131,12 +131,12 @@ public class ContainsAllTest
 
     private static void populateStrings( ExampleEntity proto, String... strings )
     {
-        proto.strings().set( new HashSet<String>( Arrays.asList( strings ) ) );
+        proto.strings().set( setOf( strings ) );
     }
 
     private static void populateComplexValue( ExampleEntity proto, ValueBuilderFactory vbf, String... valueStrings )
     {
-        Set<ExampleValue> values = new HashSet<ExampleValue>();
+        Set<ExampleValue> values = new HashSet<>();
         for( String value : valueStrings )
         {
             ValueBuilder<ExampleValue2> vBuilder = vbf.newValueBuilder( ExampleValue2.class );
@@ -154,16 +154,9 @@ public class ContainsAllTest
     public void simpleContainsAllQuerySuccessTest()
         throws Exception
     {
-
         ExampleEntity result = this.performContainsAllStringsTest(
-            new HashSet<String>( Arrays.asList(
-                TEST_STRING_1, TEST_STRING_2, TEST_STRING_3
-            )
-            ),
-            new HashSet<String>( Arrays.asList(
-                TEST_STRING_1, TEST_STRING_2
-            )
-            )
+            setOf( TEST_STRING_1, TEST_STRING_2, TEST_STRING_3 ),
+            setOf( TEST_STRING_1, TEST_STRING_2 )
         );
 
         Assert.assertTrue( "The entity must have been found.", result != null );
@@ -174,14 +167,8 @@ public class ContainsAllTest
         throws Exception
     {
         ExampleEntity result = this.performContainsAllStringsTest(
-            new HashSet<String>( Arrays.asList(
-                TEST_STRING_1, TEST_STRING_2, TEST_STRING_3
-            )
-            ),
-            new HashSet<String>( Arrays.asList(
-                TEST_STRING_1, TEST_STRING_2, TEST_STRING_3
-            )
-            )
+            setOf( TEST_STRING_1, TEST_STRING_2, TEST_STRING_3 ),
+            setOf( TEST_STRING_1, TEST_STRING_2, TEST_STRING_3 )
         );
 
         Assert.assertTrue( "The entity must have been found.", result != null );
@@ -192,14 +179,8 @@ public class ContainsAllTest
         throws Exception
     {
         ExampleEntity result = this.performContainsAllStringsTest(
-            new HashSet<String>( Arrays.asList(
-                TEST_STRING_1, TEST_STRING_2, TEST_STRING_3
-            )
-            ),
-            new HashSet<String>( Arrays.asList(
-                TEST_STRING_1, TEST_STRING_2, TEST_STRING_3, TEST_STRING_4
-            )
-            )
+            setOf( TEST_STRING_1, TEST_STRING_2, TEST_STRING_3 ),
+            setOf( TEST_STRING_1, TEST_STRING_2, TEST_STRING_3, TEST_STRING_4 )
         );
 
         Assert.assertTrue( "The entity must not have been found.", result == null );
@@ -210,14 +191,8 @@ public class ContainsAllTest
         throws Exception
     {
         ExampleEntity result = this.performContainsAllStringsTest(
-            new HashSet<String>( Arrays.asList(
-                TEST_STRING_1, TEST_STRING_2, TEST_STRING_3
-            )
-            ),
-            new HashSet<String>( Arrays.asList(
-                TEST_STRING_1, null, TEST_STRING_2
-            )
-            )
+            setOf( TEST_STRING_1, TEST_STRING_2, TEST_STRING_3 ),
+            setOf( TEST_STRING_1, null, TEST_STRING_2 )
         );
 
         Assert.assertTrue( "The entity must have been found.", result != null );
@@ -228,11 +203,8 @@ public class ContainsAllTest
         throws Exception
     {
         ExampleEntity result = this.performContainsAllStringsTest(
-            new HashSet<String>( Arrays.asList(
-                TEST_STRING_1, TEST_STRING_2
-            )
-            ),
-            new HashSet<String>()
+            setOf( TEST_STRING_1, TEST_STRING_2 ),
+            setOf()
         );
 
         Assert.assertTrue( "The entity must have been found.", result != null );
@@ -243,14 +215,8 @@ public class ContainsAllTest
         throws Exception
     {
         ExampleEntity result = this.performContainsAllStringValueTest(
-            new HashSet<String>( Arrays.asList(
-                TEST_STRING_1, TEST_STRING_2
-            )
-            ),
-            new HashSet<String>( Arrays.asList(
-                TEST_STRING_1
-            )
-            )
+            setOf( TEST_STRING_1, TEST_STRING_2 ),
+            setOf( TEST_STRING_1 )
         );
 
         Assert.assertTrue( "The entity must have been found.", result != null );
@@ -261,14 +227,8 @@ public class ContainsAllTest
         throws Exception
     {
         ExampleEntity result = this.performContainsAllStringValueTest(
-            new HashSet<String>( Arrays.asList(
-                TEST_STRING_1, TEST_STRING_2
-            )
-            ),
-            new HashSet<String>( Arrays.asList(
-                TEST_STRING_1, TEST_STRING_2
-            )
-            )
+            setOf( TEST_STRING_1, TEST_STRING_2 ),
+            setOf( TEST_STRING_1, TEST_STRING_2 )
         );
 
         Assert.assertTrue( "The entity must have been found", result != null );
@@ -279,14 +239,8 @@ public class ContainsAllTest
         throws Exception
     {
         ExampleEntity result = this.performContainsAllStringValueTest(
-            new HashSet<String>( Arrays.asList(
-                TEST_STRING_1, TEST_STRING_2
-            )
-            ),
-            new HashSet<String>( Arrays.asList(
-                TEST_STRING_1, TEST_STRING_2, TEST_STRING_3
-            )
-            )
+            setOf( TEST_STRING_1, TEST_STRING_2 ),
+            setOf( TEST_STRING_1, TEST_STRING_2, TEST_STRING_3 )
         );
 
         Assert.assertTrue( "The entity must not have been found.", result == null );
@@ -297,11 +251,8 @@ public class ContainsAllTest
         throws Exception
     {
         ExampleEntity result = this.performContainsAllStringValueTest(
-            new HashSet<String>( Arrays.asList(
-                TEST_STRING_1, TEST_STRING_2
-            )
-            ),
-            new HashSet<String>()
+            setOf( TEST_STRING_1, TEST_STRING_2 ),
+            setOf()
         );
 
         Assert.assertTrue( "The entity must have been found.", result != null );
@@ -312,8 +263,8 @@ public class ContainsAllTest
         QueryBuilder<ExampleEntity> builder = this.queryBuilderFactory.newQueryBuilder( ExampleEntity.class );
 
         builder = builder.where( QueryExpressions.containsAll(
-                QueryExpressions.templateFor( ExampleEntity.class ).strings(),
-                Arrays.asList( strings ) ) );
+            QueryExpressions.templateFor( ExampleEntity.class ).strings(),
+            Arrays.asList( strings ) ) );
         return this.unitOfWorkFactory.currentUnitOfWork().newQuery( builder ).find();
     }
 
@@ -337,9 +288,9 @@ public class ContainsAllTest
     {
         QueryBuilder<ExampleEntity> builder = this.queryBuilderFactory.newQueryBuilder( ExampleEntity.class );
         builder = builder.where( QueryExpressions.containsAll(
-                QueryExpressions.templateFor( ExampleEntity.class ).complexValue(),
-                valuez
-        )
+            QueryExpressions.templateFor( ExampleEntity.class ).complexValue(),
+            valuez
+                                 )
         );
 
         return this.unitOfWorkFactory.currentUnitOfWork().newQuery( builder );
@@ -349,14 +300,14 @@ public class ContainsAllTest
         throws Exception
     {
         UnitOfWork creatingUOW = this.unitOfWorkFactory.newUnitOfWork();
-        String[] entityStringsArray = new String[entityStrings.size()];
+        String[] entityStringsArray = new String[ entityStrings.size() ];
         createEntityWithStrings( creatingUOW, this.valueBuilderFactory, entityStrings.toArray( entityStringsArray ) );
         creatingUOW.complete();
 
         UnitOfWork queryingUOW = this.unitOfWorkFactory.newUnitOfWork();
         try
         {
-            String[] queryableStringsArray = new String[queryableStrings.size()];
+            String[] queryableStringsArray = new String[ queryableStrings.size() ];
             ExampleEntity entity = this.findEntity( queryableStrings.toArray( queryableStringsArray ) );
             return entity;
         }
@@ -370,15 +321,17 @@ public class ContainsAllTest
         throws Exception
     {
         UnitOfWork creatingUOW = this.unitOfWorkFactory.newUnitOfWork();
-        String[] entityStringsArray = new String[entityStrings.size()];
-        createEntityWithComplexValues( creatingUOW, this.valueBuilderFactory, entityStrings.toArray( entityStringsArray ) );
+        String[] entityStringsArray = new String[ entityStrings.size() ];
+        createEntityWithComplexValues( creatingUOW, this.valueBuilderFactory,
+                                       entityStrings.toArray( entityStringsArray ) );
         creatingUOW.complete();
 
         UnitOfWork queryingUOW = this.unitOfWorkFactory.newUnitOfWork();
         try
         {
-            String[] queryableStringsArray = new String[queryableStrings.size()];
-            ExampleEntity entity = this.findEntityBasedOnValueStrings( queryableStrings.toArray( queryableStringsArray ) );
+            String[] queryableStringsArray = new String[ queryableStrings.size() ];
+            ExampleEntity entity = this.findEntityBasedOnValueStrings(
+                queryableStrings.toArray( queryableStringsArray ) );
             return entity;
         }
         finally
@@ -386,4 +339,9 @@ public class ContainsAllTest
             queryingUOW.discard();
         }
     }
+
+    static <T> Set<T> setOf( T... elements )
+    {
+        return new HashSet<T>( Arrays.asList( elements ) );
+    }
 }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/e4cca11e/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/ContainsTest.java
----------------------------------------------------------------------
diff --git a/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/ContainsTest.java b/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/ContainsTest.java
index 7e76e3d..db4982d 100644
--- a/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/ContainsTest.java
+++ b/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/ContainsTest.java
@@ -20,8 +20,6 @@
 package org.apache.polygene.index.rdf;
 
 import java.io.File;
-import java.util.Arrays;
-import java.util.HashSet;
 import java.util.Set;
 import org.apache.polygene.api.common.Visibility;
 import org.apache.polygene.api.query.Query;
@@ -45,6 +43,12 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 
+import static org.apache.polygene.index.rdf.ContainsAllTest.TEST_STRING_1;
+import static org.apache.polygene.index.rdf.ContainsAllTest.TEST_STRING_2;
+import static org.apache.polygene.index.rdf.ContainsAllTest.TEST_STRING_3;
+import static org.apache.polygene.index.rdf.ContainsAllTest.TEST_STRING_4;
+import static org.apache.polygene.index.rdf.ContainsAllTest.setOf;
+
 public class ContainsTest extends AbstractPolygeneTest
 {
     @Rule
@@ -76,10 +80,8 @@ public class ContainsTest extends AbstractPolygeneTest
     public void simpleContainsSuccessTest() throws Exception
     {
         ExampleEntity result = this.performContainsStringTest(
-            new HashSet<>( Arrays.asList(
-                ContainsAllTest.TEST_STRING_1, ContainsAllTest.TEST_STRING_2, ContainsAllTest.TEST_STRING_3
-            ) ),
-            ContainsAllTest.TEST_STRING_3
+            setOf( TEST_STRING_1, TEST_STRING_2, TEST_STRING_3 ),
+            TEST_STRING_3
         );
 
         Assert.assertTrue( "The entity must have been found", result != null );
@@ -89,22 +91,18 @@ public class ContainsTest extends AbstractPolygeneTest
     public void simpleContainsSuccessFailTest() throws Exception
     {
         ExampleEntity result = this.performContainsStringTest(
-            new HashSet<>( Arrays.asList(
-                ContainsAllTest.TEST_STRING_1, ContainsAllTest.TEST_STRING_2, ContainsAllTest.TEST_STRING_3
-            ) ),
-            ContainsAllTest.TEST_STRING_4
+            setOf( TEST_STRING_1, TEST_STRING_2, TEST_STRING_3 ),
+            TEST_STRING_4
         );
 
         Assert.assertTrue( "The entity must not have been found", result == null );
     }
 
     @Test( expected = IllegalArgumentException.class )
-    public void simplecontainsNullTest() throws Exception
+    public void simpleContainsNullTest() throws Exception
     {
         this.performContainsStringTest(
-            new HashSet<>( Arrays.asList(
-                ContainsAllTest.TEST_STRING_1, ContainsAllTest.TEST_STRING_2, ContainsAllTest.TEST_STRING_3
-            ) ),
+            setOf( TEST_STRING_1, TEST_STRING_2, TEST_STRING_3 ),
             null
         );
     }
@@ -113,10 +111,8 @@ public class ContainsTest extends AbstractPolygeneTest
     public void simpleContainsStringValueSuccessTest() throws Exception
     {
         ExampleEntity result = this.performContainsStringValueTest(
-            new HashSet<>( Arrays.asList(
-                ContainsAllTest.TEST_STRING_1, ContainsAllTest.TEST_STRING_2, ContainsAllTest.TEST_STRING_3
-            ) ),
-            ContainsAllTest.TEST_STRING_3
+            setOf( TEST_STRING_1, TEST_STRING_2, TEST_STRING_3 ),
+            TEST_STRING_3
         );
 
         Assert.assertTrue( "The entity must have been found", result != null );
@@ -126,10 +122,8 @@ public class ContainsTest extends AbstractPolygeneTest
     public void simpleContainsStringValueFailTest() throws Exception
     {
         ExampleEntity result = this.performContainsStringTest(
-            new HashSet<>( Arrays.asList(
-                ContainsAllTest.TEST_STRING_1, ContainsAllTest.TEST_STRING_2, ContainsAllTest.TEST_STRING_3
-            ) ),
-            ContainsAllTest.TEST_STRING_4
+            setOf( TEST_STRING_1, TEST_STRING_2, TEST_STRING_3 ),
+            TEST_STRING_4
         );
 
         Assert.assertTrue( "The entity must not have been found", result == null );
@@ -139,11 +133,8 @@ public class ContainsTest extends AbstractPolygeneTest
     {
         QueryBuilder<ExampleEntity> builder = this.queryBuilderFactory.newQueryBuilder( ExampleEntity.class );
 
-        builder = builder.where( QueryExpressions.contains(
-            QueryExpressions.templateFor( ExampleEntity.class ).strings(),
-            string
-                                 )
-        );
+        builder = builder.where(
+            QueryExpressions.contains( QueryExpressions.templateFor( ExampleEntity.class ).strings(), string ) );
         return this.unitOfWorkFactory.currentUnitOfWork().newQuery( builder ).find();
     }
 
@@ -161,11 +152,8 @@ public class ContainsTest extends AbstractPolygeneTest
     private Query<ExampleEntity> createComplexQuery( ExampleValue value )
     {
         QueryBuilder<ExampleEntity> builder = this.queryBuilderFactory.newQueryBuilder( ExampleEntity.class );
-        builder = builder.where( QueryExpressions.contains(
-            QueryExpressions.templateFor( ExampleEntity.class ).complexValue(),
-            value
-                                 )
-        );
+        builder = builder.where(
+            QueryExpressions.contains( QueryExpressions.templateFor( ExampleEntity.class ).complexValue(), value ) );
 
         return this.unitOfWorkFactory.currentUnitOfWork().newQuery( builder );
     }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/e4cca11e/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/RdfComplexQueryTest.java
----------------------------------------------------------------------
diff --git a/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/RdfComplexQueryTest.java b/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/RdfComplexQueryTest.java
index 6102e8b..31c2d3c 100644
--- a/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/RdfComplexQueryTest.java
+++ b/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/RdfComplexQueryTest.java
@@ -19,15 +19,13 @@
  */
 package org.apache.polygene.index.rdf;
 
-import org.junit.Ignore;
-import org.apache.polygene.api.value.ValueSerialization;
 import org.apache.polygene.bootstrap.AssemblyException;
 import org.apache.polygene.bootstrap.ModuleAssembly;
 import org.apache.polygene.library.rdf.entity.EntityStateSerializer;
 import org.apache.polygene.library.rdf.entity.EntityTypeSerializer;
 import org.apache.polygene.library.rdf.repository.MemoryRepositoryService;
 import org.apache.polygene.test.indexing.AbstractComplexQueryTest;
-import org.apache.polygene.valueserialization.orgjson.OrgJsonValueSerializationService;
+import org.junit.Ignore;
 
 @Ignore( "RDF Index/Query do not support Complex Queries, ie. queries by 'example values'" )
 public class RdfComplexQueryTest
@@ -40,7 +38,6 @@ public class RdfComplexQueryTest
     {
         super.assemble( module );
         module.services( RdfIndexingEngineService.class ).instantiateOnStartup();
-        module.services( OrgJsonValueSerializationService.class ).taggedWith( ValueSerialization.Formats.JSON );
         module.objects( EntityStateSerializer.class, EntityTypeSerializer.class );
         module.services( MemoryRepositoryService.class ).identifiedBy( "rdf-indexing" ).instantiateOnStartup();
     }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/e4cca11e/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/RdfEntityFinderTest.java
----------------------------------------------------------------------
diff --git a/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/RdfEntityFinderTest.java b/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/RdfEntityFinderTest.java
index 626d184..86723ce 100644
--- a/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/RdfEntityFinderTest.java
+++ b/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/RdfEntityFinderTest.java
@@ -19,14 +19,12 @@
  */
 package org.apache.polygene.index.rdf;
 
-import org.apache.polygene.api.value.ValueSerialization;
 import org.apache.polygene.bootstrap.AssemblyException;
 import org.apache.polygene.bootstrap.ModuleAssembly;
 import org.apache.polygene.library.rdf.entity.EntityStateSerializer;
 import org.apache.polygene.library.rdf.entity.EntityTypeSerializer;
 import org.apache.polygene.library.rdf.repository.MemoryRepositoryService;
 import org.apache.polygene.test.indexing.AbstractEntityFinderTest;
-import org.apache.polygene.valueserialization.orgjson.OrgJsonValueSerializationService;
 
 public class RdfEntityFinderTest extends AbstractEntityFinderTest
 {
@@ -37,7 +35,6 @@ public class RdfEntityFinderTest extends AbstractEntityFinderTest
         super.assemble( module );
         module.objects( EntityStateSerializer.class, EntityTypeSerializer.class );
         module.services( RdfIndexingEngineService.class ).instantiateOnStartup();
-        module.services( OrgJsonValueSerializationService.class ).taggedWith( ValueSerialization.Formats.JSON );
         module.services( MemoryRepositoryService.class ).identifiedBy( "rdf-indexing" ).instantiateOnStartup();
         // module.services( NativeRdfRepositoryService.class ).identifiedBy( "rdf-indexing" );
         // module.addComposites( NativeRdfConfiguration.class );

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/e4cca11e/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/qi66/Qi66IssueTest.java
----------------------------------------------------------------------
diff --git a/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/qi66/Qi66IssueTest.java b/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/qi66/Qi66IssueTest.java
index 372e9d8..d5a385c 100644
--- a/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/qi66/Qi66IssueTest.java
+++ b/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/qi66/Qi66IssueTest.java
@@ -19,12 +19,10 @@
  */
 package org.apache.polygene.index.rdf.qi66;
 
-import org.apache.polygene.api.identity.Identity;
-import org.junit.Test;
 import org.apache.polygene.api.entity.EntityBuilder;
+import org.apache.polygene.api.identity.Identity;
 import org.apache.polygene.api.unitofwork.UnitOfWork;
 import org.apache.polygene.api.unitofwork.UnitOfWorkCompletionException;
-import org.apache.polygene.api.value.ValueSerialization;
 import org.apache.polygene.bootstrap.AssemblyException;
 import org.apache.polygene.bootstrap.ModuleAssembly;
 import org.apache.polygene.index.rdf.query.RdfQueryParserFactory;
@@ -34,7 +32,7 @@ import org.apache.polygene.library.rdf.entity.EntityTypeSerializer;
 import org.apache.polygene.library.rdf.repository.MemoryRepositoryService;
 import org.apache.polygene.test.AbstractPolygeneTest;
 import org.apache.polygene.test.EntityTestAssembler;
-import org.apache.polygene.valueserialization.orgjson.OrgJsonValueSerializationService;
+import org.junit.Test;
 
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
@@ -97,7 +95,6 @@ public class Qi66IssueTest
         module.services( RdfQueryService.class,
                          RdfQueryParserFactory.class,
                          MemoryRepositoryService.class );
-        module.services( OrgJsonValueSerializationService.class ).taggedWith( ValueSerialization.Formats.JSON );
         module.objects( EntityStateSerializer.class, EntityTypeSerializer.class );
     }
 }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/e4cca11e/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/qi95/Qi95IssueTest.java
----------------------------------------------------------------------
diff --git a/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/qi95/Qi95IssueTest.java b/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/qi95/Qi95IssueTest.java
index 1d57ef0..2694153 100644
--- a/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/qi95/Qi95IssueTest.java
+++ b/extensions/indexing-rdf/src/test/java/org/apache/polygene/index/rdf/qi95/Qi95IssueTest.java
@@ -23,9 +23,6 @@ import java.io.File;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import org.apache.polygene.bootstrap.unitofwork.DefaultUnitOfWorkAssembler;
-import org.junit.Rule;
-import org.junit.Test;
 import org.apache.polygene.api.common.Visibility;
 import org.apache.polygene.api.entity.EntityBuilder;
 import org.apache.polygene.api.entity.EntityComposite;
@@ -36,14 +33,22 @@ import org.apache.polygene.api.structure.Application;
 import org.apache.polygene.api.structure.Module;
 import org.apache.polygene.api.unitofwork.UnitOfWork;
 import org.apache.polygene.api.unitofwork.UnitOfWorkFactory;
-import org.apache.polygene.bootstrap.*;
+import org.apache.polygene.bootstrap.ApplicationAssembler;
+import org.apache.polygene.bootstrap.ApplicationAssembly;
+import org.apache.polygene.bootstrap.ApplicationAssemblyFactory;
+import org.apache.polygene.bootstrap.Assembler;
+import org.apache.polygene.bootstrap.AssemblyException;
+import org.apache.polygene.bootstrap.Energy4Java;
+import org.apache.polygene.bootstrap.LayerAssembly;
+import org.apache.polygene.bootstrap.ModuleAssembly;
 import org.apache.polygene.entitystore.jdbm.JdbmConfiguration;
 import org.apache.polygene.entitystore.jdbm.assembly.JdbmEntityStoreAssembler;
 import org.apache.polygene.index.rdf.assembly.RdfMemoryStoreAssembler;
 import org.apache.polygene.index.rdf.assembly.RdfNativeSesameStoreAssembler;
 import org.apache.polygene.library.rdf.repository.NativeConfiguration;
 import org.apache.polygene.test.EntityTestAssembler;
-import org.apache.polygene.valueserialization.orgjson.OrgJsonValueSerializationAssembler;
+import org.junit.Rule;
+import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 
 import static org.junit.Assert.assertTrue;
@@ -280,7 +285,6 @@ public class Qi95IssueTest
                     throws AssemblyException
                 {
                     module.entities( ItemTypeEntity.class );
-                    new DefaultUnitOfWorkAssembler().assemble( module );
                 }
             } );
             return domainLayer;
@@ -296,7 +300,6 @@ public class Qi95IssueTest
                 throws AssemblyException
             {
                 new EntityTestAssembler().assemble( module );
-                new DefaultUnitOfWorkAssembler().assemble( module );
 
                 module.entities( NativeConfiguration.class ).visibleIn( Visibility.application );
                 module.forMixin( NativeConfiguration.class )
@@ -322,9 +325,7 @@ public class Qi95IssueTest
             public void assemble( ModuleAssembly module )
                 throws AssemblyException
             {
-                new OrgJsonValueSerializationAssembler().assemble( module );
                 new JdbmEntityStoreAssembler().visibleIn( Visibility.application ).assemble( module );
-                new DefaultUnitOfWorkAssembler().assemble( module );
             }
         };
     }
@@ -334,7 +335,6 @@ public class Qi95IssueTest
     {
         ModuleAssembly moduleAssembly = layerAssembly.module( name );
         assembler.assemble( moduleAssembly );
-        new DefaultUnitOfWorkAssembler().assemble( moduleAssembly );
         return moduleAssembly;
     }
 

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/e4cca11e/extensions/indexing-solr/src/main/java/org/apache/polygene/index/solr/SolrAssembler.java
----------------------------------------------------------------------
diff --git a/extensions/indexing-solr/src/main/java/org/apache/polygene/index/solr/SolrAssembler.java b/extensions/indexing-solr/src/main/java/org/apache/polygene/index/solr/SolrAssembler.java
index 84d2a79..cd0c5a9 100644
--- a/extensions/indexing-solr/src/main/java/org/apache/polygene/index/solr/SolrAssembler.java
+++ b/extensions/indexing-solr/src/main/java/org/apache/polygene/index/solr/SolrAssembler.java
@@ -21,12 +21,10 @@
 package org.apache.polygene.index.solr;
 
 import org.apache.polygene.api.common.Visibility;
-import org.apache.polygene.api.value.ValueSerialization;
 import org.apache.polygene.bootstrap.Assembler;
 import org.apache.polygene.bootstrap.AssemblyException;
 import org.apache.polygene.bootstrap.ModuleAssembly;
 import org.apache.polygene.library.rdf.entity.EntityStateSerializer;
-import org.apache.polygene.valueserialization.orgjson.OrgJsonValueSerializationService;
 
 /**
  * JAVADOC
@@ -43,7 +41,6 @@ public class SolrAssembler
             taggedWith( "solr", "search" ).
             identifiedBy( "solrquery" ).
             visibleIn( Visibility.application );
-      module.services( OrgJsonValueSerializationService.class ).taggedWith( ValueSerialization.Formats.JSON );
       module.objects( EntityStateSerializer.class );
    }
 }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/e4cca11e/extensions/indexing-solr/src/main/java/org/apache/polygene/index/solr/internal/SolrEntityIndexerMixin.java
----------------------------------------------------------------------
diff --git a/extensions/indexing-solr/src/main/java/org/apache/polygene/index/solr/internal/SolrEntityIndexerMixin.java b/extensions/indexing-solr/src/main/java/org/apache/polygene/index/solr/internal/SolrEntityIndexerMixin.java
index 1301718..14335d0 100644
--- a/extensions/indexing-solr/src/main/java/org/apache/polygene/index/solr/internal/SolrEntityIndexerMixin.java
+++ b/extensions/indexing-solr/src/main/java/org/apache/polygene/index/solr/internal/SolrEntityIndexerMixin.java
@@ -21,15 +21,19 @@
 package org.apache.polygene.index.solr.internal;
 
 import java.io.IOException;
+import java.io.StringReader;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import org.apache.solr.client.solrj.SolrServer;
-import org.apache.solr.client.solrj.SolrServerException;
-import org.apache.solr.common.SolrInputDocument;
-import org.apache.solr.core.SolrCore;
-import org.apache.solr.schema.SchemaField;
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonNumber;
+import javax.json.JsonObject;
+import javax.json.JsonReader;
+import javax.json.JsonString;
+import javax.json.JsonValue;
+import javax.json.stream.JsonParser;
 import org.apache.polygene.api.injection.scope.Service;
 import org.apache.polygene.api.injection.scope.Uses;
 import org.apache.polygene.index.solr.EmbeddedSolrService;
@@ -37,9 +41,11 @@ import org.apache.polygene.index.solr.SolrQueryService;
 import org.apache.polygene.library.rdf.entity.EntityStateSerializer;
 import org.apache.polygene.spi.entity.EntityState;
 import org.apache.polygene.spi.entity.EntityStatus;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
+import org.apache.solr.client.solrj.SolrServer;
+import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.common.SolrInputDocument;
+import org.apache.solr.core.SolrCore;
+import org.apache.solr.schema.SchemaField;
 import org.openrdf.model.BNode;
 import org.openrdf.model.Graph;
 import org.openrdf.model.Literal;
@@ -151,7 +157,7 @@ public abstract class SolrEntityIndexerMixin
     }
 
     private SolrInputDocument indexEntityState( final EntityState entityState )
-        throws IOException, SolrServerException, JSONException
+        throws IOException, SolrServerException
     {
         Graph graph = new GraphImpl();
         stateSerializer.serialize( entityState, false, graph );
@@ -171,15 +177,24 @@ public abstract class SolrEntityIndexerMixin
                     String value = statement.getObject().stringValue();
                     if( field.getType().getTypeName().equals( "json" ) )
                     {
-                        if( value.charAt( 0 ) == '[' )
-                        {
-                            JSONArray array = new JSONArray( value );
-                            indexJson( input, array );
-                        }
-                        else if( value.charAt( 0 ) == '{' )
+                        try( JsonParser parser = Json.createParser( new StringReader( value ) ) )
                         {
-                            JSONObject object = new JSONObject( value );
-                            indexJson( input, object );
+                            JsonParser.Event event = parser.next();
+                            switch( event )
+                            {
+                                case START_ARRAY:
+                                    try( JsonReader reader = Json.createReader( new StringReader( value ) ) )
+                                    {
+                                        indexJson( input, reader.readArray() );
+                                    }
+                                    break;
+                                case START_OBJECT:
+                                    try( JsonReader reader = Json.createReader( new StringReader( value ) ) )
+                                    {
+                                        indexJson( input, reader.readObject() );
+                                    }
+                                    break;
+                            }
                         }
                     }
                     else
@@ -215,34 +230,54 @@ public abstract class SolrEntityIndexerMixin
     }
 
     private void indexJson( SolrInputDocument input, Object object )
-        throws JSONException
     {
-        if( object instanceof JSONArray )
+        if( object instanceof JsonArray )
         {
-            JSONArray array = (JSONArray) object;
-            for( int i = 0; i < array.length(); i++ )
+            JsonArray array = (JsonArray) object;
+            for( int i = 0; i < array.size(); i++ )
             {
                 indexJson( input, array.get( i ) );
             }
         }
         else
         {
-            JSONObject jsonObject = (JSONObject) object;
-            Iterator keys = jsonObject.keys();
-            while( keys.hasNext() )
+            JsonObject jsonObject = (JsonObject) object;
+            for( String name : jsonObject.keySet() )
             {
-                Object name = keys.next();
-                Object value = jsonObject.get( name.toString() );
-                if( value instanceof JSONObject || value instanceof JSONArray )
+                JsonValue jsonValue = jsonObject.get( name );
+                if( jsonValue.getValueType() == JsonValue.ValueType.OBJECT
+                    || jsonValue.getValueType() == JsonValue.ValueType.ARRAY )
                 {
-                    indexJson( input, value );
+                    indexJson( input, jsonValue );
                 }
                 else
                 {
-                    SchemaField field = indexedFields.get( name.toString() );
+                    SchemaField field = indexedFields.get( name );
                     if( field != null )
                     {
-                        input.addField( name.toString(), jsonObject.get( name.toString() ) );
+                        Object value;
+                        switch( jsonValue.getValueType() )
+                        {
+                            case NULL:
+                                value = null;
+                                break;
+                            case STRING:
+                                value = ( (JsonString) jsonValue ).getString();
+                                break;
+                            case NUMBER:
+                                JsonNumber jsonNumber = (JsonNumber) jsonValue;
+                                value = jsonNumber.isIntegral() ? jsonNumber.longValue() : jsonNumber.doubleValue();
+                                break;
+                            case TRUE:
+                                value = Boolean.TRUE;
+                                break;
+                            case FALSE:
+                                value = Boolean.FALSE;
+                                break;
+                            default:
+                                value = jsonValue.toString();
+                        }
+                        input.addField( name, value );
                     }
                 }
             }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/e4cca11e/extensions/indexing-sql/src/main/java/org/apache/polygene/index/sql/support/skeletons/SQLCompatEntityStateWrapper.java
----------------------------------------------------------------------
diff --git a/extensions/indexing-sql/src/main/java/org/apache/polygene/index/sql/support/skeletons/SQLCompatEntityStateWrapper.java b/extensions/indexing-sql/src/main/java/org/apache/polygene/index/sql/support/skeletons/SQLCompatEntityStateWrapper.java
index b3c7621..c15ea5b 100644
--- a/extensions/indexing-sql/src/main/java/org/apache/polygene/index/sql/support/skeletons/SQLCompatEntityStateWrapper.java
+++ b/extensions/indexing-sql/src/main/java/org/apache/polygene/index/sql/support/skeletons/SQLCompatEntityStateWrapper.java
@@ -81,6 +81,7 @@ class SQLCompatEntityStateWrapper
                    || Character.class.isAssignableFrom( primaryType )
                    || Enum.class.isAssignableFrom( primaryType )
                    || String.class.isAssignableFrom( primaryType )
+                   // TODO javax.time support in indexing-sql
                    // || Date.class.isAssignableFrom( primaryType )
                    // || DateTime.class.isAssignableFrom( primaryType )
                    // || LocalDateTime.class.isAssignableFrom( primaryType )

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/e4cca11e/extensions/migration/src/main/java/org/apache/polygene/migration/MigrationService.java
----------------------------------------------------------------------
diff --git a/extensions/migration/src/main/java/org/apache/polygene/migration/MigrationService.java b/extensions/migration/src/main/java/org/apache/polygene/migration/MigrationService.java
index 9f700d7..d7c1705 100644
--- a/extensions/migration/src/main/java/org/apache/polygene/migration/MigrationService.java
+++ b/extensions/migration/src/main/java/org/apache/polygene/migration/MigrationService.java
@@ -22,9 +22,12 @@ package org.apache.polygene.migration;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
+import javax.json.Json;
+import javax.json.JsonException;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+import javax.json.JsonString;
+import javax.json.JsonValue;
 import org.apache.polygene.api.activation.ActivatorAdapter;
 import org.apache.polygene.api.activation.Activators;
 import org.apache.polygene.api.configuration.Configuration;
@@ -39,14 +42,18 @@ import org.apache.polygene.api.structure.Application;
 import org.apache.polygene.api.unitofwork.UnitOfWorkFactory;
 import org.apache.polygene.migration.assembly.EntityMigrationRule;
 import org.apache.polygene.migration.assembly.MigrationBuilder;
+import org.apache.polygene.migration.assembly.MigrationContext;
 import org.apache.polygene.migration.assembly.MigrationRule;
 import org.apache.polygene.spi.entitystore.EntityStore;
 import org.apache.polygene.spi.entitystore.helpers.JSONKeys;
 import org.apache.polygene.spi.entitystore.helpers.Migration;
 import org.apache.polygene.spi.entitystore.helpers.StateStore;
+import org.apache.polygene.spi.serialization.JsonSerialization;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static java.util.Arrays.asList;
+
 /**
  * Migration service. This is used by MapEntityStore EntityStore implementations to
  * migrate JSON state for Entities. To use it register the service so that the EntityStore
@@ -63,24 +70,21 @@ import org.slf4j.LoggerFactory;
 public interface MigrationService
     extends Migration
 {
-
     void initialize()
         throws Exception;
 
     class Activator
         extends ActivatorAdapter<ServiceReference<MigrationService>>
     {
-
         @Override
         public void afterActivation( ServiceReference<MigrationService> activated )
             throws Exception
         {
             activated.get().initialize();
         }
-
     }
 
-    public class MigrationMixin
+    class MigrationMixin
         implements MigrationService, Migrator
     {
         @Structure
@@ -96,6 +100,8 @@ public interface MigrationService
         StateStore store;
         @Service
         EntityStore entityStore;
+        @Service
+        JsonSerialization serialization;
         @Structure
         UnitOfWorkFactory uowf;
 
@@ -109,38 +115,61 @@ public interface MigrationService
         Iterable<MigrationEvents> migrationEvents;
 
         @Override
-        public boolean migrate( JSONObject state, String toVersion, StateStore stateStore )
-            throws JSONException
+        public JsonObject migrate( final JsonObject state, String toVersion, StateStore stateStore )
+            throws JsonException
         {
             // Get current version
-            String fromVersion = state.optString( JSONKeys.APPLICATION_VERSION, "0.0" );
+            String fromVersion = state.getString( JSONKeys.APPLICATION_VERSION, "0.0" );
 
-            Iterable<EntityMigrationRule> matchedRules = builder.entityMigrationRules().rulesBetweenVersions( fromVersion, toVersion );
+            Iterable<EntityMigrationRule> matchedRules = builder.entityMigrationRules()
+                                                                .rulesBetweenVersions( fromVersion, toVersion );
 
+            JsonObject migratedState = state;
             boolean changed = false;
+            List<String> failures = new ArrayList<>();
             if( matchedRules != null )
             {
                 for( EntityMigrationRule matchedRule : matchedRules )
                 {
-                    boolean ruleExecuted = matchedRule.upgrade( state, stateStore, migrator );
+                    MigrationContext context = new MigrationContext();
+
+                    migratedState = matchedRule.upgrade( context, migratedState, stateStore, migrator );
 
-                    if( ruleExecuted && log.isDebugEnabled() )
+                    if( context.isSuccess() && context.hasChanged() && log.isDebugEnabled() )
                     {
                         log.debug( matchedRule.toString() );
                     }
 
-                    changed = ruleExecuted || changed;
+                    failures.addAll( context.failures() );
+                    changed = context.hasChanged() || changed;
                 }
             }
 
-            state.put( JSONKeys.APPLICATION_VERSION, toVersion );
+            JsonObjectBuilder appVersionBuilder = Json.createObjectBuilder();
+            for( Map.Entry<String, JsonValue> entry : migratedState.entrySet() )
+            {
+                appVersionBuilder.add( entry.getKey(), entry.getValue() );
+            }
+            appVersionBuilder.add( JSONKeys.APPLICATION_VERSION, toVersion );
+            migratedState = appVersionBuilder.build();
+
+            if( failures.size() > 0 )
+            {
+                log.warn( "Migration of {} from {} to {} aborted, failed operation(s):\n{}",
+                          state.getString( JSONKeys.IDENTITY ), fromVersion, toVersion,
+                          String.join( "\n\t", failures ) );
+                return state;
+            }
 
             if( changed )
             {
-                log.info( "Migrated " + state.getString( JSONKeys.IDENTITY ) + " from " + fromVersion + " to " + toVersion );
+                log.info( "Migrated {} from {} to {}",
+                          migratedState.getString( JSONKeys.IDENTITY ), fromVersion, toVersion );
+                return migratedState;
             }
 
-            return changed;
+            // Nothing done
+            return state;
         }
 
         @Override
@@ -191,304 +220,571 @@ public interface MigrationService
 
         // Migrator implementation
         @Override
-        public boolean addProperty( JSONObject state, String name, Object defaultValue )
-            throws JSONException
+        public JsonObject addProperty( MigrationContext context, JsonObject state, String name, Object defaultValue )
+            throws JsonException
         {
-            JSONObject properties = state.getJSONObject( JSONKeys.PROPERTIES );
-            if( !properties.has( name ) )
+            JsonObject properties = state.getJsonObject( JSONKeys.PROPERTIES );
+            if( !properties.containsKey( name ) )
             {
-                if( defaultValue == null )
+                JsonValue value = serialization.toJson( defaultValue );
+                JsonObjectBuilder builder = Json.createObjectBuilder();
+                for( Map.Entry<String, JsonValue> entry : state.entrySet() )
                 {
-                    properties.put( name, JSONObject.NULL );
+                    String key = entry.getKey();
+                    if( !JSONKeys.PROPERTIES.equals( key ) )
+                    {
+                        builder.add( key, entry.getValue() );
+                    }
                 }
-                else
+                JsonObjectBuilder propBuilder = Json.createObjectBuilder();
+                for( Map.Entry<String, JsonValue> entry : properties.entrySet() )
                 {
-                    properties.put( name, defaultValue );
+                    propBuilder.add( entry.getKey(), entry.getValue() );
                 }
+                propBuilder.add( name, value );
+                builder.add( JSONKeys.PROPERTIES, propBuilder.build() );
+                context.markAsChanged();
 
                 for( MigrationEvents migrationEvent : migrationEvents )
                 {
                     migrationEvent.propertyAdded( state.getString( JSONKeys.IDENTITY ), name, defaultValue );
                 }
 
-                return true;
+                return builder.build();
             }
             else
             {
-                return false;
+                context.addFailure( "Add property " + name + ", default:" + defaultValue );
+                return state;
             }
         }
 
         @Override
-        public boolean removeProperty( JSONObject state, String name )
-            throws JSONException
+        public JsonObject removeProperty( MigrationContext context, JsonObject state, String name )
+            throws JsonException
         {
-            JSONObject properties = state.getJSONObject( JSONKeys.PROPERTIES );
-            if( properties.has( name ) )
+            JsonObject properties = state.getJsonObject( JSONKeys.PROPERTIES );
+            if( properties.containsKey( name ) )
             {
-                properties.remove( name );
-                for( MigrationEvents migrationEvent : migrationEvents )
+                JsonObjectBuilder builder = Json.createObjectBuilder();
+                for( Map.Entry<String, JsonValue> entry : state.entrySet() )
                 {
-                    migrationEvent.propertyRemoved( state.getString( JSONKeys.IDENTITY ), name );
+                    String key = entry.getKey();
+                    if( !JSONKeys.PROPERTIES.equals( key ) )
+                    {
+                        builder.add( key, entry.getValue() );
+                    }
+                }
+                JsonObjectBuilder propBuilder = Json.createObjectBuilder();
+                for( Map.Entry<String, JsonValue> entry : properties.entrySet() )
+                {
+                    String key = entry.getKey();
+                    if( !name.equals( key ) )
+                    {
+                        propBuilder.add( key, entry.getValue() );
+                    }
+                    else
+                    {
+                        context.markAsChanged();
+                    }
                 }
+                builder.add( JSONKeys.PROPERTIES, propBuilder.build() );
 
-                return true;
+                if( context.hasChanged() )
+                {
+                    for( MigrationEvents migrationEvent : migrationEvents )
+                    {
+                        migrationEvent.propertyRemoved( state.getString( JSONKeys.IDENTITY ), name );
+                    }
+                }
+
+                return builder.build();
             }
             else
             {
-                return false;
+                context.addFailure( "Remove property " + name );
+                return state;
             }
         }
 
         @Override
-        public boolean renameProperty( JSONObject state, String from, String to )
-            throws JSONException
+        public JsonObject renameProperty( MigrationContext context, JsonObject state, String from, String to )
+            throws JsonException
         {
-            JSONObject properties = state.getJSONObject( JSONKeys.PROPERTIES );
-            if( properties.has( from ) )
+            JsonObject properties = state.getJsonObject( JSONKeys.PROPERTIES );
+            if( properties.containsKey( from ) )
             {
-                Object value = properties.remove( from );
-                properties.put( to, value );
+                JsonObjectBuilder builder = Json.createObjectBuilder();
+                for( Map.Entry<String, JsonValue> entry : state.entrySet() )
+                {
+                    String key = entry.getKey();
+                    if( !JSONKeys.PROPERTIES.equals( key ) )
+                    {
+                        builder.add( key, entry.getValue() );
+                    }
+                }
+                JsonObjectBuilder propBuilder = Json.createObjectBuilder();
+                for( Map.Entry<String, JsonValue> entry : properties.entrySet() )
+                {
+                    String key = entry.getKey();
+                    if( from.equals( key ) )
+                    {
+                        propBuilder.add( to, entry.getValue() );
+                        context.markAsChanged();
+                    }
+                    else
+                    {
+                        propBuilder.add( key, entry.getValue() );
+                    }
+                }
+                builder.add( JSONKeys.PROPERTIES, propBuilder.build() );
+
                 for( MigrationEvents migrationEvent : migrationEvents )
                 {
                     migrationEvent.propertyRenamed( state.getString( JSONKeys.IDENTITY ), from, to );
                 }
 
-                return true;
+                return builder.build();
             }
             else
             {
-                return false;
+                context.addFailure( "Rename property " + from + " to " + to );
+                return state;
             }
         }
 
         @Override
-        public boolean addAssociation( JSONObject state, String name, String defaultReference )
-            throws JSONException
+        public JsonObject addAssociation( MigrationContext context, JsonObject state, String name,
+                                          String defaultReference )
+            throws JsonException
         {
-            JSONObject associations = state.getJSONObject( JSONKeys.ASSOCIATIONS );
-            if( !associations.has( name ) )
+            JsonObject associations = state.getJsonObject( JSONKeys.ASSOCIATIONS );
+            if( !associations.containsKey( name ) )
             {
-                if( defaultReference == null )
+                JsonObjectBuilder builder = Json.createObjectBuilder();
+                for( Map.Entry<String, JsonValue> entry : state.entrySet() )
                 {
-                    associations.put( name, JSONObject.NULL );
+                    String key = entry.getKey();
+                    if( !JSONKeys.ASSOCIATIONS.equals( key ) )
+                    {
+                        builder.add( key, entry.getValue() );
+                    }
                 }
-                else
+                JsonObjectBuilder assocBuilder = Json.createObjectBuilder();
+                for( Map.Entry<String, JsonValue> entry : associations.entrySet() )
                 {
-                    associations.put( name, defaultReference );
+                    assocBuilder.add( entry.getKey(), entry.getValue() );
                 }
+                JsonValue value = serialization.toJson( defaultReference );
+                assocBuilder.add( name, value );
+                builder.add( JSONKeys.ASSOCIATIONS, assocBuilder.build() );
+                context.markAsChanged();
 
                 for( MigrationEvents migrationEvent : migrationEvents )
                 {
                     migrationEvent.associationAdded( state.getString( JSONKeys.IDENTITY ), name, defaultReference );
                 }
 
-                return true;
+                return builder.build();
             }
             else
             {
-                return false;
+                context.addFailure( "Add association " + name + ", default:" + defaultReference );
+                return state;
             }
         }
 
         @Override
-        public boolean removeAssociation( JSONObject state, String name )
-            throws JSONException
+        public JsonObject removeAssociation( MigrationContext context, JsonObject state, String name )
+            throws JsonException
         {
-            JSONObject associations = state.getJSONObject( JSONKeys.ASSOCIATIONS );
-            if( associations.has( name ) )
+            JsonObject associations = state.getJsonObject( JSONKeys.ASSOCIATIONS );
+            if( associations.containsKey( name ) )
             {
-                associations.remove( name );
+                JsonObjectBuilder builder = Json.createObjectBuilder();
+                for( Map.Entry<String, JsonValue> entry : state.entrySet() )
+                {
+                    String key = entry.getKey();
+                    if( !JSONKeys.ASSOCIATIONS.equals( key ) )
+                    {
+                        builder.add( key, entry.getValue() );
+                    }
+                }
+                JsonObjectBuilder assocBuilder = Json.createObjectBuilder();
+                for( Map.Entry<String, JsonValue> entry : associations.entrySet() )
+                {
+                    String key = entry.getKey();
+                    if( !name.equals( key ) )
+                    {
+                        assocBuilder.add( key, entry.getValue() );
+                    }
+                    else
+                    {
+                        context.markAsChanged();
+                    }
+                }
+                builder.add( JSONKeys.ASSOCIATIONS, assocBuilder.build() );
+
                 for( MigrationEvents migrationEvent : migrationEvents )
                 {
                     migrationEvent.associationRemoved( state.getString( JSONKeys.IDENTITY ), name );
                 }
 
-                return true;
+                return builder.build();
             }
             else
             {
-                return false;
+                context.addFailure( "Remove association " + name );
+                return state;
             }
         }
 
         @Override
-        public boolean renameAssociation( JSONObject state, String from, String to )
-            throws JSONException
+        public JsonObject renameAssociation( MigrationContext context, JsonObject state, String from, String to )
+            throws JsonException
         {
-            JSONObject associations = state.getJSONObject( JSONKeys.ASSOCIATIONS );
-            if( associations.has( from ) )
+            JsonObject associations = state.getJsonObject( JSONKeys.ASSOCIATIONS );
+            if( associations.containsKey( from ) )
             {
-                Object value = associations.remove( from );
-                associations.put( to, value );
+                JsonObjectBuilder builder = Json.createObjectBuilder();
+                for( Map.Entry<String, JsonValue> entry : state.entrySet() )
+                {
+                    String key = entry.getKey();
+                    if( !JSONKeys.ASSOCIATIONS.equals( key ) )
+                    {
+                        builder.add( key, entry.getValue() );
+                    }
+                }
+                JsonObjectBuilder assocBuilder = Json.createObjectBuilder();
+                for( Map.Entry<String, JsonValue> entry : associations.entrySet() )
+                {
+                    String key = entry.getKey();
+                    if( from.equals( key ) )
+                    {
+                        assocBuilder.add( to, entry.getValue() );
+                        context.markAsChanged();
+                    }
+                    else
+                    {
+                        assocBuilder.add( to, entry.getValue() );
+                    }
+                }
+                builder.add( JSONKeys.ASSOCIATIONS, assocBuilder.build() );
 
                 for( MigrationEvents migrationEvent : migrationEvents )
                 {
                     migrationEvent.associationRenamed( state.getString( JSONKeys.IDENTITY ), from, to );
                 }
 
-                return true;
+                return builder.build();
             }
             else
             {
-                return false;
+                context.addFailure( "Rename association " + from + " to " + to );
+                return state;
             }
         }
 
         @Override
-        public boolean addManyAssociation( JSONObject state, String name, String... defaultReferences )
-            throws JSONException
+        public JsonObject addManyAssociation( MigrationContext context, JsonObject state, String name,
+                                              String... defaultReferences )
+            throws JsonException
         {
-            JSONObject manyAssociations = state.getJSONObject( JSONKeys.MANY_ASSOCIATIONS );
-            if( !manyAssociations.has( name ) )
+            JsonObject manyAssociations = state.getJsonObject( JSONKeys.MANY_ASSOCIATIONS );
+            if( !manyAssociations.containsKey( name ) )
             {
-                JSONArray references = new JSONArray();
-                for( String reference : defaultReferences )
+                JsonObjectBuilder builder = Json.createObjectBuilder();
+                for( Map.Entry<String, JsonValue> entry : state.entrySet() )
+                {
+                    String key = entry.getKey();
+                    if( !JSONKeys.MANY_ASSOCIATIONS.equals( key ) )
+                    {
+                        builder.add( key, entry.getValue() );
+                    }
+                }
+                JsonObjectBuilder assocBuilder = Json.createObjectBuilder();
+                for( Map.Entry<String, JsonValue> entry : manyAssociations.entrySet() )
                 {
-                    references.put( reference );
+                    assocBuilder.add( entry.getKey(), entry.getValue() );
                 }
-                manyAssociations.put( name, references );
+                JsonValue value = serialization.toJson( defaultReferences );
+                assocBuilder.add( name, value );
+                builder.add( JSONKeys.MANY_ASSOCIATIONS, assocBuilder.build() );
+                context.markAsChanged();
 
                 for( MigrationEvents migrationEvent : migrationEvents )
                 {
-                    migrationEvent.manyAssociationAdded( state.getString( JSONKeys.IDENTITY ), name, defaultReferences );
+                    migrationEvent.manyAssociationAdded( state.getString( JSONKeys.IDENTITY ), name,
+                                                         defaultReferences );
                 }
 
-                return true;
+                return builder.build();
             }
             else
             {
-                return false;
+                context.addFailure( "Add many-association " + name + ", default:" + asList( defaultReferences ) );
+                return state;
             }
         }
 
         @Override
-        public boolean removeManyAssociation( JSONObject state, String name )
-            throws JSONException
+        public JsonObject removeManyAssociation( MigrationContext context, JsonObject state, String name )
+            throws JsonException
         {
-            JSONObject manyAssociations = state.getJSONObject( JSONKeys.MANY_ASSOCIATIONS );
-            if( manyAssociations.has( name ) )
+            JsonObject manyAssociations = state.getJsonObject( JSONKeys.MANY_ASSOCIATIONS );
+            if( manyAssociations.containsKey( name ) )
             {
-                manyAssociations.remove( name );
+                JsonObjectBuilder builder = Json.createObjectBuilder();
+                for( Map.Entry<String, JsonValue> entry : state.entrySet() )
+                {
+                    String key = entry.getKey();
+                    if( !JSONKeys.MANY_ASSOCIATIONS.equals( key ) )
+                    {
+                        builder.add( key, entry.getValue() );
+                    }
+                }
+                JsonObjectBuilder assocBuilder = Json.createObjectBuilder();
+                for( Map.Entry<String, JsonValue> entry : manyAssociations.entrySet() )
+                {
+                    String key = entry.getKey();
+                    if( !name.equals( key ) )
+                    {
+                        assocBuilder.add( key, entry.getValue() );
+                    }
+                    else
+                    {
+                        context.markAsChanged();
+                    }
+                }
+                builder.add( JSONKeys.MANY_ASSOCIATIONS, assocBuilder.build() );
+
                 for( MigrationEvents migrationEvent : migrationEvents )
                 {
                     migrationEvent.manyAssociationRemoved( state.getString( JSONKeys.IDENTITY ), name );
                 }
 
-                return true;
+                return builder.build();
             }
             else
             {
-                return false;
+                context.addFailure( "Remove many-association " + name );
+                return state;
             }
         }
 
         @Override
-        public boolean renameManyAssociation( JSONObject state, String from, String to )
-            throws JSONException
+        public JsonObject renameManyAssociation( MigrationContext context, JsonObject state, String from, String to )
+            throws JsonException
         {
-            JSONObject manyAssociations = state.getJSONObject( JSONKeys.MANY_ASSOCIATIONS );
-            if( manyAssociations.has( from ) )
+            JsonObject manyAssociations = state.getJsonObject( JSONKeys.MANY_ASSOCIATIONS );
+            if( manyAssociations.containsKey( from ) )
             {
-                Object value = manyAssociations.remove( from );
-                manyAssociations.put( to, value );
+                JsonObjectBuilder builder = Json.createObjectBuilder();
+                for( Map.Entry<String, JsonValue> entry : state.entrySet() )
+                {
+                    String key = entry.getKey();
+                    if( !JSONKeys.MANY_ASSOCIATIONS.equals( key ) )
+                    {
+                        builder.add( key, entry.getValue() );
+                    }
+                }
+                JsonObjectBuilder assocBuilder = Json.createObjectBuilder();
+                for( Map.Entry<String, JsonValue> entry : manyAssociations.entrySet() )
+                {
+                    String key = entry.getKey();
+                    if( from.equals( key ) )
+                    {
+                        context.markAsChanged();
+                        assocBuilder.add( to, entry.getValue() );
+                    }
+                    else
+                    {
+                        assocBuilder.add( key, entry.getValue() );
+                    }
+                }
+                builder.add( JSONKeys.MANY_ASSOCIATIONS, assocBuilder.build() );
 
                 for( MigrationEvents migrationEvent : migrationEvents )
                 {
                     migrationEvent.manyAssociationRenamed( state.getString( JSONKeys.IDENTITY ), from, to );
                 }
 
-                return true;
+                return builder.build();
             }
             else
             {
-                return false;
+                context.addFailure( "Rename many-association " + from + " to " + to );
+                return state;
             }
         }
 
         @Override
-        public boolean addNamedAssociation( JSONObject state, String name, Map<String, String> defaultReferences )
-            throws JSONException
+        public JsonObject addNamedAssociation( MigrationContext context, JsonObject state, String name,
+                                               Map<String, String> defaultReferences )
+            throws JsonException
         {
-            JSONObject namedAssociations = state.getJSONObject( JSONKeys.NAMED_ASSOCIATIONS );
-            if( !namedAssociations.has( name ) )
+            JsonObject namedAssociations = state.getJsonObject( JSONKeys.NAMED_ASSOCIATIONS );
+            if( !namedAssociations.containsKey( name ) )
             {
-                JSONObject references = new JSONObject();
-                for( Map.Entry<String, String> namedRef : defaultReferences.entrySet() )
+                JsonObjectBuilder builder = Json.createObjectBuilder();
+                for( Map.Entry<String, JsonValue> entry : state.entrySet() )
                 {
-                    references.put( namedRef.getKey(), namedRef.getValue() );
+                    String key = entry.getKey();
+                    if( !JSONKeys.NAMED_ASSOCIATIONS.equals( key ) )
+                    {
+                        builder.add( key, entry.getValue() );
+                    }
                 }
-                namedAssociations.put( name, references );
+                JsonObjectBuilder assocBuilder = Json.createObjectBuilder();
+                for( Map.Entry<String, JsonValue> entry : namedAssociations.entrySet() )
+                {
+                    assocBuilder.add( entry.getKey(), entry.getValue() );
+                }
+                JsonValue value = serialization.toJson( defaultReferences );
+                assocBuilder.add( name, value );
+                builder.add( JSONKeys.NAMED_ASSOCIATIONS, assocBuilder.build() );
+                context.markAsChanged();
 
                 for( MigrationEvents migrationEvent : migrationEvents )
                 {
-                    migrationEvent.namedAssociationAdded( state.getString( JSONKeys.IDENTITY ), name, defaultReferences );
+                    migrationEvent.namedAssociationAdded( state.getString( JSONKeys.IDENTITY ), name,
+                                                          defaultReferences );
                 }
 
-                return true;
+                return builder.build();
             }
             else
             {
-                return false;
+                context.addFailure( "Add named-association " + name + ", default:" + defaultReferences );
+                return state;
             }
         }
 
         @Override
-        public boolean removeNamedAssociation( JSONObject state, String name )
-            throws JSONException
+        public JsonObject removeNamedAssociation( MigrationContext context, JsonObject state, String name )
+            throws JsonException
         {
-            JSONObject namedAssociations = state.getJSONObject( JSONKeys.NAMED_ASSOCIATIONS );
-            if( namedAssociations.has( name ) )
+            JsonObject namedAssociations = state.getJsonObject( JSONKeys.NAMED_ASSOCIATIONS );
+            if( namedAssociations.containsKey( name ) )
             {
-                namedAssociations.remove( name );
+                JsonObjectBuilder builder = Json.createObjectBuilder();
+                for( Map.Entry<String, JsonValue> entry : state.entrySet() )
+                {
+                    String key = entry.getKey();
+                    if( !JSONKeys.NAMED_ASSOCIATIONS.equals( key ) )
+                    {
+                        builder.add( key, entry.getValue() );
+                    }
+                }
+                JsonObjectBuilder assocBuilder = Json.createObjectBuilder();
+                for( Map.Entry<String, JsonValue> entry : namedAssociations.entrySet() )
+                {
+                    String key = entry.getKey();
+                    if( !name.equals( key ) )
+                    {
+                        assocBuilder.add( key, entry.getValue() );
+                    }
+                    else
+                    {
+                        context.markAsChanged();
+                    }
+                }
+                builder.add( JSONKeys.NAMED_ASSOCIATIONS, assocBuilder.build() );
 
                 for( MigrationEvents migrationEvent : migrationEvents )
                 {
                     migrationEvent.namedAssociationRemoved( state.getString( JSONKeys.IDENTITY ), name );
                 }
 
-                return true;
+                return builder.build();
             }
             else
             {
-                return false;
+                context.addFailure( "Remove named-association " + name );
+                return state;
             }
         }
 
         @Override
-        public boolean renameNamedAssociation( JSONObject state, String from, String to )
-            throws JSONException
+        public JsonObject renameNamedAssociation( MigrationContext context, JsonObject state, String from, String to )
+            throws JsonException
         {
-            JSONObject namedAssociations = state.getJSONObject( JSONKeys.NAMED_ASSOCIATIONS );
-            if( namedAssociations.has( from ) )
+            JsonObject namedAssociations = state.getJsonObject( JSONKeys.NAMED_ASSOCIATIONS );
+            if( namedAssociations.containsKey( from ) )
             {
-                Object value = namedAssociations.remove( from );
-                namedAssociations.put( to, value );
+                JsonObjectBuilder builder = Json.createObjectBuilder();
+                for( Map.Entry<String, JsonValue> entry : state.entrySet() )
+                {
+                    String key = entry.getKey();
+                    if( !JSONKeys.NAMED_ASSOCIATIONS.equals( key ) )
+                    {
+                        builder.add( key, entry.getValue() );
+                    }
+                }
+                JsonObjectBuilder assocBuilder = Json.createObjectBuilder();
+                for( Map.Entry<String, JsonValue> entry : namedAssociations.entrySet() )
+                {
+                    String key = entry.getKey();
+                    if( from.equals( key ) )
+                    {
+                        assocBuilder.add( to, entry.getValue() );
+                        context.markAsChanged();
+                    }
+                    else
+                    {
+                        assocBuilder.add( key, entry.getValue() );
+                    }
+                }
+                builder.add( JSONKeys.NAMED_ASSOCIATIONS, assocBuilder.build() );
 
                 for( MigrationEvents migrationEvent : migrationEvents )
                 {
                     migrationEvent.namedAssociationRenamed( state.getString( JSONKeys.IDENTITY ), from, to );
                 }
 
-                return true;
+                return builder.build();
             }
             else
             {
-                return false;
+                context.addFailure( "Rename named-association " + from + " to " + to );
+                return state;
             }
         }
 
         @Override
-        public void changeEntityType( JSONObject state, String newEntityType )
-            throws JSONException
+        public JsonObject changeEntityType( MigrationContext context, JsonObject state,
+                                            String fromType, String toType )
+            throws JsonException
         {
-            state.put( JSONKeys.TYPE, newEntityType );
+            JsonObjectBuilder builder = Json.createObjectBuilder();
+            for( Map.Entry<String, JsonValue> entry : state.entrySet() )
+            {
+                String key = entry.getKey();
+                if( JSONKeys.TYPE.equals( key ) )
+                {
+                    String oldValue = entry.getValue().getValueType() == JsonValue.ValueType.STRING
+                                      ? ( (JsonString) entry.getValue() ).getString()
+                                      : entry.getValue().toString();
+                    if( !fromType.equals( oldValue ) )
+                    {
+                        context.addFailure( "Change entity type from " + fromType + " to " + toType );
+                        return state;
+                    }
+                    builder.add( JSONKeys.TYPE, toType );
+                    context.markAsChanged();
+                }
+                else
+                {
+                    builder.add( key, entry.getValue() );
+                }
+            }
 
             for( MigrationEvents migrationEvent : migrationEvents )
             {
-                migrationEvent.entityTypeChanged( state.getString( JSONKeys.IDENTITY ), newEntityType );
+                migrationEvent.entityTypeChanged( state.getString( JSONKeys.IDENTITY ), toType );
             }
+
+            return builder.build();
         }
     }
-
 }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/e4cca11e/extensions/migration/src/main/java/org/apache/polygene/migration/Migrator.java
----------------------------------------------------------------------
diff --git a/extensions/migration/src/main/java/org/apache/polygene/migration/Migrator.java b/extensions/migration/src/main/java/org/apache/polygene/migration/Migrator.java
index 7880946..a09b891 100644
--- a/extensions/migration/src/main/java/org/apache/polygene/migration/Migrator.java
+++ b/extensions/migration/src/main/java/org/apache/polygene/migration/Migrator.java
@@ -20,8 +20,8 @@
 package org.apache.polygene.migration;
 
 import java.util.Map;
-import org.json.JSONException;
-import org.json.JSONObject;
+import javax.json.JsonObject;
+import org.apache.polygene.migration.assembly.MigrationContext;
 
 /**
  * The Migrator implements this interface, which is invoked by MigrationOperation implementations
@@ -29,42 +29,42 @@ import org.json.JSONObject;
  */
 public interface Migrator
 {
-    boolean addProperty( JSONObject state, String name, Object defaultValue )
-        throws JSONException;
+    JsonObject addProperty( MigrationContext content, JsonObject state,
+                            String name, Object defaultValue );
 
-    boolean removeProperty( JSONObject state, String name )
-        throws JSONException;
+    JsonObject removeProperty( MigrationContext content, JsonObject state,
+                               String name );
 
-    boolean renameProperty( JSONObject state, String from, String to )
-        throws JSONException;
+    JsonObject renameProperty( MigrationContext content, JsonObject state,
+                               String from, String to );
 
-    boolean addAssociation( JSONObject state, String name, String defaultReference )
-        throws JSONException;
+    JsonObject addAssociation( MigrationContext content, JsonObject state,
+                               String name, String defaultReference );
 
-    boolean removeAssociation( JSONObject state, String name )
-        throws JSONException;
+    JsonObject removeAssociation( MigrationContext content, JsonObject state,
+                                  String name );
 
-    boolean renameAssociation( JSONObject state, String from, String to )
-        throws JSONException;
+    JsonObject renameAssociation( MigrationContext content, JsonObject state,
+                                  String from, String to );
 
-    boolean addManyAssociation( JSONObject state, String name, String... defaultReferences )
-        throws JSONException;
+    JsonObject addManyAssociation( MigrationContext content, JsonObject state,
+                                   String name, String... defaultReferences );
 
-    boolean removeManyAssociation( JSONObject state, String name )
-        throws JSONException;
+    JsonObject removeManyAssociation( MigrationContext content, JsonObject state,
+                                      String name );
 
-    boolean renameManyAssociation( JSONObject state, String from, String to )
-        throws JSONException;
+    JsonObject renameManyAssociation( MigrationContext content, JsonObject state,
+                                      String from, String to );
 
-    boolean addNamedAssociation( JSONObject state, String name, Map<String, String> defaultReferences )
-        throws JSONException;
+    JsonObject addNamedAssociation( MigrationContext content, JsonObject state,
+                                    String name, Map<String, String> defaultReferences );
 
-    boolean removeNamedAssociation( JSONObject state, String name )
-        throws JSONException;
+    JsonObject removeNamedAssociation( MigrationContext content, JsonObject state,
+                                       String name );
 
-    boolean renameNamedAssociation( JSONObject state, String from, String to )
-        throws JSONException;
+    JsonObject renameNamedAssociation( MigrationContext content, JsonObject state,
+                                       String from, String to );
 
-    void changeEntityType( JSONObject state, String newEntityType )
-        throws JSONException;
+    JsonObject changeEntityType( MigrationContext content, JsonObject state,
+                                 String fromType, String toType );
 }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/e4cca11e/extensions/migration/src/main/java/org/apache/polygene/migration/assembly/AbstractMigrationRule.java
----------------------------------------------------------------------
diff --git a/extensions/migration/src/main/java/org/apache/polygene/migration/assembly/AbstractMigrationRule.java b/extensions/migration/src/main/java/org/apache/polygene/migration/assembly/AbstractMigrationRule.java
index 80f9612..df5e929 100644
--- a/extensions/migration/src/main/java/org/apache/polygene/migration/assembly/AbstractMigrationRule.java
+++ b/extensions/migration/src/main/java/org/apache/polygene/migration/assembly/AbstractMigrationRule.java
@@ -43,4 +43,10 @@ public class AbstractMigrationRule
     {
         return toVersion;
     }
+
+    @Override
+    public String toString()
+    {
+        return fromVersion + "=>" + toVersion + ": " + getClass();
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/e4cca11e/extensions/migration/src/main/java/org/apache/polygene/migration/assembly/EntityMigrationOperation.java
----------------------------------------------------------------------
diff --git a/extensions/migration/src/main/java/org/apache/polygene/migration/assembly/EntityMigrationOperation.java b/extensions/migration/src/main/java/org/apache/polygene/migration/assembly/EntityMigrationOperation.java
index 0bff1aa..a5b5741 100644
--- a/extensions/migration/src/main/java/org/apache/polygene/migration/assembly/EntityMigrationOperation.java
+++ b/extensions/migration/src/main/java/org/apache/polygene/migration/assembly/EntityMigrationOperation.java
@@ -20,8 +20,8 @@
 
 package org.apache.polygene.migration.assembly;
 
-import org.json.JSONException;
-import org.json.JSONObject;
+import javax.json.JsonException;
+import javax.json.JsonObject;
 import org.apache.polygene.migration.Migrator;
 import org.apache.polygene.spi.entitystore.helpers.StateStore;
 
@@ -30,9 +30,9 @@ import org.apache.polygene.spi.entitystore.helpers.StateStore;
  */
 public interface EntityMigrationOperation
 {
-    boolean upgrade( JSONObject state, StateStore stateStore, Migrator migrator )
-        throws JSONException;
+    JsonObject upgrade( MigrationContext context, JsonObject state, StateStore stateStore, Migrator migrator )
+        throws JsonException;
 
-    boolean downgrade( JSONObject state, StateStore stateStore, Migrator migrator )
-        throws JSONException;
+    JsonObject downgrade( MigrationContext context, JsonObject state, StateStore stateStore, Migrator migrator )
+        throws JsonException;
 }
\ No newline at end of file