This is a utility class used by selectors and DirectoryScanner. The
@@ -452,6 +451,141 @@ static boolean matchAntPathPattern( String[] patDirs, String[] strDirs, boolean
return true;
}
+ static boolean matchAntPathPattern( char[][] patDirs, char[][] strDirs, boolean isCaseSensitive )
+ {
+ int patIdxStart = 0;
+ int patIdxEnd = patDirs.length - 1;
+ int strIdxStart = 0;
+ int strIdxEnd = strDirs.length - 1;
+
+ // up to first '**'
+ while ( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd )
+ {
+ char[] patDir = patDirs[patIdxStart];
+ if ( isDoubleStar( patDir ) )
+ {
+ break;
+ }
+ if ( !match( patDir, strDirs[strIdxStart], isCaseSensitive ) )
+ {
+ return false;
+ }
+ patIdxStart++;
+ strIdxStart++;
+ }
+ if ( strIdxStart > strIdxEnd )
+ {
+ // String is exhausted
+ for ( int i = patIdxStart; i <= patIdxEnd; i++ )
+ {
+ if ( !isDoubleStar( patDirs[i] ) )
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ else
+ {
+ if ( patIdxStart > patIdxEnd )
+ {
+ // String not exhausted, but pattern is. Failure.
+ return false;
+ }
+ }
+
+ // up to last '**'
+ while ( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd )
+ {
+ char[] patDir = patDirs[patIdxEnd];
+ if ( isDoubleStar( patDir ) )
+ {
+ break;
+ }
+ if ( !match( patDir, strDirs[strIdxEnd], isCaseSensitive ) )
+ {
+ return false;
+ }
+ patIdxEnd--;
+ strIdxEnd--;
+ }
+ if ( strIdxStart > strIdxEnd )
+ {
+ // String is exhausted
+ for ( int i = patIdxStart; i <= patIdxEnd; i++ )
+ {
+ if ( !isDoubleStar( patDirs[i] ) )
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ while ( patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd )
+ {
+ int patIdxTmp = -1;
+ for ( int i = patIdxStart + 1; i <= patIdxEnd; i++ )
+ {
+ if ( isDoubleStar( patDirs[i] ) )
+ {
+ patIdxTmp = i;
+ break;
+ }
+ }
+ if ( patIdxTmp == patIdxStart + 1 )
+ {
+ // '**/**' situation, so skip one
+ patIdxStart++;
+ continue;
+ }
+ // Find the pattern between padIdxStart & padIdxTmp in str between
+ // strIdxStart & strIdxEnd
+ int patLength = ( patIdxTmp - patIdxStart - 1 );
+ int strLength = ( strIdxEnd - strIdxStart + 1 );
+ int foundIdx = -1;
+ strLoop:
+ for ( int i = 0; i <= strLength - patLength; i++ )
+ {
+ for ( int j = 0; j < patLength; j++ )
+ {
+ char[] subPat = patDirs[patIdxStart + j + 1];
+ char[] subStr = strDirs[strIdxStart + i + j];
+ if ( !match( subPat, subStr, isCaseSensitive ) )
+ {
+ continue strLoop;
+ }
+ }
+
+ foundIdx = strIdxStart + i;
+ break;
+ }
+
+ if ( foundIdx == -1 )
+ {
+ return false;
+ }
+
+ patIdxStart = patIdxTmp;
+ strIdxStart = foundIdx + patLength;
+ }
+
+ for ( int i = patIdxStart; i <= patIdxEnd; i++ )
+ {
+ if ( !isDoubleStar( patDirs[i] ) )
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private static boolean isDoubleStar( char[] patDir )
+ {
+ return patDir != null && patDir.length == 2 && patDir[0] == '*' && patDir[1] == '*';
+ }
+
/**
* Tests whether or not a string matches against a pattern.
* The pattern may contain two special characters: Unify quotes in a path for the Bourne Shell. Using simple dotted expressions to extract the values from an Object instance,
- * For example we might want to extract a value like: The implementation supports indexed, nested and mapped properties similar to the JSP way.
+ * Using simple dotted expressions to extract the values from an Object instance, For example we might want to extract a
+ * value like:
+ * The implementation supports indexed, nested and mapped properties similar to the JSP way.
+ * The implementation supports indexed, nested and mapped properties.
+ * The implementation supports indexed, nested and mapped properties.
+ * The implementation supports indexed, nested and mapped properties.
+ * The implementation supports indexed, nested and mapped properties.
+ *
@@ -489,6 +623,11 @@ public static boolean match( String pattern, String str, boolean isCaseSensitive
{
char[] patArr = pattern.toCharArray();
char[] strArr = str.toCharArray();
+ return match( patArr, strArr, isCaseSensitive);
+ }
+
+ public static boolean match( char[] patArr, char[] strArr, boolean isCaseSensitive )
+ {
int patIdxStart = 0;
int patIdxEnd = patArr.length - 1;
int strIdxStart = 0;
@@ -711,7 +850,7 @@ public static boolean isOutOfDate( File src, File target, int granularity )
*/
public static String removeWhitespace( String input )
{
- StringBuffer result = new StringBuffer();
+ StringBuilder result = new StringBuilder();
if ( input != null )
{
StringTokenizer st = new StringTokenizer( input );
diff --git a/src/main/java/org/codehaus/plexus/util/StringUtils.java b/src/main/java/org/codehaus/plexus/util/StringUtils.java
index 873cad09..846f491f 100644
--- a/src/main/java/org/codehaus/plexus/util/StringUtils.java
+++ b/src/main/java/org/codehaus/plexus/util/StringUtils.java
@@ -137,7 +137,7 @@ public static String trim( String str )
*/
public static String deleteWhitespace( String str )
{
- StringBuffer buffer = new StringBuffer();
+ StringBuilder buffer = new StringBuilder();
int sz = str.length();
for ( int i = 0; i < sz; i++ )
{
@@ -292,10 +292,10 @@ public static int indexOfAny( String str, String[] searchStrs )
// String's can't have a MAX_VALUEth index.
int ret = Integer.MAX_VALUE;
- int tmp = 0;
- for ( int i = 0; i < sz; i++ )
+ int tmp;
+ for ( String searchStr : searchStrs )
{
- tmp = str.indexOf( searchStrs[i] );
+ tmp = str.indexOf( searchStr );
if ( tmp == -1 )
{
continue;
@@ -326,12 +326,11 @@ public static int lastIndexOfAny( String str, String[] searchStrs )
{
return -1;
}
- int sz = searchStrs.length;
int ret = -1;
- int tmp = 0;
- for ( int i = 0; i < sz; i++ )
+ int tmp;
+ for ( String searchStr : searchStrs )
{
- tmp = str.lastIndexOf( searchStrs[i] );
+ tmp = str.lastIndexOf( searchStr );
if ( tmp > ret )
{
ret = tmp;
@@ -574,7 +573,7 @@ public static String[] split( String text, String separator )
*/
public static String[] split( String str, String separator, int max )
{
- StringTokenizer tok = null;
+ StringTokenizer tok;
if ( separator == null )
{
// Null separator means we're using StringTokenizer's default
@@ -594,7 +593,7 @@ public static String[] split( String str, String separator, int max )
String[] list = new String[listSize];
int i = 0;
- int lastTokenBegin = 0;
+ int lastTokenBegin;
int lastTokenEnd = 0;
while ( tok.hasMoreTokens() )
{
@@ -654,7 +653,7 @@ public static String join( Object[] array, String separator )
int arraySize = array.length;
int bufSize = ( arraySize == 0 ? 0 : ( array[0].toString().length() +
separator.length() ) * arraySize );
- StringBuffer buf = new StringBuffer( bufSize );
+ StringBuilder buf = new StringBuilder( bufSize );
for ( int i = 0; i < arraySize; i++ )
{
@@ -684,7 +683,7 @@ public static String join( Iterator> iterator, String separator )
{
separator = "";
}
- StringBuffer buf = new StringBuffer( 256 ); // Java default is 16, probably too small
+ StringBuilder buf = new StringBuilder( 256 ); // Java default is 16, probably too small
while ( iterator.hasNext() )
{
buf.append( iterator.next() );
@@ -801,11 +800,11 @@ public static String replace( String text, String repl, String with, int max )
return text;
}
- StringBuffer buf = new StringBuffer( text.length() );
- int start = 0, end = 0;
+ StringBuilder buf = new StringBuilder( text.length() );
+ int start = 0, end;
while ( ( end = text.indexOf( repl, start ) ) != -1 )
{
- buf.append( text.substring( start, end ) ).append( with );
+ buf.append( text, start, end ).append( with );
start = end + repl.length();
if ( --max == 0 )
@@ -813,7 +812,7 @@ public static String replace( String text, String repl, String with, int max )
break;
}
}
- buf.append( text.substring( start ) );
+ buf.append( text, start, text.length());
return buf.toString();
}
@@ -830,9 +829,9 @@ public static String replace( String text, String repl, String with, int max )
public static String overlayString( String text, String overlay, int start, int end )
{
return new StringBuffer( start + overlay.length() + text.length() - end + 1 )
- .append( text.substring( 0, start ) )
+ .append( text, 0, start )
.append( overlay )
- .append( text.substring( end ) )
+ .append( text, end, text.length() )
.toString();
}
@@ -1107,7 +1106,7 @@ public static String escape( String str )
// improved with code from cybertiger@cyberiantiger.org
// unicode from him, and defaul for < 32's.
int sz = str.length();
- StringBuffer buffer = new StringBuffer( 2 * sz );
+ StringBuilder buffer = new StringBuilder( 2 * sz );
for ( int i = 0; i < sz; i++ )
{
char ch = str.charAt( i );
@@ -1201,7 +1200,7 @@ else if ( ch < 32 )
*/
public static String repeat( String str, int repeat )
{
- StringBuffer buffer = new StringBuffer( repeat * str.length() );
+ StringBuilder buffer = new StringBuilder( repeat * str.length() );
for ( int i = 0; i < repeat; i++ )
{
buffer.append( str );
@@ -1478,7 +1477,7 @@ else if ( str.length() == 0 )
{
return new StringBuffer( str.length() )
.append( Character.toLowerCase( str.charAt( 0 ) ) )
- .append( str.substring( 1 ) )
+ .append( str, 1, str.length() )
.toString();
}
}
@@ -1504,9 +1503,9 @@ else if ( str.length() == 0 )
}
else
{
- return new StringBuffer( str.length() )
+ return new StringBuilder( str.length() )
.append( Character.toTitleCase( str.charAt( 0 ) ) )
- .append( str.substring( 1 ) )
+ .append( str, 1, str.length() )
.toString();
}
}
@@ -1529,11 +1528,11 @@ public static String swapCase( String str )
return null;
}
int sz = str.length();
- StringBuffer buffer = new StringBuffer( sz );
+ StringBuilder buffer = new StringBuilder( sz );
boolean whitespace = false;
- char ch = 0;
- char tmp = 0;
+ char ch;
+ char tmp;
for ( int i = 0; i < sz; i++ )
{
@@ -1586,7 +1585,7 @@ public static String capitaliseAllWords( String str )
return null;
}
int sz = str.length();
- StringBuffer buffer = new StringBuffer( sz );
+ StringBuilder buffer = new StringBuilder( sz );
boolean space = true;
for ( int i = 0; i < sz; i++ )
{
@@ -1627,7 +1626,7 @@ public static String uncapitaliseAllWords( String str )
return null;
}
int sz = str.length();
- StringBuffer buffer = new StringBuffer( sz );
+ StringBuilder buffer = new StringBuilder( sz );
boolean space = true;
for ( int i = 0; i < sz; i++ )
{
@@ -2161,7 +2160,7 @@ public static String removeAndHump( String data, String replaceThis )
{
String temp;
- StringBuffer out = new StringBuffer();
+ StringBuilder out = new StringBuilder();
temp = data;
@@ -2197,7 +2196,7 @@ public static String lowercaseFirstLetter( String data )
public static String addAndDeHump( String view )
{
- StringBuffer sb = new StringBuffer();
+ StringBuilder sb = new StringBuilder();
for ( int i = 0; i < view.length(); i++ )
{
@@ -2331,9 +2330,9 @@ else if ( !escaped.equals( source ) )
}
else
{
- for ( int i = 0; i < quotingTriggers.length; i++ )
+ for ( char quotingTrigger : quotingTriggers )
{
- if ( escaped.indexOf( quotingTriggers[i] ) > -1 )
+ if ( escaped.indexOf( quotingTrigger ) > -1 )
{
quote = true;
break;
@@ -2379,7 +2378,7 @@ public static String escape( String source, final char[] escapedChars, String es
System.arraycopy( escapedChars, 0, eqc, 0, escapedChars.length );
Arrays.sort( eqc );
- StringBuffer buffer = new StringBuffer( source.length() );
+ StringBuilder buffer = new StringBuilder( source.length() );
for ( int i = 0; i < source.length(); i++ )
{
@@ -2409,7 +2408,7 @@ public static String escape( String source, final char[] escapedChars, String es
*/
public static String removeDuplicateWhitespace( String s )
{
- StringBuffer result = new StringBuffer( );
+ StringBuilder result = new StringBuilder( );
int length = s.length();
boolean isPreviousWhiteSpace = false;
for (int i = 0; i < length; i++){
@@ -2466,7 +2465,7 @@ public static String unifyLineSeparators( String s, String ls )
int length = s.length();
- StringBuffer buffer = new StringBuffer( length );
+ StringBuilder buffer = new StringBuilder( length );
for ( int i = 0; i < length; i++ )
{
if ( s.charAt( i ) == '\r' )
diff --git a/src/main/java/org/codehaus/plexus/util/cli/CommandLineUtils.java b/src/main/java/org/codehaus/plexus/util/cli/CommandLineUtils.java
index 283785eb..fc73e515 100644
--- a/src/main/java/org/codehaus/plexus/util/cli/CommandLineUtils.java
+++ b/src/main/java/org/codehaus/plexus/util/cli/CommandLineUtils.java
@@ -16,12 +16,8 @@
* limitations under the License.
*/
-import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Locale;
import java.util.Map;
@@ -29,11 +25,8 @@
import java.util.StringTokenizer;
import java.util.Vector;
import org.codehaus.plexus.util.Os;
-import org.codehaus.plexus.util.ReaderFactory;
import org.codehaus.plexus.util.StringUtils;
-import org.codehaus.plexus.util.IOUtil;
-
/**
* @author Trygve Laugstøl
* @version $Id$
@@ -274,107 +267,18 @@ public static Properties getSystemEnvVars()
public static Properties getSystemEnvVars( boolean caseSensitive )
throws IOException
{
-
- // check if it's 1.5+ run
-
- Method getenvMethod = getEnvMethod();
- if ( getenvMethod != null )
- {
- try
- {
- return getEnvFromSystem( getenvMethod, caseSensitive );
- }
- catch ( IllegalAccessException e )
- {
- throw new IOException( e.getMessage() );
- }
- catch ( IllegalArgumentException e )
- {
- throw new IOException( e.getMessage() );
- }
- catch ( InvocationTargetException e )
- {
- throw new IOException( e.getMessage() );
- }
- }
-
- Process p = null;
-
- try
- {
- Properties envVars = new Properties();
-
- Runtime r = Runtime.getRuntime();
-
- //If this is windows set the shell to command.com or cmd.exe with correct arguments.
- boolean overriddenEncoding = false;
- if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
- {
- if ( Os.isFamily( Os.FAMILY_WIN9X ) )
- {
- p = r.exec( "command.com /c set" );
- }
- else
- {
- overriddenEncoding = true;
- // /U = change stdout encoding to UTF-16LE to avoid encoding inconsistency
- // between command-line/DOS and GUI/Windows, see PLXUTILS-124
- p = r.exec( "cmd.exe /U /c set" );
- }
- }
- else
- {
- p = r.exec( "env" );
- }
-
- Reader reader = overriddenEncoding
- ? new InputStreamReader( p.getInputStream(), ReaderFactory.UTF_16LE )
- : new InputStreamReader( p.getInputStream() );
- BufferedReader br = new BufferedReader( reader );
-
- String line;
-
- String lastKey = null;
- String lastVal = null;
-
- while ( ( line = br.readLine() ) != null )
- {
- int idx = line.indexOf( '=' );
-
- if ( idx > 0 )
- {
- lastKey = line.substring( 0, idx );
-
- if ( !caseSensitive )
- {
- lastKey = lastKey.toUpperCase( Locale.ENGLISH );
- }
-
- lastVal = line.substring( idx + 1 );
-
- envVars.setProperty( lastKey, lastVal );
- }
- else if ( lastKey != null )
- {
- lastVal += "\n" + line;
-
- envVars.setProperty( lastKey, lastVal );
- }
- }
-
- return envVars;
- }
- finally
+ Properties envVars = new Properties();
+ Map
- * BourneShell.unifyQuotes(null) = null
- * BourneShell.unifyQuotes("") = (empty)
- * BourneShell.unifyQuotes("/test/quotedpath'abc") = /test/quotedpath\'abc
- * BourneShell.unifyQuotes("/test/quoted path'abc") = "/test/quoted path'abc"
- * BourneShell.unifyQuotes("/test/quotedpath\"abc") = "/test/quotedpath\"abc"
- * BourneShell.unifyQuotes("/test/quoted path\"abc") = "/test/quoted path\"abc"
- * BourneShell.unifyQuotes("/test/quotedpath\"'abc") = "/test/quotedpath\"'abc"
- * BourneShell.unifyQuotes("/test/quoted path\"'abc") = "/test/quoted path\"'abc"
+ * BourneShell.quoteOneItem(null) = null
+ * BourneShell.quoteOneItem("") = ''
+ * BourneShell.quoteOneItem("/test/quotedpath'abc") = '/test/quotedpath'"'"'abc'
+ * BourneShell.quoteOneItem("/test/quoted path'abc") = '/test/quoted pat'"'"'habc'
+ * BourneShell.quoteOneItem("/test/quotedpath\"abc") = '/test/quotedpath"abc'
+ * BourneShell.quoteOneItem("/test/quoted path\"abc") = '/test/quoted path"abc'
+ * BourneShell.quoteOneItem("/test/quotedpath\"'abc") = '/test/quotedpath"'"'"'abc'
+ * BourneShell.quoteOneItem("/test/quoted path\"'abc") = '/test/quoted path"'"'"'abc'
*
*
* @param path not null path.
* @return the path unified correctly for the Bourne shell.
*/
- protected static String unifyQuotes( String path )
+ protected String quoteOneItem( String path, boolean isExecutable )
{
if ( path == null )
{
return null;
}
- if ( path.indexOf( " " ) == -1 && path.indexOf( "'" ) != -1 && path.indexOf( "\"" ) == -1 )
- {
- return StringUtils.escape( path );
- }
+ StringBuilder sb = new StringBuilder();
+ sb.append( "'" );
+ sb.append( path.replace( "'", "'\"'\"'" ) );
+ sb.append( "'" );
- return StringUtils.quoteAndEscape( path, '\"', BASH_QUOTING_TRIGGER_CHARS );
+ return sb.toString();
}
}
diff --git a/src/main/java/org/codehaus/plexus/util/cli/shell/CmdShell.java b/src/main/java/org/codehaus/plexus/util/cli/shell/CmdShell.java
index bbe44728..a96bb68a 100644
--- a/src/main/java/org/codehaus/plexus/util/cli/shell/CmdShell.java
+++ b/src/main/java/org/codehaus/plexus/util/cli/shell/CmdShell.java
@@ -79,7 +79,7 @@ public CmdShell()
*/
public Listproject.build.sourceDirectory
project.build.sourceDirectory
+ * (\\w+)\\[(\\d+)\\]
- */
- private static final Pattern INDEXED_PROPS = Pattern.compile( "(\\w+)\\[(\\d+)\\]" );
+ static final int EOF = -1;
- /**
- * Indexed properties pattern, ie (\\w+)\\((.+)\\)
- */
- private static final Pattern MAPPED_PROPS = Pattern.compile( "(\\w+)\\((.+)\\)" );
+ static final char PROPERTY_START = '.';
+
+ static final char INDEXED_START = '[';
+
+ static final char INDEXED_END = ']';
+
+ static final char MAPPED_START = '(';
+
+ static final char MAPPED_END = ')';
+
+ static class Tokenizer
+ {
+ final String expression;
+
+ int idx;
+
+ public Tokenizer( String expression )
+ {
+ this.expression = expression;
+ }
+
+ public int peekChar()
+ {
+ return idx < expression.length() ? expression.charAt( idx ) : EOF;
+ }
+
+ public int skipChar()
+ {
+ return idx < expression.length() ? expression.charAt( idx++ ) : EOF;
+ }
+
+ public String nextToken( char delimiter )
+ {
+ int start = idx;
+
+ while ( idx < expression.length() && delimiter != expression.charAt( idx ) )
+ {
+ idx++;
+ }
+
+ // delimiter MUST be present
+ if ( idx <= start || idx >= expression.length() )
+ {
+ return null;
+ }
+
+ return expression.substring( start, idx++ );
+ }
+
+ public String nextPropertyName()
+ {
+ final int start = idx;
+
+ while ( idx < expression.length() && Character.isJavaIdentifierPart( expression.charAt( idx ) ) )
+ {
+ idx++;
+ }
+
+ // property name does not require delimiter
+ if ( idx <= start || idx > expression.length() )
+ {
+ return null;
+ }
+
+ return expression.substring( start, idx );
+ }
+
+ public int getPosition()
+ {
+ return idx < expression.length() ? idx : EOF;
+ }
+
+ // to make tokenizer look pretty in debugger
+ @Override
+ public String toString()
+ {
+ return idx < expression.length() ? expression.substring( idx ) : "
*
(\\w+)\\[(\\d+)\\]
* pattern, i.e. "user.addresses[1].street"(\\w+)\\((.+)\\)
pattern, i.e. "user.addresses(myAddress).street"(\\w+)\\((.+)\\)
pattern, i.e.
+ * "user.addresses(myAddress).street"
- *
+ *
* @param expression not null expression
* @param root not null object
* @return the object defined by the expression
@@ -88,30 +164,26 @@ public static Object evaluate( String expression, Object root )
}
/**
- *
*
(\\w+)\\[(\\d+)\\]
* pattern, i.e. "user.addresses[1].street"(\\w+)\\((.+)\\)
pattern, i.e. "user.addresses(myAddress).street"(\\w+)\\((.+)\\)
pattern, i.e.
+ * "user.addresses(myAddress).street"
- *
+ *
* @param expression not null expression
* @param root not null object
* @return the object defined by the expression
* @throws Exception if any
*/
// TODO: don't throw Exception
- public static Object evaluate( String expression, Object root, boolean trimRootToken )
+ public static Object evaluate( final String expression, final Object root, final boolean trimRootToken )
throws Exception
{
- // if the root token refers to the supplied root object parameter, remove it.
- if ( trimRootToken )
- {
- expression = expression.substring( expression.indexOf( '.' ) + 1 );
- }
-
Object value = root;
// ----------------------------------------------------------------------
@@ -119,128 +191,166 @@ public static Object evaluate( String expression, Object root, boolean trimRootT
// MavenProject instance.
// ----------------------------------------------------------------------
- StringTokenizer parser = new StringTokenizer( expression, "." );
+ if ( StringUtils.isEmpty( expression ) || !Character.isJavaIdentifierStart( expression.charAt( 0 ) ) )
+ {
+ return null;
+ }
+
+ final Tokenizer tokenizer;
+ if ( trimRootToken )
+ {
+ tokenizer = new Tokenizer( expression );
+ tokenizer.nextPropertyName();
+ }
+ else
+ {
+ tokenizer = new Tokenizer( "." + expression );
+ }
- while ( parser.hasMoreTokens() )
+ int propertyPosition = tokenizer.getPosition();
+ while ( value != null && tokenizer.peekChar() != EOF )
{
- // if we have nothing, stop now
- if ( value == null )
+ switch ( tokenizer.skipChar() )
{
- return null;
+ case INDEXED_START:
+ value =
+ getIndexedValue( expression, propertyPosition, tokenizer.getPosition(), value,
+ tokenizer.nextToken( INDEXED_END ) );
+ break;
+ case MAPPED_START:
+ value =
+ getMappedValue( expression, propertyPosition, tokenizer.getPosition(), value,
+ tokenizer.nextToken( MAPPED_END ) );
+ break;
+ case PROPERTY_START:
+ propertyPosition = tokenizer.getPosition();
+ value = getPropertyValue( value, tokenizer.nextPropertyName() );
+ break;
+ default:
+ // could not parse expression
+ return null;
}
+ }
- String token = parser.nextToken();
+ return value;
+ }
+ private static Object getMappedValue( final String expression, final int from, final int to, final Object value,
+ final String key )
+ throws Exception
+ {
+ if ( value == null || key == null )
+ {
+ return null;
+ }
+
+ if ( value instanceof Map )
+ {
+ Object[] localParams = new Object[] { key };
ClassMap classMap = getClassMap( value.getClass() );
+ Method method = classMap.findMethod( "get", localParams );
+ return method.invoke( value, localParams );
+ }
+
+ final String message =
+ String.format( "The token '%s' at position '%d' refers to a java.util.Map, but the value seems is an instance of '%s'",
+ expression.subSequence( from, to ), from, value.getClass() );
+
+ throw new Exception( message );
+ }
- Method method;
- Object[] localParams = OBJECT_ARGS;
+ private static Object getIndexedValue( final String expression, final int from, final int to, final Object value,
+ final String indexStr )
+ throws Exception
+ {
+ try
+ {
+ int index = Integer.parseInt( indexStr );
- // do we have an indexed property?
- Matcher matcher = INDEXED_PROPS.matcher( token );
- if ( matcher.find() )
+ if ( value.getClass().isArray() )
{
- String methodBase = StringUtils.capitalizeFirstLetter( matcher.group( 1 ) );
- String methodName = "get" + methodBase;
- method = classMap.findMethod( methodName, CLASS_ARGS );
- value = method.invoke( value, OBJECT_ARGS );
- classMap = getClassMap( value.getClass() );
-
- if ( classMap.getCachedClass().isArray() )
- {
- value = Arrays.asList( (Object[]) value );
- classMap = getClassMap( value.getClass() );
- }
-
- if ( value instanceof List )
- {
- // use get method on List interface
- localParams = new Object[1];
- localParams[0] = Integer.valueOf( matcher.group( 2 ) );
- method = classMap.findMethod( "get", localParams );
- }
- else
- {
- throw new Exception( "The token '" + token
- + "' refers to a java.util.List or an array, but the value seems is an instance of '"
- + value.getClass() + "'." );
- }
+ return Array.get( value, index );
}
- else
+
+ if ( value instanceof List )
{
- // do we have a mapped property?
- matcher = MAPPED_PROPS.matcher( token );
- if ( matcher.find() )
- {
- String methodBase = StringUtils.capitalizeFirstLetter( matcher.group( 1 ) );
- String methodName = "get" + methodBase;
- method = classMap.findMethod( methodName, CLASS_ARGS );
- value = method.invoke( value, OBJECT_ARGS );
- classMap = getClassMap( value.getClass() );
-
- if ( value instanceof Map )
- {
- // use get method on List interface
- localParams = new Object[1];
- localParams[0] = matcher.group( 2 );
- method = classMap.findMethod( "get", localParams );
- }
- else
- {
- throw new Exception( "The token '" + token
- + "' refers to a java.util.Map, but the value seems is an instance of '"
- + value.getClass() + "'." );
- }
- }
- else
- {
- String methodBase = StringUtils.capitalizeFirstLetter( token );
- String methodName = "get" + methodBase;
- method = classMap.findMethod( methodName, CLASS_ARGS );
-
- if ( method == null )
- {
- // perhaps this is a boolean property??
- methodName = "is" + methodBase;
-
- method = classMap.findMethod( methodName, CLASS_ARGS );
- }
- }
+ ClassMap classMap = getClassMap( value.getClass() );
+ // use get method on List interface
+ Object[] localParams = new Object[] { index };
+ Method method = classMap.findMethod( "get", localParams );
+ return method.invoke( value, localParams );
}
-
- if ( method == null )
+ }
+ catch ( NumberFormatException e )
+ {
+ return null;
+ }
+ catch ( InvocationTargetException e )
+ {
+ // catch array index issues gracefully, otherwise release
+ if ( e.getCause() instanceof IndexOutOfBoundsException )
{
return null;
}
- try
- {
- value = method.invoke( value, localParams );
- }
- catch ( InvocationTargetException e )
- {
- // catch array index issues gracefully, otherwise release
- if ( e.getCause() instanceof IndexOutOfBoundsException )
- {
- return null;
- }
+ throw e;
+ }
- throw e;
- }
+ final String message =
+ String.format( "The token '%s' at position '%d' refers to a java.util.List or an array, but the value seems is an instance of '%s'",
+ expression.subSequence( from, to ), from, value.getClass() );
+
+ throw new Exception( message );
+ }
+
+ private static Object getPropertyValue( Object value, String property )
+ throws Exception
+ {
+ if ( value == null || property == null )
+ {
+ return null;
}
- return value;
+ ClassMap classMap = getClassMap( value.getClass() );
+ String methodBase = StringUtils.capitalizeFirstLetter( property );
+ String methodName = "get" + methodBase;
+ Method method = classMap.findMethod( methodName, CLASS_ARGS );
+
+ if ( method == null )
+ {
+ // perhaps this is a boolean property??
+ methodName = "is" + methodBase;
+
+ method = classMap.findMethod( methodName, CLASS_ARGS );
+ }
+
+ if ( method == null )
+ {
+ return null;
+ }
+
+ try
+ {
+ return method.invoke( value, OBJECT_ARGS );
+ }
+ catch ( InvocationTargetException e )
+ {
+ throw e;
+ }
}
- private static ClassMap getClassMap( Class clazz )
+ private static ClassMap getClassMap( Class> clazz )
{
- ClassMap classMap = (ClassMap) classMaps.get( clazz );
- if ( classMap == null )
+ WeakReference