move utils to plexus-utils

git-svn-id: https://svn.apache.org/repos/asf/maven/components/trunk@164078 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Brett Leslie Porter 2005-04-21 16:16:25 +00:00
parent 082bda52a0
commit bc738a21f4
10 changed files with 7 additions and 1273 deletions

View File

@ -18,10 +18,10 @@ package org.apache.maven.plugin;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.project.path.PathTranslator;
import org.apache.maven.util.introspection.ReflectionValueExtractor;
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.util.introspection.ReflectionValueExtractor;
import java.io.File;

View File

@ -37,7 +37,6 @@ import org.apache.maven.model.Plugin;
import org.apache.maven.model.PluginManagement;
import org.apache.maven.model.Reports;
import org.apache.maven.model.Scm;
import org.apache.maven.util.Xpp3DomUtils;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import java.io.File;
@ -739,8 +738,8 @@ public class MavenProject
Xpp3Dom goalConfiguration = (Xpp3Dom) goal.getConfiguration();
if ( goalConfiguration != null )
{
Xpp3Dom newDom = Xpp3DomUtils.copyXpp3Dom( goalConfiguration );
dom = Xpp3DomUtils.mergeXpp3Dom( newDom, dom );
Xpp3Dom newDom = new Xpp3Dom( goalConfiguration );
dom = Xpp3Dom.mergeXpp3Dom( newDom, dom );
}
break;
}

View File

@ -26,7 +26,6 @@ import org.apache.maven.model.Plugin;
import org.apache.maven.model.PluginManagement;
import org.apache.maven.model.Repository;
import org.apache.maven.model.Scm;
import org.apache.maven.util.Xpp3DomUtils;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.xml.Xpp3Dom;
@ -273,7 +272,7 @@ public class DefaultModelInheritanceAssembler
{
Xpp3Dom childDom = (Xpp3Dom) childGoal.getConfiguration();
Xpp3Dom parentDom = (Xpp3Dom) parentGoal.getConfiguration();
childGoal.setConfiguration( Xpp3DomUtils.mergeXpp3Dom( childDom, parentDom ) );
childGoal.setConfiguration( Xpp3Dom.mergeXpp3Dom( childDom, parentDom ) );
}
}
}

View File

@ -22,7 +22,6 @@ import org.apache.maven.model.Goal;
import org.apache.maven.model.Model;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.PluginManagement;
import org.apache.maven.util.Xpp3DomUtils;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import java.util.ArrayList;
@ -123,7 +122,7 @@ public class DefaultModelDefaultsInjector
Xpp3Dom goalConfiguration = (Xpp3Dom) localGoal.getConfiguration();
Xpp3Dom defaultGoalConfiguration = (Xpp3Dom) defaultGoal.getConfiguration();
localGoal.setConfiguration(
Xpp3DomUtils.mergeXpp3Dom( goalConfiguration, defaultGoalConfiguration ) );
Xpp3Dom.mergeXpp3Dom( goalConfiguration, defaultGoalConfiguration ) );
}
}
}
@ -132,7 +131,7 @@ public class DefaultModelDefaultsInjector
Xpp3Dom pluginConfiguration = (Xpp3Dom) plugin.getConfiguration();
Xpp3Dom defaultPluginConfiguration = (Xpp3Dom) def.getConfiguration();
plugin.setConfiguration( Xpp3DomUtils.mergeXpp3Dom( pluginConfiguration, defaultPluginConfiguration ) );
plugin.setConfiguration( Xpp3Dom.mergeXpp3Dom( pluginConfiguration, defaultPluginConfiguration ) );
}
private void injectDependencyDefaults( List dependencies, DependencyManagement dependencyManagement )

View File

@ -19,10 +19,10 @@ package org.apache.maven.project.interpolation;
import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
import org.apache.maven.util.introspection.ReflectionValueExtractor;
import org.codehaus.plexus.logging.AbstractLogEnabled;
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.introspection.ReflectionValueExtractor;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import java.io.IOException;

View File

@ -1,85 +0,0 @@
package org.apache.maven.util;
import org.codehaus.plexus.util.xml.Xpp3Dom;
/*
* Copyright 2001-2005 The Apache Software Foundation.
*
* Licensed 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.
*/
/**
* TODO: describe
*
* @author <a href="mailto:brett@apache.org">Brett Porter</a>
* @version $Id$
*/
public class Xpp3DomUtils
{
private static void mergeIntoXpp3Dom( Xpp3Dom dominant, Xpp3Dom recessive )
{
// TODO: how to mergeXpp3Dom lists rather than override?
// TODO: share this as some sort of assembler, implement a walk interface?
if ( recessive == null )
{
return;
}
Xpp3Dom[] children = recessive.getChildren();
for ( int i = 0; i < children.length; i++ )
{
Xpp3Dom child = children[i];
Xpp3Dom childDom = dominant.getChild( child.getName() );
if ( childDom != null )
{
mergeIntoXpp3Dom( childDom, child );
}
else
{
dominant.addChild( copyXpp3Dom( child ) );
}
}
}
public static Xpp3Dom copyXpp3Dom( Xpp3Dom src )
{
// TODO: into Xpp3Dom as a copy constructor
Xpp3Dom dom = new Xpp3Dom( src.getName() );
dom.setValue( src.getValue() );
String[] attributeNames = src.getAttributeNames();
for ( int i = 0; i < attributeNames.length; i++ )
{
String attributeName = attributeNames[i];
dom.setAttribute( attributeName, src.getAttribute( attributeName ) );
}
Xpp3Dom[] children = src.getChildren();
for ( int i = 0; i < children.length; i++ )
{
dom.addChild( copyXpp3Dom( children[i] ) );
}
return dom;
}
public static Xpp3Dom mergeXpp3Dom( Xpp3Dom dominant, Xpp3Dom recessive )
{
if ( dominant != null )
{
mergeIntoXpp3Dom( dominant, recessive );
return dominant;
}
return recessive;
}
}

View File

@ -1,520 +0,0 @@
package org.apache.maven.util.introspection;
/* ====================================================================
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed 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.Method;
import java.lang.reflect.Modifier;
import java.util.Hashtable;
import java.util.Map;
/**
* A cache of introspection information for a specific class instance.
* Keys {@link java.lang.Method} objects by a concatenation of the
* method name and the names of classes that make up the parameters.
*
* @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
* @author <a href="mailto:bob@werken.com">Bob McWhirter</a>
* @author <a href="mailto:szegedia@freemail.hu">Attila Szegedi</a>
* @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
* @version $Id$
*/
public class ClassMap
{
private static final class CacheMiss
{
}
private static final CacheMiss CACHE_MISS = new CacheMiss();
private static final Object OBJECT = new Object();
/**
* Class passed into the constructor used to as
* the basis for the Method map.
*/
private Class clazz;
/**
* Cache of Methods, or CACHE_MISS, keyed by method
* name and actual arguments used to find it.
*/
private Map methodCache = new Hashtable();
private MethodMap methodMap = new MethodMap();
/**
* Standard constructor
*/
public ClassMap( Class clazz )
{
this.clazz = clazz;
populateMethodCache();
}
/**
* @return the class object whose methods are cached by this map.
*/
Class getCachedClass()
{
return clazz;
}
/**
* Find a Method using the methodKey
* provided.
* <p/>
* Look in the methodMap for an entry. If found,
* it'll either be a CACHE_MISS, in which case we
* simply give up, or it'll be a Method, in which
* case, we return it.
* <p/>
* If nothing is found, then we must actually go
* and introspect the method from the MethodMap.
*/
public Method findMethod( String name, Object[] params )
throws MethodMap.AmbiguousException
{
String methodKey = makeMethodKey( name, params );
Object cacheEntry = methodCache.get( methodKey );
if ( cacheEntry == CACHE_MISS )
{
return null;
}
if ( cacheEntry == null )
{
try
{
cacheEntry = methodMap.find( name,
params );
}
catch ( MethodMap.AmbiguousException ae )
{
/*
* that's a miss :)
*/
methodCache.put( methodKey,
CACHE_MISS );
throw ae;
}
if ( cacheEntry == null )
{
methodCache.put( methodKey,
CACHE_MISS );
}
else
{
methodCache.put( methodKey,
cacheEntry );
}
}
// Yes, this might just be null.
return (Method) cacheEntry;
}
/**
* Populate the Map of direct hits. These
* are taken from all the public methods
* that our class provides.
*/
private void populateMethodCache()
{
StringBuffer methodKey;
/*
* get all publicly accessible methods
*/
Method[] methods = getAccessibleMethods( clazz );
/*
* map and cache them
*/
for ( int i = 0; i < methods.length; i++ )
{
Method method = methods[i];
/*
* now get the 'public method', the method declared by a
* public interface or class. (because the actual implementing
* class may be a facade...
*/
Method publicMethod = getPublicMethod( method );
/*
* it is entirely possible that there is no public method for
* the methods of this class (i.e. in the facade, a method
* that isn't on any of the interfaces or superclass
* in which case, ignore it. Otherwise, map and cache
*/
if ( publicMethod != null )
{
methodMap.add( publicMethod );
methodCache.put( makeMethodKey( publicMethod ), publicMethod );
}
}
}
/**
* Make a methodKey for the given method using
* the concatenation of the name and the
* types of the method parameters.
*/
private String makeMethodKey( Method method )
{
Class[] parameterTypes = method.getParameterTypes();
StringBuffer methodKey = new StringBuffer( method.getName() );
for ( int j = 0; j < parameterTypes.length; j++ )
{
/*
* If the argument type is primitive then we want
* to convert our primitive type signature to the
* corresponding Object type so introspection for
* methods with primitive types will work correctly.
*/
if ( parameterTypes[j].isPrimitive() )
{
if ( parameterTypes[j].equals( Boolean.TYPE ) )
methodKey.append( "java.lang.Boolean" );
else if ( parameterTypes[j].equals( Byte.TYPE ) )
methodKey.append( "java.lang.Byte" );
else if ( parameterTypes[j].equals( Character.TYPE ) )
methodKey.append( "java.lang.Character" );
else if ( parameterTypes[j].equals( Double.TYPE ) )
methodKey.append( "java.lang.Double" );
else if ( parameterTypes[j].equals( Float.TYPE ) )
methodKey.append( "java.lang.Float" );
else if ( parameterTypes[j].equals( Integer.TYPE ) )
methodKey.append( "java.lang.Integer" );
else if ( parameterTypes[j].equals( Long.TYPE ) )
methodKey.append( "java.lang.Long" );
else if ( parameterTypes[j].equals( Short.TYPE ) )
methodKey.append( "java.lang.Short" );
}
else
{
methodKey.append( parameterTypes[j].getName() );
}
}
return methodKey.toString();
}
private static String makeMethodKey( String method, Object[] params )
{
StringBuffer methodKey = new StringBuffer().append( method );
for ( int j = 0; j < params.length; j++ )
{
Object arg = params[j];
if ( arg == null )
{
arg = OBJECT;
}
methodKey.append( arg.getClass().getName() );
}
return methodKey.toString();
}
/**
* Retrieves public methods for a class. In case the class is not
* public, retrieves methods with same signature as its public methods
* from public superclasses and interfaces (if they exist). Basically
* upcasts every method to the nearest acccessible method.
*/
private static Method[] getAccessibleMethods( Class clazz )
{
Method[] methods = clazz.getMethods();
/*
* Short circuit for the (hopefully) majority of cases where the
* clazz is public
*/
if ( Modifier.isPublic( clazz.getModifiers() ) )
{
return methods;
}
/*
* No luck - the class is not public, so we're going the longer way.
*/
MethodInfo[] methodInfos = new MethodInfo[methods.length];
for ( int i = methods.length; i-- > 0; )
{
methodInfos[i] = new MethodInfo( methods[i] );
}
int upcastCount = getAccessibleMethods( clazz, methodInfos, 0 );
/*
* Reallocate array in case some method had no accessible counterpart.
*/
if ( upcastCount < methods.length )
{
methods = new Method[upcastCount];
}
int j = 0;
for ( int i = 0; i < methodInfos.length; ++i )
{
MethodInfo methodInfo = methodInfos[i];
if ( methodInfo.upcast )
{
methods[j++] = methodInfo.method;
}
}
return methods;
}
/**
* Recursively finds a match for each method, starting with the class, and then
* searching the superclass and interfaces.
*
* @param clazz Class to check
* @param methodInfos array of methods we are searching to match
* @param upcastCount current number of methods we have matched
* @return count of matched methods
*/
private static int getAccessibleMethods( Class clazz, MethodInfo[] methodInfos, int upcastCount )
{
int l = methodInfos.length;
/*
* if this class is public, then check each of the currently
* 'non-upcasted' methods to see if we have a match
*/
if ( Modifier.isPublic( clazz.getModifiers() ) )
{
for ( int i = 0; i < l && upcastCount < l; ++i )
{
try
{
MethodInfo methodInfo = methodInfos[i];
if ( !methodInfo.upcast )
{
methodInfo.tryUpcasting( clazz );
upcastCount++;
}
}
catch ( NoSuchMethodException e )
{
/*
* Intentionally ignored - it means
* it wasn't found in the current class
*/
}
}
/*
* Short circuit if all methods were upcast
*/
if ( upcastCount == l )
{
return upcastCount;
}
}
/*
* Examine superclass
*/
Class superclazz = clazz.getSuperclass();
if ( superclazz != null )
{
upcastCount = getAccessibleMethods( superclazz, methodInfos, upcastCount );
/*
* Short circuit if all methods were upcast
*/
if ( upcastCount == l )
{
return upcastCount;
}
}
/*
* Examine interfaces. Note we do it even if superclazz == null.
* This is redundant as currently java.lang.Object does not implement
* any interfaces, however nothing guarantees it will not in future.
*/
Class[] interfaces = clazz.getInterfaces();
for ( int i = interfaces.length; i-- > 0; )
{
upcastCount = getAccessibleMethods( interfaces[i], methodInfos, upcastCount );
/*
* Short circuit if all methods were upcast
*/
if ( upcastCount == l )
{
return upcastCount;
}
}
return upcastCount;
}
/**
* For a given method, retrieves its publicly accessible counterpart.
* This method will look for a method with same name
* and signature declared in a public superclass or implemented interface of this
* method's declaring class. This counterpart method is publicly callable.
*
* @param method a method whose publicly callable counterpart is requested.
* @return the publicly callable counterpart method. Note that if the parameter
* method is itself declared by a public class, this method is an identity
* function.
*/
public static Method getPublicMethod( Method method )
{
Class clazz = method.getDeclaringClass();
/*
* Short circuit for (hopefully the majority of) cases where the declaring
* class is public.
*/
if ( ( clazz.getModifiers() & Modifier.PUBLIC ) != 0 )
{
return method;
}
return getPublicMethod( clazz, method.getName(), method.getParameterTypes() );
}
/**
* Looks up the method with specified name and signature in the first public
* superclass or implemented interface of the class.
*
* @param class the class whose method is sought
* @param name the name of the method
* @param paramTypes the classes of method parameters
*/
private static Method getPublicMethod( Class clazz, String name, Class[] paramTypes )
{
/*
* if this class is public, then try to get it
*/
if ( ( clazz.getModifiers() & Modifier.PUBLIC ) != 0 )
{
try
{
return clazz.getMethod( name, paramTypes );
}
catch ( NoSuchMethodException e )
{
/*
* If the class does not have the method, then neither its
* superclass nor any of its interfaces has it so quickly return
* null.
*/
return null;
}
}
/*
* try the superclass
*/
Class superclazz = clazz.getSuperclass();
if ( superclazz != null )
{
Method superclazzMethod = getPublicMethod( superclazz, name, paramTypes );
if ( superclazzMethod != null )
{
return superclazzMethod;
}
}
/*
* and interfaces
*/
Class[] interfaces = clazz.getInterfaces();
for ( int i = 0; i < interfaces.length; ++i )
{
Method interfaceMethod = getPublicMethod( interfaces[i], name, paramTypes );
if ( interfaceMethod != null )
{
return interfaceMethod;
}
}
return null;
}
/**
* Used for the iterative discovery process for public methods.
*/
private static final class MethodInfo
{
Method method;
String name;
Class[] parameterTypes;
boolean upcast;
MethodInfo( Method method )
{
this.method = null;
name = method.getName();
parameterTypes = method.getParameterTypes();
upcast = false;
}
void tryUpcasting( Class clazz )
throws NoSuchMethodException
{
method = clazz.getMethod( name, parameterTypes );
name = null;
parameterTypes = null;
upcast = true;
}
}
}

View File

@ -1,465 +0,0 @@
package org.apache.maven.util.introspection;
/* ====================================================================
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed 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.Method;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
*
* @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
* @author <a href="mailto:bob@werken.com">Bob McWhirter</a>
* @author <a href="mailto:Christoph.Reck@dlr.de">Christoph Reck</a>
* @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
* @author <a href="mailto:szegedia@freemail.hu">Attila Szegedi</a>
* @version $Id$
*/
public class MethodMap
{
private static final int MORE_SPECIFIC = 0;
private static final int LESS_SPECIFIC = 1;
private static final int INCOMPARABLE = 2;
/**
* Keep track of all methods with the same name.
*/
Map methodByNameMap = new Hashtable();
/**
* Add a method to a list of methods by name.
* For a particular class we are keeping track
* of all the methods with the same name.
*/
public void add(Method method)
{
String methodName = method.getName();
List l = get( methodName );
if ( l == null)
{
l = new ArrayList();
methodByNameMap.put(methodName, l);
}
l.add(method);
return;
}
/**
* Return a list of methods with the same name.
*
* @param String key
* @return List list of methods
*/
public List get(String key)
{
return (List) methodByNameMap.get(key);
}
/**
* <p>
* Find a method. Attempts to find the
* most specific applicable method using the
* algorithm described in the JLS section
* 15.12.2 (with the exception that it can't
* distinguish a primitive type argument from
* an object type argument, since in reflection
* primitive type arguments are represented by
* their object counterparts, so for an argument of
* type (say) java.lang.Integer, it will not be able
* to decide between a method that takes int and a
* method that takes java.lang.Integer as a parameter.
* </p>
*
* <p>
* This turns out to be a relatively rare case
* where this is needed - however, functionality
* like this is needed.
* </p>
*
* @param methodName name of method
* @param args the actual arguments with which the method is called
* @return the most specific applicable method, or null if no
* method is applicable.
* @throws AmbiguousException if there is more than one maximally
* specific applicable method
*/
public Method find(String methodName, Object[] args)
throws AmbiguousException
{
List methodList = get(methodName);
if (methodList == null)
{
return null;
}
int l = args.length;
Class[] classes = new Class[l];
for(int i = 0; i < l; ++i)
{
Object arg = args[i];
/*
* if we are careful down below, a null argument goes in there
* so we can know that the null was passed to the method
*/
classes[i] =
arg == null ? null : arg.getClass();
}
return getMostSpecific(methodList, classes);
}
/**
* simple distinguishable exception, used when
* we run across ambiguous overloading
*/
public static class AmbiguousException extends Exception
{
}
private static Method getMostSpecific(List methods, Class[] classes)
throws AmbiguousException
{
LinkedList applicables = getApplicables(methods, classes);
if(applicables.isEmpty())
{
return null;
}
if(applicables.size() == 1)
{
return (Method)applicables.getFirst();
}
/*
* This list will contain the maximally specific methods. Hopefully at
* the end of the below loop, the list will contain exactly one method,
* (the most specific method) otherwise we have ambiguity.
*/
LinkedList maximals = new LinkedList();
for (Iterator applicable = applicables.iterator();
applicable.hasNext();)
{
Method app = (Method) applicable.next();
Class[] appArgs = app.getParameterTypes();
boolean lessSpecific = false;
for (Iterator maximal = maximals.iterator();
!lessSpecific && maximal.hasNext();)
{
Method max = (Method) maximal.next();
switch(moreSpecific(appArgs, max.getParameterTypes()))
{
case MORE_SPECIFIC:
{
/*
* This method is more specific than the previously
* known maximally specific, so remove the old maximum.
*/
maximal.remove();
break;
}
case LESS_SPECIFIC:
{
/*
* This method is less specific than some of the
* currently known maximally specific methods, so we
* won't add it into the set of maximally specific
* methods
*/
lessSpecific = true;
break;
}
}
}
if(!lessSpecific)
{
maximals.addLast(app);
}
}
if(maximals.size() > 1)
{
// We have more than one maximally specific method
throw new AmbiguousException();
}
return (Method)maximals.getFirst();
}
/**
* Determines which method signature (represented by a class array) is more
* specific. This defines a partial ordering on the method signatures.
* @param c1 first signature to compare
* @param c2 second signature to compare
* @return MORE_SPECIFIC if c1 is more specific than c2, LESS_SPECIFIC if
* c1 is less specific than c2, INCOMPARABLE if they are incomparable.
*/
private static int moreSpecific(Class[] c1, Class[] c2)
{
boolean c1MoreSpecific = false;
boolean c2MoreSpecific = false;
for(int i = 0; i < c1.length; ++i)
{
if(c1[i] != c2[i])
{
c1MoreSpecific =
c1MoreSpecific ||
isStrictMethodInvocationConvertible(c2[i], c1[i]);
c2MoreSpecific =
c2MoreSpecific ||
isStrictMethodInvocationConvertible(c1[i], c2[i]);
}
}
if(c1MoreSpecific)
{
if(c2MoreSpecific)
{
/*
* Incomparable due to cross-assignable arguments (i.e.
* foo(String, Object) vs. foo(Object, String))
*/
return INCOMPARABLE;
}
return MORE_SPECIFIC;
}
if(c2MoreSpecific)
{
return LESS_SPECIFIC;
}
/*
* Incomparable due to non-related arguments (i.e.
* foo(Runnable) vs. foo(Serializable))
*/
return INCOMPARABLE;
}
/**
* Returns all methods that are applicable to actual argument types.
* @param methods list of all candidate methods
* @param classes the actual types of the arguments
* @return a list that contains only applicable methods (number of
* formal and actual arguments matches, and argument types are assignable
* to formal types through a method invocation conversion).
*/
private static LinkedList getApplicables(List methods, Class[] classes)
{
LinkedList list = new LinkedList();
for (Iterator imethod = methods.iterator(); imethod.hasNext();)
{
Method method = (Method) imethod.next();
if(isApplicable(method, classes))
{
list.add(method);
}
}
return list;
}
/**
* Returns true if the supplied method is applicable to actual
* argument types.
*/
private static boolean isApplicable(Method method, Class[] classes)
{
Class[] methodArgs = method.getParameterTypes();
if(methodArgs.length != classes.length)
{
return false;
}
for(int i = 0; i < classes.length; ++i)
{
if(!isMethodInvocationConvertible(methodArgs[i], classes[i]))
{
return false;
}
}
return true;
}
/**
* Determines whether a type represented by a class object is
* convertible to another type represented by a class object using a
* method invocation conversion, treating object types of primitive
* types as if they were primitive types (that is, a Boolean actual
* parameter type matches boolean primitive formal type). This behavior
* is because this method is used to determine applicable methods for
* an actual parameter list, and primitive types are represented by
* their object duals in reflective method calls.
*
* @param formal the formal parameter type to which the actual
* parameter type should be convertible
* @param actual the actual parameter type.
* @return true if either formal type is assignable from actual type,
* or formal is a primitive type and actual is its corresponding object
* type or an object type of a primitive type that can be converted to
* the formal type.
*/
private static boolean isMethodInvocationConvertible(Class formal,
Class actual)
{
/*
* if it's a null, it means the arg was null
*/
if (actual == null && !formal.isPrimitive())
{
return true;
}
/*
* Check for identity or widening reference conversion
*/
if (actual != null && formal.isAssignableFrom(actual))
{
return true;
}
/*
* Check for boxing with widening primitive conversion. Note that
* actual parameters are never primitives.
*/
if (formal.isPrimitive())
{
if(formal == Boolean.TYPE && actual == Boolean.class)
return true;
if(formal == Character.TYPE && actual == Character.class)
return true;
if(formal == Byte.TYPE && actual == Byte.class)
return true;
if(formal == Short.TYPE &&
(actual == Short.class || actual == Byte.class))
return true;
if(formal == Integer.TYPE &&
(actual == Integer.class || actual == Short.class ||
actual == Byte.class))
return true;
if(formal == Long.TYPE &&
(actual == Long.class || actual == Integer.class ||
actual == Short.class || actual == Byte.class))
return true;
if(formal == Float.TYPE &&
(actual == Float.class || actual == Long.class ||
actual == Integer.class || actual == Short.class ||
actual == Byte.class))
return true;
if(formal == Double.TYPE &&
(actual == Double.class || actual == Float.class ||
actual == Long.class || actual == Integer.class ||
actual == Short.class || actual == Byte.class))
return true;
}
return false;
}
/**
* Determines whether a type represented by a class object is
* convertible to another type represented by a class object using a
* method invocation conversion, without matching object and primitive
* types. This method is used to determine the more specific type when
* comparing signatures of methods.
*
* @param formal the formal parameter type to which the actual
* parameter type should be convertible
* @param actual the actual parameter type.
* @return true if either formal type is assignable from actual type,
* or formal and actual are both primitive types and actual can be
* subject to widening conversion to formal.
*/
private static boolean isStrictMethodInvocationConvertible(Class formal,
Class actual)
{
/*
* we shouldn't get a null into, but if so
*/
if (actual == null && !formal.isPrimitive())
{
return true;
}
/*
* Check for identity or widening reference conversion
*/
if(formal.isAssignableFrom(actual))
{
return true;
}
/*
* Check for widening primitive conversion.
*/
if(formal.isPrimitive())
{
if(formal == Short.TYPE && (actual == Byte.TYPE))
return true;
if(formal == Integer.TYPE &&
(actual == Short.TYPE || actual == Byte.TYPE))
return true;
if(formal == Long.TYPE &&
(actual == Integer.TYPE || actual == Short.TYPE ||
actual == Byte.TYPE))
return true;
if(formal == Float.TYPE &&
(actual == Long.TYPE || actual == Integer.TYPE ||
actual == Short.TYPE || actual == Byte.TYPE))
return true;
if(formal == Double.TYPE &&
(actual == Float.TYPE || actual == Long.TYPE ||
actual == Integer.TYPE || actual == Short.TYPE ||
actual == Byte.TYPE))
return true;
}
return false;
}
}

View File

@ -1,101 +0,0 @@
package org.apache.maven.util.introspection;
/*
* Copyright 2001-2005 The Apache Software Foundation.
*
* Licensed 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.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import org.codehaus.plexus.util.StringUtils;
/**
* Using simple dotted expressions extract the values from a MavenProject
* instance, For example we might want to extract a value like:
* project.build.sourceDirectory
*
* @author <a href="mailto:jason@maven.org">Jason van Zyl </a>
* @version $Id$
*/
public class ReflectionValueExtractor
{
private static Class[] args = new Class[ 0 ];
private static Object[] params = new Object[ 0 ];
private static ClassMap classMap;
private static Map classMaps = new HashMap();
private ReflectionValueExtractor()
{
}
// TODO: don't throw Exception
public static Object evaluate( String expression, Object root )
throws Exception
{
// ----------------------------------------------------------------------
// Remove the leading "project" token
// ----------------------------------------------------------------------
expression = expression.substring( expression.indexOf( '.' ) + 1 );
Object value = root;
// ----------------------------------------------------------------------
// Walk the dots and retrieve the ultimate value desired from the
// MavenProject instance.
// ----------------------------------------------------------------------
StringTokenizer parser = new StringTokenizer( expression, "." );
while ( parser.hasMoreTokens() )
{
String token = parser.nextToken();
classMap = getClassMap( value.getClass() );
String methodName = "get" + StringUtils.capitalizeFirstLetter( token );
Method method = classMap.findMethod( methodName, args );
if ( method == null )
{
return null;
}
value = method.invoke( value, params );
}
return value;
}
private static ClassMap getClassMap( Class clazz )
{
classMap = (ClassMap) classMaps.get( clazz );
if ( classMap == null )
{
classMap = new ClassMap( clazz );
classMaps.put( clazz, classMap );
}
return classMap;
}
}

View File

@ -1,92 +0,0 @@
package org.apache.maven.util.introspection;
/*
* Copyright 2001-2005 The Apache Software Foundation.
*
* Licensed 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 org.apache.maven.MavenTestCase;
import org.apache.maven.model.Build;
import org.apache.maven.project.MavenProject;
import java.io.File;
import java.util.List;
/**
* @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
* @version $Id$
*/
public class ReflectionValueExtractorTest
extends MavenTestCase
{
private MavenProject project;
protected void setUp()
throws Exception
{
super.setUp();
File f = getFileForClasspathResource( "pom.xml" );
project = getProject( f );
}
public void testValueExtraction()
throws Exception
{
// ----------------------------------------------------------------------
// Top level values
// ----------------------------------------------------------------------
assertEquals( "4.0.0", ReflectionValueExtractor.evaluate( "project.modelVersion", project ) );
assertEquals( "org.apache.maven", ReflectionValueExtractor.evaluate( "project.groupId", project ) );
assertEquals( "maven-core", ReflectionValueExtractor.evaluate( "project.artifactId", project ) );
assertEquals( "Maven", ReflectionValueExtractor.evaluate( "project.name", project ) );
assertEquals( "2.0-SNAPSHOT", ReflectionValueExtractor.evaluate( "project.version", project ) );
// ----------------------------------------------------------------------
// SCM
// ----------------------------------------------------------------------
assertEquals( "scm-connection", ReflectionValueExtractor.evaluate( "project.scm.connection", project ) );
// ----------------------------------------------------------------------
// Dependencies
// ----------------------------------------------------------------------
List dependencies = (List) ReflectionValueExtractor.evaluate( "project.dependencies", project );
assertNotNull( dependencies );
assertEquals( 2, dependencies.size() );
// ----------------------------------------------------------------------
// Build
// ----------------------------------------------------------------------
Build build = (Build) ReflectionValueExtractor.evaluate( "project.build", project );
assertNotNull( build );
}
public void testValueExtractorWithAInvalidExpression()
throws Exception
{
assertNull( ReflectionValueExtractor.evaluate( "project.foo", project ) );
}
}