From aafe8e9c673d1bb4b62c02ad0b7f323ade9f5d9c Mon Sep 17 00:00:00 2001 From: Benjamin Bentmann Date: Mon, 31 May 2010 16:16:22 +0000 Subject: [PATCH] o Extended plugin to support expressions like "project/dependencies/*/artifactId" to iterate collections git-svn-id: https://svn.apache.org/repos/asf/maven/core-integration-testing/trunk@949790 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/maven/plugin/coreit/EvalMojo.java | 12 ++- .../maven/plugin/coreit/ExpressionUtil.java | 88 ++++++++++++------- .../plugin/coreit/ExpressionUtilTest.java | 63 +++++++------ 3 files changed, 103 insertions(+), 60 deletions(-) diff --git a/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/EvalMojo.java b/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/EvalMojo.java index d10a68e719..6aee51c053 100644 --- a/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/EvalMojo.java +++ b/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/EvalMojo.java @@ -26,6 +26,7 @@ import java.io.File; import java.io.IOException; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; import java.util.Properties; @@ -51,7 +52,7 @@ * * * Expressions that reference non-existing objects or use invalid collection/array indices silently resolve to - * null. + * null. For collections and arrays, the special index "*" can be used to iterate all elements. * * @goal eval * @phase initialize @@ -176,8 +177,13 @@ public void execute() for ( int i = 0; i < expressions.length; i++ ) { - Object value = ExpressionUtil.evaluate( expressions[i], contexts ); - PropertyUtil.store( expressionProperties, expressions[i].replace( '/', '.' ), value ); + Map values = ExpressionUtil.evaluate( expressions[i], contexts ); + for ( Iterator it = values.keySet().iterator(); it.hasNext(); ) + { + Object key = it.next(); + Object value = values.get( key ); + PropertyUtil.store( expressionProperties, key.toString().replace( '/', '.' ), value ); + } } } diff --git a/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/ExpressionUtil.java b/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/ExpressionUtil.java index 004c03aa7d..be6a522540 100644 --- a/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/ExpressionUtil.java +++ b/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/ExpressionUtil.java @@ -24,6 +24,9 @@ import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -48,65 +51,56 @@ class ExpressionUtil * Evaluates the specified expression. Expressions are composed of segments which are separated by a forward slash * ('/'). Each segment specifies a (public) bean property of the current object and drives the evaluation further * down the object graph. For lists, arrays and maps segments can additionally specify the index/key of an element. - * The initial segment denotes the root object and the parameter contexts is used to specify which - * root objects are available. For instance, if contexts maps the token "project" to a Maven project + * The initial segment denotes the root object and the parameter contexts is used to specify which root + * objects are available. For instance, if contexts maps the token "project" to a Maven project * instance, the expression "project/build/resources/0/directory" specifies the first resource directory of the * project. * * @param expression The expression to evaluate, may be null. - * @param contexts The possible root objects for the expression evaluation, indexed by their identifying token, must - * not be null. - * @return The value of the expression or null if the expression could not be evaluated. + * @param context The object to start expression evaluation at, must not be null. + * @return The values of the evaluation, indexed by expression, or an empty map if the segments could not be + * evaluated. */ - public static Object evaluate( String expression, Map contexts ) + public static Map evaluate( String expression, Object context ) { - Object value = null; + Map values = Collections.EMPTY_MAP; if ( expression != null && expression.length() > 0 ) { List segments = Arrays.asList( expression.split( "/", 0 ) ); - if ( !segments.isEmpty() ) - { - Object context = contexts.get( segments.get( 0 ) ); - if ( context != null ) - { - value = evaluate( context, segments.subList( 1, segments.size() ) ); - } - } + values = evaluate( "", segments, context ); } - return value; + return values; } /** * Evaluates the given expression segments against the specified object. * - * @param context The object to evaluate the segments against, may be null. + * @param prefix The expression prefix that led to the current context, must not be null. * @param segments The expression segments to evaluate, must not be null. - * @return The value of the evaluation or null if the segments could not be evaluated. + * @param context The object to evaluate the segments against, may be null. + * @return The values of the evaluation, indexed by expression, or an empty map if the segments could not be + * evaluated. */ - private static Object evaluate( Object context, List segments ) + private static Map evaluate( String prefix, List segments, Object context ) { - Object value = null; + Map values = Collections.EMPTY_MAP; if ( segments.isEmpty() ) { - value = context; + values = Collections.singletonMap( prefix, context ); } else if ( context != null ) { - Object target = null; + Map targets = Collections.EMPTY_MAP; String segment = (String) segments.get( 0 ); - if ( segment.length() <= 0 ) - { - value = context; - } - else if ( context.getClass().isArray() && Character.isDigit( segment.charAt( 0 ) ) ) + if ( context.getClass().isArray() && Character.isDigit( segment.charAt( 0 ) ) ) { try { int index = Integer.parseInt( segment ); - target = Array.get( context, index ); + targets = Collections.singletonMap( segment, Array.get( context, index ) ); } catch ( RuntimeException e ) { @@ -118,21 +112,51 @@ else if ( ( context instanceof List ) && Character.isDigit( segment.charAt( 0 ) try { int index = Integer.parseInt( segment ); - target = ( (List) context ).get( index ); + targets = Collections.singletonMap( segment, ( (List) context ).get( index ) ); } catch ( RuntimeException e ) { // invalid index, just ignore } } + else if ( ( context instanceof Collection ) && "*".equals( segment ) ) + { + targets = new LinkedHashMap(); + int index = 0; + for ( Iterator it = ( (Collection) context ).iterator(); it.hasNext(); index++ ) + { + targets.put( Integer.toString( index ), it.next() ); + } + } + else if ( context.getClass().isArray() && "*".equals( segment ) ) + { + targets = new LinkedHashMap(); + for ( int index = 0, n = Array.getLength( context ); index < n; index++ ) + { + targets.put( Integer.toString( index ), Array.get( context, index ) ); + } + } else { - target = getProperty( context, segment ); + targets = Collections.singletonMap( segment, getProperty( context, segment ) ); + } + + values = new LinkedHashMap(); + for ( Iterator it = targets.keySet().iterator(); it.hasNext(); ) + { + Object key = it.next(); + Object target = targets.get( key ); + values.putAll( evaluate( concat( prefix, String.valueOf( key ) ), + segments.subList( 1, segments.size() ), target ) ); } - value = evaluate( target, segments.subList( 1, segments.size() ) ); } - return value; + return values; + } + + private static String concat( String prefix, String segment ) + { + return ( prefix == null || prefix.length() <= 0 ) ? segment : ( prefix + '/' + segment ); } /** diff --git a/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/ExpressionUtilTest.java b/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/ExpressionUtilTest.java index fe797405c0..88e82f4032 100644 --- a/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/ExpressionUtilTest.java +++ b/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/ExpressionUtilTest.java @@ -47,35 +47,48 @@ public void testEvaluate() contexts.put( "map", map ); contexts.put( "bean", bean ); - assertSame( array, ExpressionUtil.evaluate( "array", contexts ) ); - assertSame( array, ExpressionUtil.evaluate( "array/", contexts ) ); - assertSame( list, ExpressionUtil.evaluate( "list", contexts ) ); - assertSame( map, ExpressionUtil.evaluate( "map", contexts ) ); - assertSame( bean, ExpressionUtil.evaluate( "bean", contexts ) ); - assertNull( ExpressionUtil.evaluate( "no-root", contexts ) ); + assertSame( array, evaluate( "array", contexts ) ); + assertSame( array, ExpressionUtil.evaluate( "array/", contexts ).get( "array" ) ); + assertSame( list, evaluate( "list", contexts ) ); + assertSame( map, evaluate( "map", contexts ) ); + assertSame( bean, evaluate( "bean", contexts ) ); + assertNull( evaluate( "no-root", contexts ) ); - assertEquals( new Integer( 3 ), ExpressionUtil.evaluate( "array/length", contexts ) ); - assertEquals( "three", ExpressionUtil.evaluate( "array/2", contexts ) ); - assertEquals( new Integer( 5 ), ExpressionUtil.evaluate( "array/2/length", contexts ) ); - assertNull( ExpressionUtil.evaluate( "array/invalid", contexts ) ); - assertNull( ExpressionUtil.evaluate( "array/-1", contexts ) ); - assertNull( ExpressionUtil.evaluate( "array/999", contexts ) ); + assertEquals( new Integer( 3 ), evaluate( "array/length", contexts ) ); + assertEquals( "three", evaluate( "array/2", contexts ) ); + assertEquals( new Integer( 5 ), evaluate( "array/2/length", contexts ) ); + assertNull( evaluate( "array/invalid", contexts ) ); + assertNull( evaluate( "array/-1", contexts ) ); + assertNull( evaluate( "array/999", contexts ) ); + assertEquals( 3, ExpressionUtil.evaluate( "array/*", contexts ).size() ); + assertEquals( "one", ExpressionUtil.evaluate( "array/*", contexts ).get( "array/0" ) ); + assertEquals( "two", ExpressionUtil.evaluate( "array/*", contexts ).get( "array/1" ) ); + assertEquals( "three", ExpressionUtil.evaluate( "array/*", contexts ).get( "array/2" ) ); - assertEquals( new Integer( 3 ), ExpressionUtil.evaluate( "list/size", contexts ) ); - assertEquals( "-2", ExpressionUtil.evaluate( "list/2", contexts ) ); - assertNull( ExpressionUtil.evaluate( "list/invalid", contexts ) ); - assertNull( ExpressionUtil.evaluate( "list/-1", contexts ) ); - assertNull( ExpressionUtil.evaluate( "list/999", contexts ) ); + assertEquals( new Integer( 3 ), evaluate( "list/size", contexts ) ); + assertEquals( "-2", evaluate( "list/2", contexts ) ); + assertNull( evaluate( "list/invalid", contexts ) ); + assertNull( evaluate( "list/-1", contexts ) ); + assertNull( evaluate( "list/999", contexts ) ); + assertEquals( 3, ExpressionUtil.evaluate( "list/*", contexts ).size() ); + assertEquals( "0", ExpressionUtil.evaluate( "list/*", contexts ).get( "list/0" ) ); + assertEquals( "-1", ExpressionUtil.evaluate( "list/*", contexts ).get( "list/1" ) ); + assertEquals( "-2", ExpressionUtil.evaluate( "list/*", contexts ).get( "list/2" ) ); - assertEquals( new Integer( 1 ), ExpressionUtil.evaluate( "map/size", contexts ) ); - assertEquals( "value", ExpressionUtil.evaluate( "map/some.key", contexts ) ); - assertNull( ExpressionUtil.evaluate( "map/invalid", contexts ) ); + assertEquals( new Integer( 1 ), evaluate( "map/size", contexts ) ); + assertEquals( "value", evaluate( "map/some.key", contexts ) ); + assertNull( evaluate( "map/invalid", contexts ) ); - assertEquals( "field", ExpressionUtil.evaluate( "bean/field", contexts ) ); - assertNull( ExpressionUtil.evaluate( "bean/invalid", contexts ) ); - assertEquals( "prop", ExpressionUtil.evaluate( "bean/bean/prop", contexts ) ); - assertEquals( "flag", ExpressionUtil.evaluate( "bean/bean/flag", contexts ) ); - assertEquals( "arg", ExpressionUtil.evaluate( "bean/bean/arg", contexts ) ); + assertEquals( "field", evaluate( "bean/field", contexts ) ); + assertNull( evaluate( "bean/invalid", contexts ) ); + assertEquals( "prop", evaluate( "bean/bean/prop", contexts ) ); + assertEquals( "flag", evaluate( "bean/bean/flag", contexts ) ); + assertEquals( "arg", evaluate( "bean/bean/arg", contexts ) ); + } + + private static Object evaluate( String expression, Object context ) + { + return ExpressionUtil.evaluate( expression, context ).get( expression ); } public void testGetProperty()