diff --git a/its/core-it-support/core-it-plugins/maven-it-plugin-expression/pom.xml b/its/core-it-support/core-it-plugins/maven-it-plugin-expression/pom.xml
new file mode 100644
index 0000000000..e2e2704776
--- /dev/null
+++ b/its/core-it-support/core-it-plugins/maven-it-plugin-expression/pom.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+ * project.dependencies.0.groupId = org.apache.maven + * project.dependencies.0.artifactId = maven-project + * project.dependencies.0.type = jar + * project.dependencies.0.version = 2.0 + * project.dependencies.0.optional = false + * project.dependencies.0.exclusions = 2 + * project.dependencies.0.exclusions.0.groupId = plexus + * project.dependencies.0.exclusions.0.artifactId = plexus-utils + * project.dependencies.0.exclusions.1.groupId = plexus + * project.dependencies.0.exclusions.1.artifactId = plexus-container-default + *+ * + * Expressions that reference non-existing objects or use invalid collection/array indices silently resolve to + *
null
.
+ *
+ * @goal eval
+ * @phase initialize
+ *
+ * @author Benjamin Bentmann
+ * @version $Id$
+ */
+public class EvalMojo
+ extends AbstractMojo
+{
+
+ /**
+ * The path to the output file for the properties with the expression values. For each expression given by the
+ * parameter {@link #expressions} an similar named properties key will be used to save the expression value. If an
+ * expression evaluated to null
, there will be no corresponding key in the properties file.
+ *
+ * @parameter expression="${expression.outputFile}" default-value="${project.build.directory}/expression.properties"
+ */
+ private File outputFile;
+
+ /**
+ * The set of expressions to evaluate.
+ *
+ * @parameter
+ */
+ private String[] expressions;
+
+ /**
+ * The comma separated set of expressions to evaluate.
+ *
+ * @parameter expression="${expression.expressions}"
+ */
+ private String expressionList;
+
+ /**
+ * The current Maven project against which expressions are evaluated.
+ *
+ * @parameter default-value="${project}"
+ * @readonly
+ */
+ private Object project;
+
+ /**
+ * The merged user/global settings of the current build against which expressions are evaluated.
+ *
+ * @parameter default-value="${settings}"
+ * @readonly
+ */
+ private Object settings;
+
+ /**
+ * The session context of the current build against which expressions are evaluated.
+ *
+ * @parameter default-value="${session}"
+ * @readonly
+ */
+ private Object session;
+
+ /**
+ * The local repository of the current build against which expressions are evaluated.
+ *
+ * @parameter default-value="${localRepository}"
+ * @readonly
+ */
+ private Object localRepository;
+
+ /**
+ * Runs this mojo.
+ *
+ * @throws MojoExecutionException If the output file could not be created.
+ * @throws MojoFailureException If the output file has not been set.
+ */
+ public void execute()
+ throws MojoExecutionException, MojoFailureException
+ {
+ if ( outputFile == null )
+ {
+ throw new MojoFailureException( "Path name for output file has not been specified" );
+ }
+
+ getLog().info( "[MAVEN-CORE-IT-LOG] Creating output file: " + outputFile );
+
+ Properties expressionProperties = new Properties();
+
+ if ( expressionList != null && expressionList.length() > 0 )
+ {
+ expressions = expressionList.split( "," );
+ }
+ if ( expressions != null && expressions.length > 0 )
+ {
+ Map contexts = new HashMap();
+ contexts.put( "project", project );
+ contexts.put( "pom", project );
+ contexts.put( "settings", settings );
+ contexts.put( "session", session );
+ contexts.put( "localRepository", localRepository );
+
+ for ( int i = 0; i < expressions.length; i++ )
+ {
+ Object value = ExpressionUtil.evaluate( expressions[i], contexts );
+ PropertyUtil.store( expressionProperties, expressions[i].replace( '/', '.' ), value );
+ }
+ }
+
+ try
+ {
+ PropertyUtil.write( expressionProperties, outputFile );
+ }
+ catch ( IOException e )
+ {
+ throw new MojoExecutionException( "Output file could not be created: " + outputFile, e );
+ }
+
+ getLog().info( "[MAVEN-CORE-IT-LOG] Created output file: " + outputFile );
+ }
+
+}
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
new file mode 100644
index 0000000000..9f32f8b04e
--- /dev/null
+++ b/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/ExpressionUtil.java
@@ -0,0 +1,227 @@
+package org.apache.maven.plugin.coreit;
+
+/*
+ * 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.
+ */
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Assists in evaluating expressions.
+ *
+ * @author Benjamin Bentmann
+ * @version $Id$
+ */
+class ExpressionUtil
+{
+
+ private static final Object[] NO_ARGS = {};
+
+ private static final Class[] NO_PARAMS = {};
+
+ private static final Class[] OBJECT_PARAM = { Object.class };
+
+ private static final Class[] STRING_PARAM = { String.class };
+
+ /**
+ * 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
+ * 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.
+ */
+ public static Object evaluate( String expression, Map contexts )
+ {
+ Object value = null;
+
+ 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() ) );
+ }
+ }
+ }
+
+ return value;
+ }
+
+ /**
+ * Evaluates the given expression segments against the specified object.
+ *
+ * @param context The object to evaluate the segments against, may 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.
+ */
+ private static Object evaluate( Object context, List segments )
+ {
+ Object value = null;
+
+ if ( segments.isEmpty() )
+ {
+ value = context;
+ }
+ else if ( context != null )
+ {
+ Object target = null;
+ String segment = (String) segments.get( 0 );
+ if ( segment.length() <= 0 )
+ {
+ value = context;
+ }
+ else if ( context.getClass().isArray() && Character.isDigit( segment.charAt( 0 ) ) )
+ {
+ try
+ {
+ int index = Integer.parseInt( segment );
+ target = Array.get( context, index );
+ }
+ catch ( RuntimeException e )
+ {
+ // invalid index, just ignore
+ }
+ }
+ else if ( ( context instanceof List ) && Character.isDigit( segment.charAt( 0 ) ) )
+ {
+ try
+ {
+ int index = Integer.parseInt( segment );
+ target = ( (List) context ).get( index );
+ }
+ catch ( RuntimeException e )
+ {
+ // invalid index, just ignore
+ }
+ }
+ else
+ {
+ target = getProperty( context, segment );
+ }
+ value = evaluate( target, segments.subList( 1, segments.size() ) );
+ }
+
+ return value;
+ }
+
+ /**
+ * Gets the value of a (public) bean property from the specified object.
+ *
+ * @param context The object whose bean property should be retrieved, must not be null
.
+ * @param property The name of the bean property, must not be null
.
+ * @return The value of the bean property or null
if the property does not exist.
+ */
+ static Object getProperty( Object context, String property )
+ {
+ Object value;
+
+ Class type = context.getClass();
+ if ( context instanceof Collection )
+ {
+ type = Collection.class;
+ }
+ else if ( context instanceof Map )
+ {
+ type = Map.class;
+ }
+
+ try
+ {
+ try
+ {
+ Method method = type.getMethod( property, NO_PARAMS );
+ value = method.invoke( context, NO_ARGS );
+ }
+ catch ( NoSuchMethodException e )
+ {
+ try
+ {
+ String name = "get" + Character.toUpperCase( property.charAt( 0 ) ) + property.substring( 1 );
+ Method method = type.getMethod( name, NO_PARAMS );
+ value = method.invoke( context, NO_ARGS );
+ }
+ catch ( NoSuchMethodException e1 )
+ {
+ try
+ {
+ String name = "is" + Character.toUpperCase( property.charAt( 0 ) ) + property.substring( 1 );
+ Method method = type.getMethod( name, NO_PARAMS );
+ value = method.invoke( context, NO_ARGS );
+ }
+ catch ( NoSuchMethodException e2 )
+ {
+ try
+ {
+ Method method;
+ try
+ {
+ method = type.getMethod( "get", STRING_PARAM );
+ }
+ catch ( NoSuchMethodException e3 )
+ {
+ method = type.getMethod( "get", OBJECT_PARAM );
+ }
+ value = method.invoke( context, new Object[] { property } );
+ }
+ catch ( NoSuchMethodException e3 )
+ {
+ try
+ {
+ Field field = type.getField( property );
+ value = field.get( context );
+ }
+ catch ( NoSuchFieldException e4 )
+ {
+ if ( "length".equals( property ) && type.isArray() )
+ {
+ value = new Integer( Array.getLength( context ) );
+ }
+ else
+ {
+ throw e4;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ catch ( Exception e )
+ {
+ value = null;
+ }
+ return value;
+ }
+
+}
diff --git a/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/PropertyUtil.java b/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/PropertyUtil.java
new file mode 100644
index 0000000000..831dc3d223
--- /dev/null
+++ b/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/main/java/org/apache/maven/plugin/coreit/PropertyUtil.java
@@ -0,0 +1,194 @@
+package org.apache.maven.plugin.coreit;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * Assists in serializing primitives and beans into properties for later inspection/verification.
+ *
+ * @author Benjamin Bentmann
+ * @version $Id$
+ */
+class PropertyUtil
+{
+
+ private static final Object[] NO_ARGS = {};
+
+ /**
+ * Serializes the specified object into the given properties, using the provided key. The object may be a scalar
+ * value like a string or some array/collection/map or a bean.
+ *
+ * @param props The properties to serialize into, must not be null
.
+ * @param key The key to use for serialization of the object data, must not be null
.
+ * @param obj The object to serialize, may be null
.
+ */
+ public static void store( Properties props, String key, Object obj )
+ {
+ store( props, key, obj, new HashSet() );
+ }
+
+ /**
+ * /** Serializes the specified object into the given properties, using the provided key. The object may be a scalar
+ * value like a string or some array/collection/map or a bean.
+ *
+ * @param props The properties to serialize into, must not be null
.
+ * @param key The key to use for serialization of the object data, must not be null
.
+ * @param obj The object to serialize, may be null
.
+ * @param visited The set/stack of already visited objects, used to detect back references in the object graph, must
+ * not be null
.
+ */
+ private static void store( Properties props, String key, Object obj, Collection visited )
+ {
+ if ( obj != null )
+ {
+ if ( ( obj instanceof String ) || ( obj instanceof Number ) || ( obj instanceof Boolean )
+ || ( obj instanceof File ) )
+ {
+ props.put( key, obj.toString() );
+ }
+ else if ( obj instanceof Collection )
+ {
+ Collection coll = (Collection) obj;
+ props.put( key, Integer.toString( coll.size() ) );
+ int index = 0;
+ for ( Iterator it = coll.iterator(); it.hasNext(); index++ )
+ {
+ Object elem = it.next();
+ store( props, key + "." + index, elem );
+ }
+ }
+ else if ( obj instanceof Map )
+ {
+ Map map = (Map) obj;
+ props.put( key, Integer.toString( map.size() ) );
+ int index = 0;
+ for ( Iterator it = map.entrySet().iterator(); it.hasNext(); index++ )
+ {
+ Map.Entry entry = (Map.Entry) it.next();
+ store( props, key + "." + entry.getKey(), entry.getValue() );
+ }
+ }
+ else if ( obj.getClass().isArray() )
+ {
+ int length = Array.getLength( obj );
+ props.put( key, Integer.toString( length ) );
+ for ( int index = 0; index < length; index++ )
+ {
+ Object elem = Array.get( obj, index );
+ store( props, key + "." + index, elem );
+ }
+ }
+ else if ( obj != null && !visited.contains( obj ) )
+ {
+ visited.add( obj );
+ Class type = obj.getClass();
+ Method[] methods = type.getMethods();
+ for ( int i = 0; i < methods.length; i++ )
+ {
+ Method method = methods[i];
+ if ( Modifier.isStatic( method.getModifiers() ) || method.getParameterTypes().length > 0
+ || !method.getName().matches( "(get|is)\\p{Lu}.*" ) || method.getName().endsWith( "AsMap" )
+ || Class.class.isAssignableFrom( method.getReturnType() )
+ || Object.class.equals( method.getReturnType() ) )
+ {
+ continue;
+ }
+
+ try
+ {
+ Object value = method.invoke( obj, NO_ARGS );
+ store( props, key + "." + getPropertyName( method.getName() ), value, visited );
+ }
+ catch ( Exception e )
+ {
+ // just ignore
+ }
+ }
+ visited.remove( obj );
+ }
+ }
+ }
+
+ /**
+ * Derives the bean property name from the specified method for its getter.
+ *
+ * @param methodName The method name of the property's getter, must not be null
.
+ * @return The property name, never null
.
+ */
+ static String getPropertyName( String methodName )
+ {
+ String propertyName = methodName;
+ if ( methodName.startsWith( "get" ) && methodName.length() > 3 )
+ {
+ propertyName = Character.toLowerCase( methodName.charAt( 3 ) ) + methodName.substring( 4 );
+ }
+ else if ( methodName.startsWith( "is" ) && methodName.length() > 2 )
+ {
+ propertyName = Character.toLowerCase( methodName.charAt( 2 ) ) + methodName.substring( 3 );
+ }
+ return propertyName;
+ }
+
+ /**
+ * Writes the specified properties to the given file.
+ *
+ * @param props The properties to write, must not be null
.
+ * @param file The output file for the properties, must not be null
.
+ * @throws IOException If the properties could not be written to the file.
+ */
+ public static void write( Properties props, File file )
+ throws IOException
+ {
+ OutputStream out = null;
+ try
+ {
+ file.getParentFile().mkdirs();
+ out = new FileOutputStream( file );
+ props.store( out, "MAVEN-CORE-IT-LOG" );
+ }
+ finally
+ {
+ if ( out != null )
+ {
+ try
+ {
+ out.close();
+ }
+ catch ( IOException e )
+ {
+ // just ignore
+ }
+ }
+ }
+ }
+
+}
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
new file mode 100644
index 0000000000..fe797405c0
--- /dev/null
+++ b/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/ExpressionUtilTest.java
@@ -0,0 +1,122 @@
+package org.apache.maven.plugin.coreit;
+
+/*
+ * 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.
+ */
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+/**
+ * @author Benjamin Bentmann
+ * @version $Id$
+ */
+public class ExpressionUtilTest
+ extends TestCase
+{
+
+ public void testEvaluate()
+ {
+ Object array = new String[] { "one", "two", "three" };
+ Object list = Arrays.asList( new String[] { "0", "-1", "-2" } );
+ Object map = Collections.singletonMap( "some.key", "value" );
+ Object bean = new BeanTwo();
+
+ Map contexts = new HashMap();
+ contexts.put( "array", array );
+ contexts.put( "list", list );
+ 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 ) );
+
+ 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 ), 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( 1 ), ExpressionUtil.evaluate( "map/size", contexts ) );
+ assertEquals( "value", ExpressionUtil.evaluate( "map/some.key", contexts ) );
+ assertNull( ExpressionUtil.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 ) );
+ }
+
+ public void testGetProperty()
+ {
+ BeanOne bean1 = new BeanOne();
+ BeanTwo bean2 = new BeanTwo();
+
+ assertEquals( bean1.isFlag(), ExpressionUtil.getProperty( bean1, "flag" ) );
+ assertEquals( bean1.getProp(), ExpressionUtil.getProperty( bean1, "prop" ) );
+ assertEquals( bean1.get( "get" ), ExpressionUtil.getProperty( bean1, "get" ) );
+
+ assertNull( ExpressionUtil.getProperty( bean2, "invalid" ) );
+ assertEquals( bean2.field, ExpressionUtil.getProperty( bean2, "field" ) );
+ assertSame( bean2.bean, ExpressionUtil.getProperty( bean2, "bean" ) );
+
+ assertEquals( new Integer( 0 ), ExpressionUtil.getProperty( new String[0], "length" ) );
+ }
+
+ public static class BeanOne
+ {
+ public String isFlag()
+ {
+ return "flag";
+ }
+
+ public String getProp()
+ {
+ return "prop";
+ }
+
+ public String get( String arg )
+ {
+ return arg;
+ }
+ }
+
+ public static class BeanTwo
+ {
+ public String field = "field";
+
+ public BeanOne bean = new BeanOne();
+
+ }
+}
diff --git a/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/PropertyUtilTest.java b/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/PropertyUtilTest.java
new file mode 100644
index 0000000000..ac0f5b2e79
--- /dev/null
+++ b/its/core-it-support/core-it-plugins/maven-it-plugin-expression/src/test/java/org/apache/maven/plugin/coreit/PropertyUtilTest.java
@@ -0,0 +1,130 @@
+package org.apache.maven.plugin.coreit;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Properties;
+
+import junit.framework.TestCase;
+
+/**
+ * @author Benjamin Bentmann
+ * @version $Id$
+ */
+public class PropertyUtilTest
+ extends TestCase
+{
+
+ public void testStoreScalar()
+ {
+ Properties props = new Properties();
+ PropertyUtil.store( props, "null", null );
+ PropertyUtil.store( props, "string", "str" );
+ PropertyUtil.store( props, "boolean", Boolean.TRUE );
+ PropertyUtil.store( props, "int", new Integer( 7 ) );
+ PropertyUtil.store( props, "file", new File( "pom.xml" ) );
+
+ assertNull( props.get( "null" ) );
+ assertEquals( "str", props.get( "string" ) );
+ assertEquals( "true", props.get( "boolean" ) );
+ assertEquals( "7", props.get( "int" ) );
+ assertEquals( "pom.xml", props.get( "file" ) );
+ assertEquals( 4, props.size() );
+ }
+
+ public void testStoreArray()
+ {
+ Properties props = new Properties();
+ PropertyUtil.store( props, "arr", new String[] { "one", "two" } );
+
+ assertEquals( "2", props.get( "arr" ) );
+ assertEquals( "one", props.get( "arr.0" ) );
+ assertEquals( "two", props.get( "arr.1" ) );
+ assertEquals( 3, props.size() );
+ }
+
+ public void testStoreList()
+ {
+ Properties props = new Properties();
+ PropertyUtil.store( props, "arr", Arrays.asList( new String[] { "one", "two" } ) );
+
+ assertEquals( "2", props.get( "arr" ) );
+ assertEquals( "one", props.get( "arr.0" ) );
+ assertEquals( "two", props.get( "arr.1" ) );
+ assertEquals( 3, props.size() );
+ }
+
+ public void testStoreMap()
+ {
+ Properties props = new Properties();
+ PropertyUtil.store( props, "map", Collections.singletonMap( "key", "value" ) );
+
+ assertEquals( "1", props.get( "map" ) );
+ assertEquals( "value", props.get( "map.key" ) );
+ assertEquals( 2, props.size() );
+ }
+
+ public void testStoreBean()
+ {
+ Properties props = new Properties();
+ PropertyUtil.store( props, "bean", new Bean() );
+
+ assertEquals( "name", props.get( "bean.name" ) );
+ assertEquals( "false", props.get( "bean.enabled" ) );
+ assertEquals( 2, props.size() );
+ }
+
+ public void testGetPropertyName()
+ {
+ assertEquals( "name", PropertyUtil.getPropertyName( "getName" ) );
+ assertEquals( "enabled", PropertyUtil.getPropertyName( "isEnabled" ) );
+ }
+
+ public static class Bean
+ {
+ public String getName()
+ {
+ return "name";
+ }
+
+ public boolean isEnabled()
+ {
+ return false;
+ }
+
+ public String toString()
+ {
+ return "excluded";
+ }
+
+ public Object getUntypedReturnValue()
+ {
+ return "excluded";
+ }
+
+ public Bean getCyclicReference()
+ {
+ return this;
+ }
+ }
+
+}
diff --git a/its/core-it-support/core-it-plugins/pom.xml b/its/core-it-support/core-it-plugins/pom.xml
index aa567b35de..bc3a828c00 100644
--- a/its/core-it-support/core-it-plugins/pom.xml
+++ b/its/core-it-support/core-it-plugins/pom.xml
@@ -39,6 +39,7 @@ under the License.