Browse Source

MOve Attribute Setter outof Reflector to its own class

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@272015 13f79535-47bb-0310-9956-ffa450edef68
master
Conor MacNeill 23 years ago
parent
commit
2e31f97888
5 changed files with 252 additions and 69 deletions
  1. +2
    -1
      proposal/mutant/build.xml
  2. +176
    -0
      proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/AttributeSetter.java
  3. +26
    -2
      proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ClassIntrospector.java
  4. +45
    -65
      proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/Reflector.java
  5. +3
    -1
      proposal/mutant/src/java/antlibs/ant1compat/org/apache/tools/ant/Project.java

+ 2
- 1
proposal/mutant/build.xml View File

@@ -201,7 +201,8 @@
useexternalfile="yes"
sourcepath="${java.dir}/antcore:${java.dir}/init:${java.dir}/common:${java.dir}/cli:${java.dir}/start"
destdir="${javadocs.dir}"
author="true" private ="true"
author="true"
private ="true"
version="true"
windowtitle="Mutant API"
doctitle="Mutant">


+ 176
- 0
proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/AttributeSetter.java View File

@@ -0,0 +1,176 @@
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2002 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Ant", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.ant.antcore.execution;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.apache.ant.common.antlib.Converter;
import org.apache.ant.common.util.ExecutionException;

/**
* AttributeSetters are created at introspection time for each
* setter method a class provides and for which a conversion from a
* String value is available.
*
* @author Conor MacNeill
* @created 19 January 2002
*/
public class AttributeSetter {
/** The method that will perform the setting */
private Method method;
/**
* A converter to convert the string value to a value to be given to
* the setter method
*/
private Converter converter;
/**
* A constructor used to create the string value to an object to be used
* by the setter
*/
private Constructor valueConstructor;
/** The depth of the setter in the class hierarchy */
private int depth;

/**
* Create a setter which just uses string values
*
* @param method the method to be invoked.
* @param depth the depth of this method declaraion in the class hierarchy.
*/
public AttributeSetter(Method method, int depth) {
this.method = method;
this.depth = depth;
}

/**
* Create a setter which just uses string values
*
* @param method the method to be invoked.
* @param depth the depth of this method declaraion in the class hierarchy.
* @param converter a converter to convert string values into instances of
* the type expected by the method.
*/
public AttributeSetter(Method method, int depth, Converter converter) {
this(method, depth);
this.converter = converter;
}

/**
* Create a setter which just uses string values
*
* @param method the method to be invoked.
* @param depth the depth of this method declaraion in the class hierarchy.
* @param valueConstructor an object constructor used to convert string
* values into instances of the type expected by the method.
*/
public AttributeSetter(Method method, int depth,
Constructor valueConstructor) {
this(method, depth);
this.valueConstructor = valueConstructor;
}
/**
* Set the attribute value on an object
*
* @param obj the object on which the set method is to be invoked
* @param stringValue the string representation of the value
* @exception InvocationTargetException if the method cannot be
* invoked
* @exception IllegalAccessException if the method cannot be invoked
* @exception ExecutionException if the conversion of the value
* fails
*/
void set(Object obj, String stringValue)
throws InvocationTargetException, IllegalAccessException,
ExecutionException {
Object value = null;
if (converter != null) {
Class type = getType();
value = converter.convert(stringValue, type);
} else if (valueConstructor != null) {
try {
value = valueConstructor.newInstance(new String[]{stringValue});
} catch (InstantiationException e) {
throw new ExecutionException(e);
}
} else {
value = stringValue;
}
method.invoke(obj, new Object[]{value});
}
/**
* Get the declaration depth of this setter.
*
* @return the attribute setter's declaration depth.
*/
public int getDepth() {
return depth;
}
/**
* Get the type expected by this setter's method
*
* @return a Class instance being the type this setter's method accepts.
*/
public Class getType() {
return method.getParameterTypes()[0];
}
}


+ 26
- 2
proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/ClassIntrospector.java View File

@@ -54,6 +54,7 @@
package org.apache.ant.antcore.execution;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.HashMap;

/**
* Introspects a class and builds a reflector for setting values on
@@ -66,6 +67,27 @@ public class ClassIntrospector {
/** The reflector that this introspector populates */
private Reflector reflector;

/**
* A Map which maps the classnames to their depth in the class hiearchy,
* with the current class being depth=0
*/
private Map classDepth = new HashMap();

/**
* Determine the class hierarchy depths for the given class.
*
* @param bean the class for which the class depths will be determined.
*/
private void getDepths(Class bean) {
Class currentClass = bean;
int index = 0;
while (currentClass != null) {
classDepth.put(currentClass, new Integer(index++));
currentClass = currentClass.getSuperclass();
}
}
/**
* Create a introspector for the bean
*
@@ -75,6 +97,7 @@ public class ClassIntrospector {
*/
public ClassIntrospector(final Class bean, Map converters) {
reflector = new Reflector();
getDepths(bean);

Method[] methods = bean.getMethods();
for (int i = 0; i < methods.length; i++) {
@@ -93,8 +116,9 @@ public class ClassIntrospector {
&& returnType.equals(Void.TYPE)
&& args.length == 1
&& !args[0].isArray()) {
reflector.addAttributeMethod(m, getPropertyName(name, "set"),
converters);
Integer depth = (Integer)classDepth.get(m.getDeclaringClass());
reflector.addAttributeMethod(m, depth.intValue(),
getPropertyName(name, "set"), converters);
} else if (name.startsWith("addConfigured")
&& name.length() > 13
&& returnType.equals(Void.TYPE)


+ 45
- 65
proposal/mutant/src/java/antcore/org/apache/ant/antcore/execution/Reflector.java View File

@@ -71,31 +71,6 @@ import org.apache.ant.common.util.ExecutionException;
*/
public class Reflector implements Setter {

/**
* AttributeSetter classes are created at introspection time for each
* setter method a class provides and for which a conversion from a
* String value is available.
*
* @author Conor MacNeill
* @created 19 January 2002
*/
private interface AttributeSetter {
/**
* Set the attribute value on an object
*
* @param obj the object on which the set method is to be invoked
* @param value the string representation of the value
* @exception InvocationTargetException if the method cannot be
* invoked
* @exception IllegalAccessException if the method cannot be invoked
* @exception ExecutionException if the conversion of the value
* fails
*/
void set(Object obj, String value)
throws InvocationTargetException, IllegalAccessException,
ExecutionException;
}

/**
* An element adder is used to add an instance of an element to an of an
* object. The object being added will have been fully configured by Ant
@@ -359,6 +334,36 @@ public class Reflector implements Setter {
return elementAdders.containsKey(elementName.toLowerCase());
}

/**
* Add an attribute setter for the given property. The setter will only
* be added if it does not override a higher priorty setter
*
* @param attributeName the name of the attribute that the setter operates
* upon.
* @param setter the AttribnuteSetter instance to use.
*/
private void addAttributeSetter(String attributeName,
AttributeSetter setter) {
String name = attributeName.toLowerCase();
AttributeSetter currentSetter
= (AttributeSetter)attributeSetters.get(name);
if (currentSetter != null) {
// there is a setter, is it lower down in the class hierarchy
int currentDepth = currentSetter.getDepth();
if (currentDepth < setter.getDepth()) {
return;
} else if (currentDepth == setter.getDepth()) {
// now check the types
Class currentType = currentSetter.getType();
if (currentType != String.class) {
return;
}
}
}
attributeSetters.put(name, setter);
}
/**
* Determine if the class associated with this reflector supports a
* particular nested element
@@ -375,51 +380,33 @@ public class Reflector implements Setter {
* Add a method to the reflector for setting an attribute value
*
* @param m the method, obtained by introspection.
* @param depth the depth of this method's declaration in the class
* hierarchy
* @param propertyName the property name the method will set.
* @param converters A map of converter classes used to convert strings
* to different types.
*/
public void addAttributeMethod(final Method m, String propertyName,
Map converters) {
final Class type = m.getParameterTypes()[0];
public void addAttributeMethod(Method m, int depth,
String propertyName, Map converters) {
Class type = m.getParameterTypes()[0];

if (converters != null && converters.containsKey(type)) {
// we have a converter to use to convert the String
// value into something the set method expects.
Converter converter = (Converter)converters.get(type);
addConvertingSetter(m, propertyName, converter, type);
addConvertingSetter(m, depth, propertyName, converter);
return;
}

if (type.equals(String.class)) {
attributeSetters.put(propertyName.toLowerCase(),
new AttributeSetter() {
public void set(Object parent, String value)
throws InvocationTargetException,
IllegalAccessException {
m.invoke(parent, new String[]{value});
}
});
addAttributeSetter(propertyName, new AttributeSetter(m, depth));
return;
}

try {
final Constructor c =
type.getConstructor(new Class[]{java.lang.String.class});
attributeSetters.put(propertyName.toLowerCase(),
new AttributeSetter() {
public void set(Object parent, String value)
throws InvocationTargetException,
IllegalAccessException, ExecutionException {
try {
Object newValue
= c.newInstance(new String[]{value});
m.invoke(parent, new Object[]{newValue});
} catch (InstantiationException ie) {
throw new ExecutionException(ie);
}
}
});
addAttributeSetter(propertyName, new AttributeSetter(m, depth, c));
return;
} catch (NoSuchMethodException nme) {
// ignore
@@ -435,7 +422,7 @@ public class Reflector implements Setter {
Converter converter
= (Converter)converters.get(converterType);
if (converter.canConvertSubType(type)) {
addConvertingSetter(m, propertyName, converter, type);
addConvertingSetter(m, depth, propertyName, converter);
return;
}
}
@@ -484,23 +471,16 @@ public class Reflector implements Setter {
* Add an attribute setter with an associated converter
*
* @param m the attribute setter method
* @param depth the depth of this method's declaration in the class
* hierarchy
* @param propertyName the name of the attribute this method supports
* @param converter the converter to be used to construct the value
* expected by the method.
* @param type the type expected by the method.
*/
private void addConvertingSetter(final Method m, String propertyName,
final Converter converter,
final Class type) {
attributeSetters.put(propertyName.toLowerCase(),
new AttributeSetter() {
public void set(Object obj, String value)
throws InvocationTargetException, ExecutionException,
IllegalAccessException {
Object convertedValue = converter.convert(value, type);
m.invoke(obj, new Object[]{convertedValue});
}
});
private void addConvertingSetter(Method m, int depth,
String propertyName, Converter converter) {
addAttributeSetter(propertyName,
new AttributeSetter(m, depth, converter));
}
}


+ 3
- 1
proposal/mutant/src/java/antlibs/ant1compat/org/apache/tools/ant/Project.java View File

@@ -885,8 +885,10 @@ public class Project implements org.apache.ant.common.event.BuildListener {
*
* @param taskType the name of the task to be created.
* @return the created task instance
*
* @exception BuildException if there is a build problem
*/
public Task createTask(String taskType) {
public Task createTask(String taskType) throws BuildException {
Task task = null;
Class taskClass = (Class)taskClassDefinitions.get(taskType);



Loading…
Cancel
Save