polygene-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From paulmer...@apache.org
Subject [2/3] polygene-java git commit: XML Serialization enhancements
Date Sun, 02 Apr 2017 17:11:50 GMT
XML Serialization enhancements

Reuse XML factories and transformers for performance reasons.
Allow to explicitly set XML factories implementation during assembly.
Normalize XML when deserializing for lenient parsing.
Adds coverage with hand crafted XML documents.


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

Branch: refs/heads/serialization-3.0
Commit: 6552f23014b632c4b775734071aa013305a97974
Parents: d6e1b0e
Author: Paul Merlin <paulmerlin@apache.org>
Authored: Sun Apr 2 16:48:25 2017 +0200
Committer: Paul Merlin <paulmerlin@apache.org>
Committed: Sun Apr 2 17:58:20 2017 +0200

----------------------------------------------------------------------
 .../spi/serialization/XmlDeserializer.java      |  24 ---
 .../spi/serialization/XmlSerializer.java        |  45 ------
 .../javaxxml/JavaxXmlDeserializer.java          |  66 +++++++--
 .../javaxxml/JavaxXmlFactories.java             |  74 ++++++++++
 .../javaxxml/JavaxXmlSerializer.java            |  77 ++++++++--
 .../javaxxml/JavaxXmlSettings.java              |  24 +++
 .../javaxxml/deserializer-normalization.xsl     |   9 ++
 .../javaxxml/HandCraftedXmlTest.java            | 146 +++++++++++++++++++
 ...JavaxXmlValueCompositeSerializationTest.java |   1 -
 9 files changed, 371 insertions(+), 95 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/polygene-java/blob/6552f230/core/spi/src/main/java/org/apache/polygene/spi/serialization/XmlDeserializer.java
----------------------------------------------------------------------
diff --git a/core/spi/src/main/java/org/apache/polygene/spi/serialization/XmlDeserializer.java
b/core/spi/src/main/java/org/apache/polygene/spi/serialization/XmlDeserializer.java
index 3d42828..4ea4fe1 100644
--- a/core/spi/src/main/java/org/apache/polygene/spi/serialization/XmlDeserializer.java
+++ b/core/spi/src/main/java/org/apache/polygene/spi/serialization/XmlDeserializer.java
@@ -17,22 +17,13 @@
  */
 package org.apache.polygene.spi.serialization;
 
-import java.io.IOException;
-import java.io.Reader;
 import java.util.function.Function;
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
 import org.apache.polygene.api.serialization.Deserializer;
-import org.apache.polygene.api.serialization.SerializationException;
 import org.apache.polygene.api.structure.ModuleDescriptor;
 import org.apache.polygene.api.type.ValueType;
 import org.apache.polygene.spi.module.ModuleSpi;
-import org.w3c.dom.Document;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
 import org.w3c.dom.Node;
 
 /**
@@ -88,19 +79,4 @@ public interface XmlDeserializer extends Deserializer
     {
         return fromXmlEach( module, valueType, Stream.of( states ) );
     }
-
-    @Override
-    default <T> T deserialize( ModuleDescriptor module, ValueType valueType, Reader
state )
-    {
-        try
-        {
-            DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
-            Document doc = docBuilder.parse( new InputSource( state ) );
-            return fromXml( module, valueType, doc );
-        }
-        catch( SAXException | IOException | ParserConfigurationException ex )
-        {
-            throw new SerializationException( "Unable to read XML document", ex );
-        }
-    }
 }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/6552f230/core/spi/src/main/java/org/apache/polygene/spi/serialization/XmlSerializer.java
----------------------------------------------------------------------
diff --git a/core/spi/src/main/java/org/apache/polygene/spi/serialization/XmlSerializer.java
b/core/spi/src/main/java/org/apache/polygene/spi/serialization/XmlSerializer.java
index 6e1b7dc..007f731 100644
--- a/core/spi/src/main/java/org/apache/polygene/spi/serialization/XmlSerializer.java
+++ b/core/spi/src/main/java/org/apache/polygene/spi/serialization/XmlSerializer.java
@@ -17,23 +17,12 @@
  */
 package org.apache.polygene.spi.serialization;
 
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.io.Writer;
 import java.util.function.Function;
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
 import org.apache.polygene.api.common.Optional;
-import org.apache.polygene.api.serialization.SerializationException;
 import org.apache.polygene.api.serialization.Serializer;
 import org.w3c.dom.Document;
-import org.w3c.dom.Node;
 
 /**
  * {@literal javax.xml} serializer.
@@ -86,38 +75,4 @@ public interface XmlSerializer extends Serializer
     {
         return toXmlEach( Options.DEFAULT, Stream.of( objects ) );
     }
-
-    default void serialize( Options options, Writer writer, @Optional Object object )
-    {
-        Document xmlDocument = toXml( options, object );
-        if( xmlDocument == null )
-        {
-            return;
-        }
-        try
-        {
-            // We want plain text nodes to be serialized without surrounding elements
-            if( xmlDocument.getNodeType() == Node.TEXT_NODE )
-            {
-                writer.write( xmlDocument.getNodeValue() );
-            }
-            else
-            {
-                Transformer transformer = TransformerFactory.newInstance().newTransformer();
-                transformer.setOutputProperty( OutputKeys.METHOD, "xml" );
-                transformer.setOutputProperty( OutputKeys.VERSION, "1.1" );
-                transformer.setOutputProperty( OutputKeys.STANDALONE, "yes" );
-                transformer.setOutputProperty( OutputKeys.ENCODING, "UTF-8" );
-                transformer.transform( new DOMSource( xmlDocument ), new StreamResult( writer
) );
-            }
-        }
-        catch( IOException ex )
-        {
-            throw new UncheckedIOException( ex );
-        }
-        catch( TransformerException ex )
-        {
-            throw new SerializationException( "Unable to transform XML Document to String",
ex );
-        }
-    }
 }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/6552f230/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlDeserializer.java
----------------------------------------------------------------------
diff --git a/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlDeserializer.java
b/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlDeserializer.java
index 5caed72..69a9068 100644
--- a/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlDeserializer.java
+++ b/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlDeserializer.java
@@ -17,6 +17,8 @@
  */
 package org.apache.polygene.serialization.javaxxml;
 
+import java.io.InputStream;
+import java.io.Reader;
 import java.lang.reflect.Array;
 import java.util.ArrayList;
 import java.util.Base64;
@@ -33,10 +35,16 @@ import java.util.function.Predicate;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.stream.StreamSource;
 import org.apache.polygene.api.association.AssociationDescriptor;
 import org.apache.polygene.api.entity.EntityReference;
 import org.apache.polygene.api.injection.scope.This;
 import org.apache.polygene.api.injection.scope.Uses;
+import org.apache.polygene.api.mixin.Initializable;
 import org.apache.polygene.api.property.PropertyDescriptor;
 import org.apache.polygene.api.serialization.Converter;
 import org.apache.polygene.api.serialization.Converters;
@@ -62,11 +70,15 @@ import static java.util.Collections.unmodifiableMap;
 import static java.util.Collections.unmodifiableSet;
 import static org.apache.polygene.api.util.Collectors.toMapWithNullValues;
 
-public class JavaxXmlDeserializer extends AbstractTextDeserializer implements XmlDeserializer
+public class JavaxXmlDeserializer extends AbstractTextDeserializer
+    implements XmlDeserializer, Initializable
 {
     private static final String NULL_ELEMENT_NAME = "null";
 
     @This
+    private JavaxXmlFactories xmlFactories;
+
+    @This
     private Converters converters;
 
     @This
@@ -75,10 +87,45 @@ public class JavaxXmlDeserializer extends AbstractTextDeserializer implements
Xm
     @Uses
     private ServiceDescriptor descriptor;
 
+    private JavaxXmlSettings settings;
+
+    private Transformer normalizingTransformer;
+
+    @Override
+    public void initialize() throws Exception
+    {
+        settings = JavaxXmlSettings.orDefault( descriptor.metaInfo( JavaxXmlSettings.class
) );
+
+        String xslPath = "/org/apache/polygene/serialization/javaxxml/deserializer-normalization.xsl";
+        InputStream xsltStream = getClass().getResourceAsStream( xslPath );
+        normalizingTransformer = xmlFactories.transformerFactory()
+                                             .newTransformer( new StreamSource( xsltStream
) );
+        normalizingTransformer.setOutputProperty( OutputKeys.METHOD, "xml" );
+        normalizingTransformer.setOutputProperty( OutputKeys.VERSION, "1.1" );
+        normalizingTransformer.setOutputProperty( OutputKeys.STANDALONE, "yes" );
+        normalizingTransformer.setOutputProperty( OutputKeys.ENCODING, UTF_8.name() );
+    }
+
+    @Override
+    public <T> T deserialize( ModuleDescriptor module, ValueType valueType, Reader
state )
+    {
+        try
+        {
+            DOMResult domResult = new DOMResult();
+            normalizingTransformer.transform( new StreamSource( state ), domResult );
+            Node node = domResult.getNode();
+            return fromXml( module, valueType, node );
+        }
+        catch( TransformerException ex )
+        {
+            throw new SerializationException( "Unable to read XML document", ex );
+        }
+    }
+
     @Override
     public <T> T fromXml( ModuleDescriptor module, ValueType valueType, Node state
)
     {
-        Optional<Element> stateElement = JavaxXml.firstChildElementNamed( state, getSettings().getRootTagName()
);
+        Optional<Element> stateElement = JavaxXml.firstChildElementNamed( state, settings.getRootTagName()
);
         if( stateElement.isPresent() )
         {
             Optional<Node> stateNode = JavaxXml.firstStateChildNode( stateElement.get()
);
@@ -139,7 +186,7 @@ public class JavaxXmlDeserializer extends AbstractTextDeserializer implements
Xm
             ValueDescriptor descriptor = module.valueDescriptor( typeInfo.get() );
             if( descriptor == null )
             {
-                String typeInfoName = getSettings().getTypeInfoTagName();
+                String typeInfoName = settings.getTypeInfoTagName();
                 throw new SerializationException(
                     typeInfoName + ": " + typeInfo.get() + " could not be resolved while
deserializing " + xml );
             }
@@ -252,7 +299,7 @@ public class JavaxXmlDeserializer extends AbstractTextDeserializer implements
Xm
             .childElements( xml )
             .map( element ->
                   {
-                      if( getSettings().getCollectionElementTagName().equals( element.getTagName()
) )
+                      if( settings.getCollectionElementTagName().equals( element.getTagName()
) )
                       {
                           return doDeserialize( module, collectionType.collectedType(),
                                                 JavaxXml.firstStateChildNode( element ).get()
);
@@ -269,7 +316,7 @@ public class JavaxXmlDeserializer extends AbstractTextDeserializer implements
Xm
         {
             return new LinkedHashMap<>();
         }
-        Predicate<Element> complexMapping = element -> getSettings().getMapEntryTagName().equals(
element.getTagName() )
+        Predicate<Element> complexMapping = element -> settings.getMapEntryTagName().equals(
element.getTagName() )
                                                        && JavaxXml.firstChildElementNamed(
element, "key" )
                                                                   .isPresent();
         // This allows deserializing mixed simple/complex mappings for a given map
@@ -309,7 +356,7 @@ public class JavaxXmlDeserializer extends AbstractTextDeserializer implements
Xm
                 return deserializeValueComposite( valueDescriptor.module(), valueDescriptor.valueType(),
xml );
             }
         }
-        if( xml.getNodeType() == Node.CDATA_SECTION_NODE )
+        if( xml.getNodeType() == Node.CDATA_SECTION_NODE || xml.getNodeType() == Node.TEXT_NODE
)
         {
             byte[] bytes = Base64.getDecoder().decode( xml.getNodeValue().getBytes( UTF_8
) );
             return deserializeJava( bytes );
@@ -323,16 +370,11 @@ public class JavaxXmlDeserializer extends AbstractTextDeserializer implements
Xm
         {
             return Optional.empty();
         }
-        String typeInfo = ( (Element) xml ).getAttribute( getSettings().getTypeInfoTagName()
);
+        String typeInfo = ( (Element) xml ).getAttribute( settings.getTypeInfoTagName() );
         if( typeInfo.isEmpty() )
         {
             return Optional.empty();
         }
         return Optional.of( typeInfo );
     }
-
-    private JavaxXmlSettings getSettings()
-    {
-        return JavaxXmlSettings.orDefault( descriptor.metaInfo( JavaxXmlSettings.class )
);
-    }
 }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/6552f230/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlFactories.java
----------------------------------------------------------------------
diff --git a/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlFactories.java
b/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlFactories.java
new file mode 100644
index 0000000..f3a7f80
--- /dev/null
+++ b/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlFactories.java
@@ -0,0 +1,74 @@
+/*
+ *  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.serialization.javaxxml;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.TransformerFactory;
+import org.apache.polygene.api.injection.scope.Uses;
+import org.apache.polygene.api.mixin.Initializable;
+import org.apache.polygene.api.mixin.Mixins;
+import org.apache.polygene.api.service.ServiceDescriptor;
+
+@Mixins( JavaxXmlFactories.Mixin.class )
+public interface JavaxXmlFactories
+{
+    DocumentBuilderFactory documentBuilderFactory();
+
+    TransformerFactory transformerFactory();
+
+    class Mixin implements JavaxXmlFactories, Initializable
+    {
+        @Uses
+        private ServiceDescriptor descriptor;
+
+        private DocumentBuilderFactory documentBuilderFactory;
+        private TransformerFactory transformerFactory;
+
+        @Override
+        public void initialize()
+        {
+            JavaxXmlSettings settings = JavaxXmlSettings.orDefault( descriptor.metaInfo(
JavaxXmlSettings.class ) );
+
+            String documentBuilderFactoryClassName = settings.getDocumentBuilderFactoryClassName();
+            documentBuilderFactory = documentBuilderFactoryClassName == null
+                                     ? DocumentBuilderFactory.newInstance()
+                                     : DocumentBuilderFactory.newInstance( documentBuilderFactoryClassName,
+                                                                           getClass().getClassLoader()
);
+            documentBuilderFactory.setNamespaceAware( false );
+            documentBuilderFactory.setIgnoringComments( true );
+
+            String transformerFactoryClassName = settings.getTransformerFactoryClassName();
+            transformerFactory = transformerFactoryClassName == null
+                                 ? TransformerFactory.newInstance()
+                                 : TransformerFactory.newInstance( transformerFactoryClassName,
+                                                                   getClass().getClassLoader()
);
+        }
+
+        @Override
+        public DocumentBuilderFactory documentBuilderFactory()
+        {
+            return documentBuilderFactory;
+        }
+
+        @Override
+        public TransformerFactory transformerFactory()
+        {
+            return transformerFactory;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/6552f230/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlSerializer.java
----------------------------------------------------------------------
diff --git a/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlSerializer.java
b/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlSerializer.java
index 3c49699..44fd7b0 100644
--- a/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlSerializer.java
+++ b/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlSerializer.java
@@ -17,19 +17,28 @@
  */
 package org.apache.polygene.serialization.javaxxml;
 
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.io.Writer;
 import java.util.Base64;
 import java.util.Map;
 import java.util.function.Function;
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
-import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
 import org.apache.polygene.api.PolygeneAPI;
 import org.apache.polygene.api.association.AssociationStateHolder;
+import org.apache.polygene.api.common.Optional;
 import org.apache.polygene.api.composite.CompositeInstance;
 import org.apache.polygene.api.entity.EntityReference;
 import org.apache.polygene.api.injection.scope.This;
 import org.apache.polygene.api.injection.scope.Uses;
+import org.apache.polygene.api.mixin.Initializable;
 import org.apache.polygene.api.serialization.Converter;
 import org.apache.polygene.api.serialization.Converters;
 import org.apache.polygene.api.serialization.SerializationException;
@@ -54,11 +63,15 @@ import static org.apache.polygene.api.util.Collectors.toMap;
 /**
  * XML Serializer.
  */
-public class JavaxXmlSerializer extends AbstractTextSerializer implements XmlSerializer
+public class JavaxXmlSerializer extends AbstractTextSerializer
+    implements XmlSerializer, Initializable
 {
     private static final String NULL_ELEMENT_NAME = "null";
 
     @This
+    private JavaxXmlFactories xmlFactories;
+
+    @This
     private Converters converters;
 
     @This
@@ -67,6 +80,51 @@ public class JavaxXmlSerializer extends AbstractTextSerializer implements
XmlSer
     @Uses
     private ServiceDescriptor descriptor;
 
+    private JavaxXmlSettings settings;
+
+    private Transformer toStringTransformer;
+
+    @Override
+    public void initialize() throws Exception
+    {
+        settings = JavaxXmlSettings.orDefault( descriptor.metaInfo( JavaxXmlSettings.class
) );
+        toStringTransformer = xmlFactories.transformerFactory().newTransformer();
+        toStringTransformer.setOutputProperty( OutputKeys.METHOD, "xml" );
+        toStringTransformer.setOutputProperty( OutputKeys.VERSION, "1.1" );
+        toStringTransformer.setOutputProperty( OutputKeys.STANDALONE, "yes" );
+        toStringTransformer.setOutputProperty( OutputKeys.ENCODING, "UTF-8" );
+    }
+
+    @Override
+    public void serialize( Options options, Writer writer, @Optional Object object )
+    {
+        Document xmlDocument = toXml( options, object );
+        if( xmlDocument == null )
+        {
+            return;
+        }
+        try
+        {
+            // We want plain text nodes to be serialized without surrounding elements
+            if( xmlDocument.getNodeType() == Node.TEXT_NODE )
+            {
+                writer.write( xmlDocument.getNodeValue() );
+            }
+            else
+            {
+                toStringTransformer.transform( new DOMSource( xmlDocument ), new StreamResult(
writer ) );
+            }
+        }
+        catch( IOException ex )
+        {
+            throw new UncheckedIOException( ex );
+        }
+        catch( TransformerException ex )
+        {
+            throw new SerializationException( "Unable to transform XML Document to String",
ex );
+        }
+    }
+
     @Override
     public <T> Function<T, Document> toXmlFunction( Options options )
     {
@@ -77,10 +135,10 @@ public class JavaxXmlSerializer extends AbstractTextSerializer implements
XmlSer
     {
         try
         {
-            Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
+            Document doc = xmlFactories.documentBuilderFactory().newDocumentBuilder().newDocument();
             doc.setXmlVersion( "1.1" );
             doc.setXmlStandalone( true );
-            Element stateElement = doc.createElement( getSettings().getRootTagName() );
+            Element stateElement = doc.createElement( settings.getRootTagName() );
             Node node = doSerialize( doc, options, object, true );
             stateElement.appendChild( node );
             doc.appendChild( stateElement );
@@ -146,7 +204,7 @@ public class JavaxXmlSerializer extends AbstractTextSerializer implements
XmlSer
         AssociationStateHolder state = (AssociationStateHolder) instance.state();
         ValueCompositeType valueType = descriptor.valueType();
 
-        Element valueElement = document.createElement( getSettings().getValueTagName() );
+        Element valueElement = document.createElement( settings.getValueTagName() );
         valueType.properties().forEach(
             property ->
             {
@@ -185,14 +243,13 @@ public class JavaxXmlSerializer extends AbstractTextSerializer implements
XmlSer
         );
         if( !root && options.includeTypeInfo() )
         {
-            valueElement.setAttribute( getSettings().getTypeInfoTagName(), valueType.primaryType().getName()
);
+            valueElement.setAttribute( settings.getTypeInfoTagName(), valueType.primaryType().getName()
);
         }
         return valueElement;
     }
 
     private Node serializeMap( Document document, Options options, Map<?, ?> map )
     {
-        JavaxXmlSettings settings = getSettings();
         Element mapElement = document.createElement( settings.getMapTagName() );
         if( map.isEmpty() )
         {
@@ -264,7 +321,6 @@ public class JavaxXmlSerializer extends AbstractTextSerializer implements
XmlSer
 
     private Node serializeStream( Document document, Options options, Stream<?> object
)
     {
-        JavaxXmlSettings settings = getSettings();
         Element collectionElement = document.createElement( settings.getCollectionTagName()
);
         object.map( each -> doSerialize( document, options, each, false ) )
               .forEach( itemValueNode ->
@@ -275,9 +331,4 @@ public class JavaxXmlSerializer extends AbstractTextSerializer implements
XmlSer
                         } );
         return collectionElement;
     }
-
-    private JavaxXmlSettings getSettings()
-    {
-        return JavaxXmlSettings.orDefault( descriptor.metaInfo( JavaxXmlSettings.class )
);
-    }
 }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/6552f230/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlSettings.java
----------------------------------------------------------------------
diff --git a/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlSettings.java
b/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlSettings.java
index c5484fb..9f4d007 100644
--- a/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlSettings.java
+++ b/extensions/serialization-javaxxml/src/main/java/org/apache/polygene/serialization/javaxxml/JavaxXmlSettings.java
@@ -37,6 +37,9 @@ public class JavaxXmlSettings extends SerializationSettings<JavaxXmlSettings>
         return settings != null ? settings : DEFAULT;
     }
 
+    private String documentBuilderFactoryClassName;
+    private String transformerFactoryClassName;
+
     private String rootTagName;
     private String collectionTagName;
     private String collectionElementTagName;
@@ -44,6 +47,7 @@ public class JavaxXmlSettings extends SerializationSettings<JavaxXmlSettings>
     private String mapEntryTagName;
     private String valueTagName;
     private String typeInfoTagName;
+
     private Map<ValueType, JavaxXmlAdapter<?>> adapters;
 
     public JavaxXmlSettings()
@@ -58,6 +62,26 @@ public class JavaxXmlSettings extends SerializationSettings<JavaxXmlSettings>
         adapters = new LinkedHashMap<>();
     }
 
+    public String getDocumentBuilderFactoryClassName()
+    {
+        return documentBuilderFactoryClassName;
+    }
+
+    public void setDocumentBuilderFactoryClassName( String documentBuilderFactoryClassName
)
+    {
+        this.documentBuilderFactoryClassName = documentBuilderFactoryClassName;
+    }
+
+    public String getTransformerFactoryClassName()
+    {
+        return transformerFactoryClassName;
+    }
+
+    public void setTransformerFactoryClassName( String transformerFactoryClassName )
+    {
+        this.transformerFactoryClassName = transformerFactoryClassName;
+    }
+
     public String getRootTagName()
     {
         return rootTagName;

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/6552f230/extensions/serialization-javaxxml/src/main/resources/org/apache/polygene/serialization/javaxxml/deserializer-normalization.xsl
----------------------------------------------------------------------
diff --git a/extensions/serialization-javaxxml/src/main/resources/org/apache/polygene/serialization/javaxxml/deserializer-normalization.xsl
b/extensions/serialization-javaxxml/src/main/resources/org/apache/polygene/serialization/javaxxml/deserializer-normalization.xsl
new file mode 100644
index 0000000..6c8505b
--- /dev/null
+++ b/extensions/serialization-javaxxml/src/main/resources/org/apache/polygene/serialization/javaxxml/deserializer-normalization.xsl
@@ -0,0 +1,9 @@
+<?xml version="1.1" encoding="UTF-8" standalone="yes"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+    <xsl:strip-space elements="*"/>
+    <xsl:template match="@*|node()">
+        <xsl:copy>
+            <xsl:apply-templates select="@*|node()"/>
+        </xsl:copy>
+    </xsl:template>
+</xsl:stylesheet>

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/6552f230/extensions/serialization-javaxxml/src/test/java/org/apache/polygene/serialization/javaxxml/HandCraftedXmlTest.java
----------------------------------------------------------------------
diff --git a/extensions/serialization-javaxxml/src/test/java/org/apache/polygene/serialization/javaxxml/HandCraftedXmlTest.java
b/extensions/serialization-javaxxml/src/test/java/org/apache/polygene/serialization/javaxxml/HandCraftedXmlTest.java
new file mode 100644
index 0000000..18f251a
--- /dev/null
+++ b/extensions/serialization-javaxxml/src/test/java/org/apache/polygene/serialization/javaxxml/HandCraftedXmlTest.java
@@ -0,0 +1,146 @@
+/*
+ *  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.serialization.javaxxml;
+
+import org.apache.polygene.api.common.Optional;
+import org.apache.polygene.api.injection.scope.Service;
+import org.apache.polygene.api.property.Property;
+import org.apache.polygene.api.serialization.Deserializer;
+import org.apache.polygene.bootstrap.ModuleAssembly;
+import org.apache.polygene.serialization.javaxxml.assembly.JavaxXmlSerializationAssembler;
+import org.apache.polygene.test.AbstractPolygeneTest;
+import org.junit.Test;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.assertThat;
+
+public class HandCraftedXmlTest extends AbstractPolygeneTest
+{
+    @Override
+    public void assemble( ModuleAssembly module )
+    {
+        new JavaxXmlSerializationAssembler().assemble( module );
+        module.values( SomeValue.class );
+    }
+
+    public interface SomeValue
+    {
+        @Optional
+        Property<String> foo();
+    }
+
+    @Service
+    private Deserializer deserializer;
+
+    @Test
+    public void canReadSingleLineXml()
+    {
+        String xml = "<state><value><foo>bar</foo></value></state>";
+        assertThat( deserializer.deserialize( module, SomeValue.class, xml ).foo().get(),
+                    equalTo( "bar" ) );
+    }
+
+    @Test
+    public void canReadMultiLineXml()
+    {
+        String xml = "<state>\n<value>\n<foo>bar</foo>\n</value>\n</state>";
+        assertThat( deserializer.deserialize( module, SomeValue.class, xml ).foo().get(),
+                    equalTo( "bar" ) );
+    }
+
+    @Test
+    public void canReadIndentedMultiLineXml()
+    {
+        String xml = "<state>\n\t<value>\n\t\t<foo>bar</foo>\n\t</value>\n</state>";
+        assertThat( deserializer.deserialize( module, SomeValue.class, xml ).foo().get(),
+                    equalTo( "bar" ) );
+    }
+
+    @Test
+    public void canReadSingleLineXmlWithMultilineStringValue()
+    {
+        String xml = "<state><value><foo>bar\nbaz\n</foo></value></state>";
+        assertThat( deserializer.deserialize( module, SomeValue.class, xml ).foo().get(),
+                    equalTo( "bar\nbaz\n" ) );
+    }
+
+    @Test
+    public void canReadMultiLineXmlWithMultilineStringValue()
+    {
+        String xml = "<state>\n<value>\n<foo>bar\nbaz\n</foo>\n</value>\n</state>";
+        assertThat( deserializer.deserialize( module, SomeValue.class, xml ).foo().get(),
+                    equalTo( "bar\nbaz\n" ) );
+    }
+
+    @Test
+    public void canReadIndentedMultiLineXmlWithMultilineStringValue()
+    {
+        String xml = "<state>\n\t<value>\n\t\t<foo>bar\nbaz\n</foo>\n\t</value>\n</state>";
+        assertThat( deserializer.deserialize( module, SomeValue.class, xml ).foo().get(),
+                    equalTo( "bar\nbaz\n" ) );
+    }
+
+    @Test
+    public void canReadCommentedXml()
+    {
+        String xml = "<state><value><!-- Some comment --><foo>bar</foo></value></state>";
+        assertThat( deserializer.deserialize( module, SomeValue.class, xml ).foo().get(),
+                    equalTo( "bar" ) );
+    }
+
+    @Test
+    public void canReadMultilineCommentedXml()
+    {
+        String xml = "<state>\n<value>\n<!-- Some comment -->\n<foo>bar</foo>\n</value>\n</state>";
+        assertThat( deserializer.deserialize( module, SomeValue.class, xml ).foo().get(),
+                    equalTo( "bar" ) );
+    }
+
+    @Test
+    public void canReadIndentedMultilineCommentedXml()
+    {
+        String xml = "<state>\n\t<value>\n\t\t<!-- Some comment -->\n\t\t<foo>bar</foo>\n\t</value>\n</state>";
+        assertThat( deserializer.deserialize( module, SomeValue.class, xml ).foo().get(),
+                    equalTo( "bar" ) );
+    }
+
+    @Test
+    public void canReadIndentedMultilineCommentedXmlWithMultilineStringValue()
+    {
+        String xml = "<state>\n\t<value>\n\t\t<!-- Some comment -->\n\t\t<foo>bar\nbaz\n</foo>\n\t</value>\n</state>";
+        assertThat( deserializer.deserialize( module, SomeValue.class, xml ).foo().get(),
+                    equalTo( "bar\nbaz\n" ) );
+    }
+
+    @Test
+    public void canReadIndentedMultilineCommentedXmlWithTextValueStartingWithNewLine()
+    {
+        String xml
+            = "<state>\n\t<value>\n\t\t<!-- Some comment -->\n\t\t<foo>\n\t\t\tbar\n\t\t\tbaz\n</foo>\n\t</value>\n</state>";
+        assertThat( deserializer.deserialize( module, SomeValue.class, xml ).foo().get(),
+                    equalTo( "\n\t\t\tbar\n\t\t\tbaz\n" ) );
+    }
+
+    @Test
+    public void canReadIndentedMultilineXmlWithNullValues()
+    {
+        String xml = "<state>\n\t<value>\n\t\t<foo>\n<null/>\n</foo>\n\t</value>\n</state>";
+        assertThat( deserializer.deserialize( module, SomeValue.class, xml ).foo().get(),
nullValue() );
+    }
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/6552f230/extensions/serialization-javaxxml/src/test/java/org/apache/polygene/serialization/javaxxml/JavaxXmlValueCompositeSerializationTest.java
----------------------------------------------------------------------
diff --git a/extensions/serialization-javaxxml/src/test/java/org/apache/polygene/serialization/javaxxml/JavaxXmlValueCompositeSerializationTest.java
b/extensions/serialization-javaxxml/src/test/java/org/apache/polygene/serialization/javaxxml/JavaxXmlValueCompositeSerializationTest.java
index dc910fc..5c5679f 100644
--- a/extensions/serialization-javaxxml/src/test/java/org/apache/polygene/serialization/javaxxml/JavaxXmlValueCompositeSerializationTest.java
+++ b/extensions/serialization-javaxxml/src/test/java/org/apache/polygene/serialization/javaxxml/JavaxXmlValueCompositeSerializationTest.java
@@ -31,7 +31,6 @@ import static org.hamcrest.Matchers.equalTo;
 import static org.junit.Assert.assertThat;
 import static org.xmlunit.matchers.CompareMatcher.isSimilarTo;
 
-// TODO Assert deserialization from formatted XML, whitespaces are a problem ATM
 public class JavaxXmlValueCompositeSerializationTest extends AbstractValueCompositeSerializationTest
 {
     // START SNIPPET: assembly


Mime
View raw message