=== 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, Map> classMapCache = Maps.newHashMap(); - - public static Map getJacksonClassMap( Class clazz ) - { - return getJacksonClassMap( clazz, true ); - } - - public static Map getJacksonClassMap( Class clazz, boolean deep ) - { + private static Map, Map> classMapCache = Maps.newHashMap(); + + public static class MethodDescriptor + { + private Method method; + + private boolean collection; + + private boolean identifiableObject; + + private Map 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 getObjects() + { + return objects; + } + + public void setObjects( Map objects ) + { + this.objects = objects; + } + } + + public static Map getJacksonClassMap( Class clazz ) + { + return getJacksonClassMap( clazz, 2 ); + } + + public static Map 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 output = Maps.newLinkedHashMap(); - + boolean deep = false; + level--; + + if ( level > 0 ) + { + deep = true; + } + + Map output = Maps.newLinkedHashMap(); List 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 classMap = getJacksonClassMap( returnType, false ); + descriptor.setIdentifiableObject( true ); - for ( String key : classMap.keySet() ) + if ( deep ) { - output.put( name + "." + key, classMap.get( key ) ); + Map 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 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 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 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 objects = WebUtils.filterFields( entityList, fields ); + // List objects = WebUtils.filterFields( entityList, include ); Map 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 List filterFields( List entityList, String fields ) + @SuppressWarnings( "unchecked" ) + private static void putInMap( Map map, String path ) { - List objects = Lists.newArrayList(); - - if ( entityList.isEmpty() || fields == null ) - { - return objects; - } - - Map classMap = ReflectionUtils.getJacksonClassMap( entityList.get( 0 ).getClass() ); - List parsedFields = parseFieldExpression( fields ); - - for ( T object : entityList ) - { - Map 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> idPropertiesList = Lists.newArrayList(); - Collection identifiableObjects; - - try - { - identifiableObjects = (Collection) o; - } - catch ( ClassCastException ex ) - { - return o; - } - - for ( IdentifiableObject identifiableObject : identifiableObjects ) - { - Map idProps = getIdentifiableObjectProperties( identifiableObject ); - idPropertiesList.add( idProps ); - } - - return idPropertiesList; - } - - private static Map getIdentifiableObjectProperties( IdentifiableObject identifiableObject ) - { - Map 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 parseFieldExpression( String fields ) - { - List splitFields = Lists.newArrayList(); + map = (Map) map.get( p ); + } + } + + public static Map parseFieldExpression( String fields ) + { + List prefixList = Lists.newArrayList(); + Map parsed = Maps.newHashMap(); StringBuilder builder = new StringBuilder(); - ArrayList 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 prefixList )