← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 13968: rewrote logic for parsing of jacksonClassMap and filter queries for web-api

 

------------------------------------------------------------
revno: 13968
committer: Morten Olav Hansen <mortenoh@xxxxxxxxx>
branch nick: dhis2
timestamp: Mon 2014-02-10 11:59:03 +0700
message:
  rewrote logic for parsing of jacksonClassMap and filter queries for web-api
modified:
  dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/ReflectionUtils.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/AbstractCrudController.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/utils/WebUtils.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
=== modified file 'dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/ReflectionUtils.java'
--- dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/ReflectionUtils.java	2014-02-06 08:24:34 +0000
+++ dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/ReflectionUtils.java	2014-02-10 04:59:03 +0000
@@ -28,6 +28,7 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
 import com.google.common.collect.Maps;
@@ -524,22 +525,90 @@
         return fieldName;
     }
 
-    private static Map<Class<?>, Map<String, Method>> classMapCache = Maps.newHashMap();
-
-    public static Map<String, Method> getJacksonClassMap( Class<?> clazz )
-    {
-        return getJacksonClassMap( clazz, true );
-    }
-
-    public static Map<String, Method> getJacksonClassMap( Class<?> clazz, boolean deep )
-    {
+    private static Map<Class<?>, Map<String, MethodDescriptor>> classMapCache = Maps.newHashMap();
+
+    public static class MethodDescriptor
+    {
+        private Method method;
+
+        private boolean collection;
+
+        private boolean identifiableObject;
+
+        private Map<String, MethodDescriptor> objects;
+
+        private MethodDescriptor( Method method )
+        {
+            this.method = method;
+        }
+
+        @JsonIgnore
+        public Method getMethod()
+        {
+            return method;
+        }
+
+        public void setMethod( Method method )
+        {
+            this.method = method;
+        }
+
+        @JsonProperty
+        public boolean isCollection()
+        {
+            return collection;
+        }
+
+        public void setCollection( boolean collection )
+        {
+            this.collection = collection;
+        }
+
+        @JsonProperty
+        public boolean isIdentifiableObject()
+        {
+            return identifiableObject;
+        }
+
+        public void setIdentifiableObject( boolean identifiableObject )
+        {
+            this.identifiableObject = identifiableObject;
+        }
+
+        @JsonProperty
+        public Map<String, MethodDescriptor> getObjects()
+        {
+            return objects;
+        }
+
+        public void setObjects( Map<String, MethodDescriptor> objects )
+        {
+            this.objects = objects;
+        }
+    }
+
+    public static Map<String, MethodDescriptor> getJacksonClassMap( Class<?> clazz )
+    {
+        return getJacksonClassMap( clazz, 2 );
+    }
+
+    public static Map<String, MethodDescriptor> getJacksonClassMap( Class<?> clazz, int level )
+    {
+        // this short-circuits the level stuff for now, need to fix this properly
         if ( classMapCache.containsKey( clazz ) )
         {
             return classMapCache.get( clazz );
         }
 
-        Map<String, Method> output = Maps.newLinkedHashMap();
-
+        boolean deep = false;
+        level--;
+
+        if ( level > 0 )
+        {
+            deep = true;
+        }
+
+        Map<String, MethodDescriptor> output = Maps.newLinkedHashMap();
         List<Method> allMethods = getAllMethods( clazz );
 
         for ( Method method : allMethods )
@@ -547,6 +616,7 @@
             if ( method.isAnnotationPresent( JsonProperty.class ) )
             {
                 JsonProperty jsonProperty = method.getAnnotation( JsonProperty.class );
+                MethodDescriptor descriptor = new MethodDescriptor( method );
 
                 String name = jsonProperty.value();
 
@@ -567,25 +637,23 @@
                     }
 
                     name = StringUtils.uncapitalize( name );
-                    output.put( name, method );
-                }
-                else
-                {
-                    output.put( name, method );
-                }
+                }
+
+                output.put( name, descriptor );
 
                 Class<?> returnType = method.getReturnType();
 
-                if ( deep && IdentifiableObject.class.isAssignableFrom( returnType ) )
+                if ( IdentifiableObject.class.isAssignableFrom( returnType ) )
                 {
-                    Map<String, Method> classMap = getJacksonClassMap( returnType, false );
+                    descriptor.setIdentifiableObject( true );
 
-                    for ( String key : classMap.keySet() )
+                    if ( deep )
                     {
-                        output.put( name + "." + key, classMap.get( key ) );
+                        Map<String, MethodDescriptor> classMap = getJacksonClassMap( returnType, level );
+                        descriptor.setObjects( classMap );
                     }
                 }
-                else if ( deep && Collection.class.isAssignableFrom( returnType ) )
+                else if ( Collection.class.isAssignableFrom( returnType ) )
                 {
                     Type type = method.getGenericReturnType();
 
@@ -596,11 +664,13 @@
 
                         if ( IdentifiableObject.class.isAssignableFrom( klass ) )
                         {
-                            Map<String, Method> classMap = getJacksonClassMap( klass, false );
+                            descriptor.setCollection( true );
+                            descriptor.setIdentifiableObject( true );
 
-                            for ( String key : classMap.keySet() )
+                            if ( deep )
                             {
-                                output.put( name + "." + key, classMap.get( key ) );
+                                Map<String, MethodDescriptor> classMap = getJacksonClassMap( klass, level );
+                                descriptor.setObjects( classMap );
                             }
                         }
                     }

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/AbstractCrudController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/AbstractCrudController.java	2014-02-06 06:37:09 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/AbstractCrudController.java	2014-02-10 04:59:03 +0000
@@ -85,12 +85,13 @@
     //--------------------------------------------------------------------------
 
     @RequestMapping( value = "/filtered", method = RequestMethod.GET )
-    public void getJacksonClassMap( @RequestParam( required = false ) String fields,
+    public void getJacksonClassMap(
+        @RequestParam( required = false ) String include,
         @RequestParam Map<String, String> parameters, HttpServletResponse response ) throws IOException
     {
-        if ( fields == null )
+        if ( include == null )
         {
-            JacksonUtils.toJson( response.getOutputStream(), ReflectionUtils.getJacksonClassMap( getEntityClass() ).keySet() );
+            JacksonUtils.toJson( response.getOutputStream(), ReflectionUtils.getJacksonClassMap( getEntityClass() ) );
             return;
         }
 
@@ -103,7 +104,7 @@
         postProcessEntities( entityList );
         postProcessEntities( entityList, options, parameters );
 
-        List<Object> objects = WebUtils.filterFields( entityList, fields );
+        // List<Object> objects = WebUtils.filterFields( entityList, include );
         Map<String, Object> output = Maps.newLinkedHashMap();
 
         if ( options.hasPaging() )
@@ -111,7 +112,7 @@
             output.put( "pager", metaData.getPager() );
         }
 
-        output.put( "objects", objects );
+        output.put( "objects", WebUtils.parseFieldExpression( include ) );
 
         JacksonUtils.toJson( response.getOutputStream(), output );
     }

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/utils/WebUtils.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/utils/WebUtils.java	2014-02-07 06:32:38 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/utils/WebUtils.java	2014-02-10 04:59:03 +0000
@@ -41,7 +41,6 @@
 import org.hisp.dhis.user.UserCredentials;
 
 import java.lang.reflect.Field;
-import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
@@ -186,111 +185,32 @@
         }
     }
 
-    public static <T extends IdentifiableObject> List<Object> filterFields( List<T> entityList, String fields )
+    @SuppressWarnings( "unchecked" )
+    private static void putInMap( Map<String, Object> map, String path )
     {
-        List<Object> objects = Lists.newArrayList();
-
-        if ( entityList.isEmpty() || fields == null )
-        {
-            return objects;
-        }
-
-        Map<String, Method> classMap = ReflectionUtils.getJacksonClassMap( entityList.get( 0 ).getClass() );
-        List<String> parsedFields = parseFieldExpression( fields );
-
-        for ( T object : entityList )
-        {
-            Map<String, Object> objMap = Maps.newLinkedHashMap();
-
-            for ( String field : parsedFields )
+        for ( String p : path.split( "\\." ) )
+        {
+            if ( map.get( p ) == null )
             {
-                if ( classMap.containsKey( field ) )
-                {
-                    Object o = ReflectionUtils.invokeMethod( object, classMap.get( field ) );
-
-                    if ( o == null )
-                    {
-                        continue;
-                    }
-
-                    if ( !ReflectionUtils.isCollection( o ) )
-                    {
-                        if ( IdentifiableObject.class.isInstance( o ) )
-                        {
-                            objMap.put( field, getIdentifiableObjectProperties( (IdentifiableObject) o ) );
-                        }
-                        else
-                        {
-                            objMap.put( field, o );
-                        }
-                    }
-                    else
-                    {
-                        objMap.put( field, getIdentifiableObjectCollectionProperties( o ) );
-                    }
-                }
+                map.put( p, Maps.newHashMap() );
             }
 
-            objects.add( objMap );
-        }
-
-        return objects;
-    }
-
-    @SuppressWarnings( "unchecked" )
-    private static Object getIdentifiableObjectCollectionProperties( Object o )
-    {
-        List<Map<String, Object>> idPropertiesList = Lists.newArrayList();
-        Collection<IdentifiableObject> identifiableObjects;
-
-        try
-        {
-            identifiableObjects = (Collection<IdentifiableObject>) o;
-        }
-        catch ( ClassCastException ex )
-        {
-            return o;
-        }
-
-        for ( IdentifiableObject identifiableObject : identifiableObjects )
-        {
-            Map<String, Object> idProps = getIdentifiableObjectProperties( identifiableObject );
-            idPropertiesList.add( idProps );
-        }
-
-        return idPropertiesList;
-    }
-
-    private static Map<String, Object> getIdentifiableObjectProperties( IdentifiableObject identifiableObject )
-    {
-        Map<String, Object> idProps = Maps.newLinkedHashMap();
-
-        idProps.put( "id", identifiableObject.getUid() );
-        idProps.put( "name", identifiableObject.getDisplayName() );
-
-        if ( identifiableObject.getCode() != null )
-        {
-            idProps.put( "code", identifiableObject.getCode() );
-        }
-
-        idProps.put( "created", identifiableObject.getCreated() );
-        idProps.put( "lastUpdated", identifiableObject.getLastUpdated() );
-
-        return idProps;
-    }
-
-    private static List<String> parseFieldExpression( String fields )
-    {
-        List<String> splitFields = Lists.newArrayList();
+            map = (Map<String, Object>) map.get( p );
+        }
+    }
+
+    public static Map<String, Object> parseFieldExpression( String fields )
+    {
+        List<String> prefixList = Lists.newArrayList();
+        Map<String, Object> parsed = Maps.newHashMap();
 
         StringBuilder builder = new StringBuilder();
-        ArrayList<String> prefixList = Lists.newArrayList();
 
         for ( String c : fields.split( "" ) )
         {
             if ( c.equals( "," ) )
             {
-                splitFields.add( joinedWithPrefix( builder, prefixList ) );
+                putInMap( parsed, joinedWithPrefix( builder, prefixList ) );
                 builder = new StringBuilder();
                 continue;
             }
@@ -306,7 +226,7 @@
             {
                 if ( !builder.toString().isEmpty() )
                 {
-                    splitFields.add( joinedWithPrefix( builder, prefixList ) );
+                    putInMap( parsed, joinedWithPrefix( builder, prefixList ) );
                 }
 
                 prefixList.remove( prefixList.size() - 1 );
@@ -322,10 +242,10 @@
 
         if ( !builder.toString().isEmpty() )
         {
-            splitFields.add( joinedWithPrefix( builder, prefixList ) );
+            putInMap( parsed, joinedWithPrefix( builder, prefixList ) );
         }
 
-        return splitFields;
+        return parsed;
     }
 
     private static String joinedWithPrefix( StringBuilder builder, List<String> prefixList )