← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 15727: change default for serializer to include all objects (even null objects), add new class for inclu...

 

------------------------------------------------------------
revno: 15727
committer: Morten Olav Hansen <mortenoh@xxxxxxxxx>
branch nick: dhis2
timestamp: Tue 2014-06-17 16:06:57 +0200
message:
  change default for serializer to include all objects (even null objects), add new class for inclusion strategy (not in use yet)
added:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/config/
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/config/Config.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/config/InclusionStrategy.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/config/Inclusions.java
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/Jackson2JsonNodeSerializer.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/StAXNodeSerializer.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/types/RootNode.java
  dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/DefaultFilterService.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AbstractCrudController.java


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== added directory 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/config'
=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/config/Config.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/config/Config.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/config/Config.java	2014-06-17 14:06:57 +0000
@@ -0,0 +1,56 @@
+package org.hisp.dhis.node.config;
+
+/*
+ * Copyright (c) 2004-2014, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
+ */
+
+/**
+ * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
+ */
+public class Config
+{
+    /**
+     * Inclusion strategy to use. There are a few already defined inclusions in the Inclusions enum.
+     *
+     * @see org.hisp.dhis.node.config.Inclusions
+     */
+    private InclusionStrategy inclusionStrategy = Inclusions.ALWAYS;
+
+    public Config()
+    {
+    }
+
+    public InclusionStrategy getInclusionStrategy()
+    {
+        return inclusionStrategy;
+    }
+
+    public void setInclusionStrategy( InclusionStrategy inclusionStrategy )
+    {
+        this.inclusionStrategy = inclusionStrategy;
+    }
+}

=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/config/InclusionStrategy.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/config/InclusionStrategy.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/config/InclusionStrategy.java	2014-06-17 14:06:57 +0000
@@ -0,0 +1,37 @@
+package org.hisp.dhis.node.config;
+
+/*
+ * Copyright (c) 2004-2014, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
+ */
+
+/**
+ * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
+ */
+public interface InclusionStrategy
+{
+    <T> boolean include( T object );
+}

=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/config/Inclusions.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/config/Inclusions.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/config/Inclusions.java	2014-06-17 14:06:57 +0000
@@ -0,0 +1,43 @@
+package org.hisp.dhis.node.config;
+
+/*
+ * Copyright (c) 2004-2014, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
+ */
+
+/**
+ * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
+ */
+public enum Inclusions implements InclusionStrategy
+{
+    ALWAYS;
+
+    @Override
+    public <T> boolean include( T object )
+    {
+        return true;
+    }
+}

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/Jackson2JsonNodeSerializer.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/Jackson2JsonNodeSerializer.java	2014-06-13 06:47:27 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/Jackson2JsonNodeSerializer.java	2014-06-17 14:06:57 +0000
@@ -28,7 +28,6 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
  */
 
-import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.core.JsonGenerator;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.SerializationFeature;
@@ -49,7 +48,7 @@
  * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
  */
 @Component
-@Scope( value = "prototype", proxyMode = ScopedProxyMode.INTERFACES )
+@Scope(value = "prototype", proxyMode = ScopedProxyMode.INTERFACES)
 public class Jackson2JsonNodeSerializer extends AbstractNodeSerializer
 {
     public static final String CONTENT_TYPE = "application/json";
@@ -58,14 +57,13 @@
 
     static
     {
-        objectMapper.setSerializationInclusion( JsonInclude.Include.NON_NULL );
         objectMapper.configure( SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false );
-        objectMapper.configure( SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, false );
+        objectMapper.configure( SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, true );
         objectMapper.configure( SerializationFeature.WRAP_EXCEPTIONS, true );
         objectMapper.getFactory().enable( JsonGenerator.Feature.QUOTE_FIELD_NAMES );
     }
 
-    private JsonGenerator generator;
+    private JsonGenerator generator = null;
 
     @Override
     public List<String> contentTypes()
@@ -86,12 +84,6 @@
     }
 
     @Override
-    protected void endSerialize( RootNode rootNode, OutputStream outputStream ) throws Exception
-    {
-        generator = null;
-    }
-
-    @Override
     protected void startWriteRootNode( RootNode rootNode ) throws Exception
     {
         //generator.writeRaw( "callback(" );
@@ -108,11 +100,6 @@
     @Override
     protected void startWriteSimpleNode( SimpleNode simpleNode ) throws Exception
     {
-        if ( simpleNode.getValue() == null ) // add hint for this, exclude if null
-        {
-            return;
-        }
-
         if ( simpleNode.getParent().isCollection() )
         {
             generator.writeObject( simpleNode.getValue() );

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/StAXNodeSerializer.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/StAXNodeSerializer.java	2014-06-08 11:06:30 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/StAXNodeSerializer.java	2014-06-17 14:06:57 +0000
@@ -50,20 +50,20 @@
  * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
  */
 @Component
-@Scope( value = "prototype", proxyMode = ScopedProxyMode.INTERFACES )
+@Scope(value = "prototype", proxyMode = ScopedProxyMode.INTERFACES)
 public class StAXNodeSerializer extends AbstractNodeSerializer
 {
     public static final String CONTENT_TYPE = "application/xml";
 
     private static final XMLOutputFactory xmlFactory = XMLOutputFactory.newInstance();
 
-    private XMLStreamWriter writer;
-
     static
     {
         xmlFactory.setProperty( "javax.xml.stream.isRepairingNamespaces", true );
     }
 
+    private XMLStreamWriter writer;
+
     @Override
     public List<String> contentTypes()
     {
@@ -106,11 +106,6 @@
     @Override
     protected void startWriteSimpleNode( SimpleNode simpleNode ) throws Exception
     {
-        if ( simpleNode.getValue() == null ) // TODO include null or not?
-        {
-            return;
-        }
-
         String value = String.format( "%s", simpleNode.getValue() );
 
         if ( simpleNode.isAttribute() )
@@ -134,7 +129,7 @@
     @Override
     protected void endWriteSimpleNode( SimpleNode simpleNode ) throws Exception
     {
-        if ( !simpleNode.isAttribute() && simpleNode.getValue() != null )
+        if ( !simpleNode.isAttribute() )
         {
             writer.writeEndElement();
         }

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/types/RootNode.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/types/RootNode.java	2014-06-13 06:47:27 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/types/RootNode.java	2014-06-17 14:06:57 +0000
@@ -29,6 +29,7 @@
  */
 
 import org.hisp.dhis.node.Node;
+import org.hisp.dhis.node.config.Config;
 
 /**
  * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
@@ -37,6 +38,8 @@
 {
     private String defaultNamespace;
 
+    private final Config config = new Config();
+
     public RootNode( String name )
     {
         super( name );
@@ -59,4 +62,9 @@
     {
         this.defaultNamespace = defaultNamespace;
     }
+
+    public Config getConfig()
+    {
+        return config;
+    }
 }

=== modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/DefaultFilterService.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/DefaultFilterService.java	2014-06-11 09:59:34 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/DefaultFilterService.java	2014-06-17 14:06:57 +0000
@@ -92,11 +92,6 @@
     public <T extends IdentifiableObject> CollectionNode fieldFilter( Class<?> klass, List<T> objects,
         List<String> fieldList )
     {
-        if ( objects.isEmpty() )
-        {
-            return null;
-        }
-
         String fields = fieldList == null ? "" : Joiner.on( "," ).join( fieldList );
 
         Schema rootSchema = schemaService.getDynamicSchema( klass );
@@ -126,24 +121,25 @@
 
         for ( Object object : objects )
         {
-            collectionNode.addChild( buildObjectOutput( fieldMap, object ) );
+            collectionNode.addChild( buildObjectOutput( fieldMap, klass, object ) );
         }
 
         return collectionNode;
     }
 
-    @SuppressWarnings("unchecked")
-    private ComplexNode buildObjectOutput( Map<String, Map> fieldMap, Object object )
+    @SuppressWarnings( "unchecked" )
+    private ComplexNode buildObjectOutput( Map<String, Map> fieldMap, Class<?> klass, Object object )
     {
-        if ( object == null )
-        {
-            return null;
-        }
+        Schema schema = schemaService.getDynamicSchema( klass );
 
-        Schema schema = schemaService.getDynamicSchema( object.getClass() );
         ComplexNode complexNode = new ComplexNode( schema.getName() );
         complexNode.setNamespace( schema.getNamespace() );
 
+        if ( object == null )
+        {
+            return complexNode;
+        }
+
         updateFields( fieldMap, schema.getKlass() );
 
         for ( String fieldKey : fieldMap.keySet() )
@@ -157,12 +153,6 @@
             Object returnValue = ReflectionUtils.invokeMethod( object, property.getGetterMethod() );
             Schema propertySchema = schemaService.getDynamicSchema( property.getKlass() );
 
-            // TODO should we include nulls?
-            if ( returnValue == null )
-            {
-                continue;
-            }
-
             Map fieldValue = fieldMap.get( fieldKey );
 
             if ( property.isCollection() )
@@ -189,7 +179,7 @@
                     {
                         for ( Object collectionObject : collection )
                         {
-                            collectionNode.addChild( getProperties( collectionObject, fields ) );
+                            collectionNode.addChild( getProperties( property.getItemKlass(), collectionObject, fields ) );
                         }
                     }
                     else if ( !property.isSimple() )
@@ -198,7 +188,7 @@
 
                         for ( Object collectionObject : collection )
                         {
-                            ComplexNode node = buildObjectOutput( map, collectionObject );
+                            ComplexNode node = buildObjectOutput( map, property.getItemKlass(), collectionObject );
 
                             if ( !node.getChildren().isEmpty() )
                             {
@@ -216,7 +206,7 @@
                 }
                 else if ( property.isIdentifiableObject() )
                 {
-                    complexNode.addChild( getProperties( returnValue, fields ) );
+                    complexNode.addChild( getProperties( property.getKlass(), returnValue, fields ) );
                 }
                 else
                 {
@@ -230,7 +220,8 @@
                     }
                     else
                     {
-                        complexNode.addChild( buildObjectOutput( getFullFieldMap( propertySchema ), returnValue ) );
+                        complexNode.addChild( buildObjectOutput( getFullFieldMap( propertySchema ), property.getKlass(),
+                            returnValue ) );
                     }
                 }
             }
@@ -243,7 +234,7 @@
 
                     for ( Object collectionObject : (Collection<?>) returnValue )
                     {
-                        ComplexNode node = buildObjectOutput( fieldValue, collectionObject );
+                        ComplexNode node = buildObjectOutput( fieldValue, property.getItemKlass(), collectionObject );
 
                         if ( !node.getChildren().isEmpty() )
                         {
@@ -253,7 +244,7 @@
                 }
                 else
                 {
-                    ComplexNode node = buildObjectOutput( fieldValue, returnValue );
+                    ComplexNode node = buildObjectOutput( fieldValue, property.getKlass(), returnValue );
 
                     if ( !node.getChildren().isEmpty() )
                     {
@@ -340,18 +331,18 @@
         return map;
     }
 
-    private ComplexNode getProperties( Object object, List<String> fields )
+    private ComplexNode getProperties( Class<?> klass, Object object, List<String> fields )
     {
-        if ( object == null )
-        {
-            return null;
-        }
-
-        Schema schema = schemaService.getDynamicSchema( object.getClass() );
+        Schema schema = schemaService.getDynamicSchema( klass );
 
         ComplexNode complexNode = new ComplexNode( schema.getSingular() );
         complexNode.setNamespace( schema.getNamespace() );
 
+        if ( object == null )
+        {
+            return complexNode;
+        }
+
         for ( String field : fields )
         {
             Property property = schema.getPropertyMap().get( field );
@@ -363,20 +354,17 @@
 
             Object o = ReflectionUtils.invokeMethod( object, property.getGetterMethod() );
 
-            if ( o != null )
-            {
-                SimpleNode simpleNode = new SimpleNode( field, o );
-                simpleNode.setAttribute( property.isAttribute() );
-                simpleNode.setNamespace( property.getNamespace() );
+            SimpleNode simpleNode = new SimpleNode( field, o );
+            simpleNode.setAttribute( property.isAttribute() );
+            simpleNode.setNamespace( property.getNamespace() );
 
-                complexNode.addChild( simpleNode );
-            }
+            complexNode.addChild( simpleNode );
         }
 
         return complexNode;
     }
 
-    @SuppressWarnings("unchecked")
+    @SuppressWarnings( "unchecked" )
     private <T> boolean evaluateWithFilters( T object, Filters filters )
     {
         Schema schema = schemaService.getDynamicSchema( object.getClass() );

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AbstractCrudController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AbstractCrudController.java	2014-06-17 10:29:40 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AbstractCrudController.java	2014-06-17 14:06:57 +0000
@@ -46,6 +46,7 @@
 import org.hisp.dhis.hibernate.exception.DeleteAccessDeniedException;
 import org.hisp.dhis.hibernate.exception.UpdateAccessDeniedException;
 import org.hisp.dhis.importexport.ImportStrategy;
+import org.hisp.dhis.node.config.Inclusions;
 import org.hisp.dhis.node.types.CollectionNode;
 import org.hisp.dhis.node.types.ComplexNode;
 import org.hisp.dhis.node.types.RootNode;