⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 introspectionhelper.java

📁 Use the links below to download a source distribution of Ant from one of our mirrors. It is good pra
💻 JAVA
📖 第 1 页 / 共 4 页
字号:
/* *  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. * */package org.apache.tools.ant;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.Collections;import java.util.Enumeration;import java.util.Hashtable;import java.util.HashMap;import java.util.List;import java.util.Locale;import java.util.Map;import org.apache.tools.ant.types.EnumeratedAttribute;import org.apache.tools.ant.taskdefs.PreSetDef;import org.apache.tools.ant.util.StringUtils;/** * Helper class that collects the methods a task or nested element * holds to set attributes, create nested elements or hold PCDATA * elements. * * It contains hashtables containing classes that use introspection * to handle all the invocation of the project-component specific methods. * * This class is somewhat complex, as it implements the O/X mapping between * Ant XML and Java class instances. This is not the best place for someone new * to Ant to start contributing to the codebase, as a change here can break the * entire system in interesting ways. Always run a full test of Ant before checking * in/submitting changes to this file. * * The class is final and has a private constructor. * To get an instance for a specific (class,project) combination, use {@link #getHelper(Project,Class)}. * This may return an existing version, or a new one * ...do not make any assumptions about its uniqueness, or its validity after the Project * instance has finished its build. * */public final class IntrospectionHelper  {    /**     * Helper instances we've already created (Class.getName() to IntrospectionHelper).     */    private static final Map HELPERS = new Hashtable();    /**     * Map from primitive types to wrapper classes for use in     * createAttributeSetter (Class to Class). Note that char     * and boolean are in here even though they get special treatment     * - this way we only need to test for the wrapper class.     */    private static final Map PRIMITIVE_TYPE_MAP = new HashMap(8);    // Set up PRIMITIVE_TYPE_MAP    static {        Class[] primitives = {Boolean.TYPE, Byte.TYPE, Character.TYPE, Short.TYPE,                              Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE};        Class[] wrappers = {Boolean.class, Byte.class, Character.class, Short.class,                            Integer.class, Long.class, Float.class, Double.class};        for (int i = 0; i < primitives.length; i++) {            PRIMITIVE_TYPE_MAP.put (primitives[i], wrappers[i]);        }    }    private static final int MAX_REPORT_NESTED_TEXT = 20;    private static final String ELLIPSIS = "...";    /**     * Map from attribute names to attribute types     * (String to Class).     */    private Hashtable attributeTypes = new Hashtable();    /**     * Map from attribute names to attribute setter methods     * (String to AttributeSetter).     */    private Hashtable attributeSetters = new Hashtable();    /**     * Map from attribute names to nested types     * (String to Class).     */    private Hashtable nestedTypes = new Hashtable();    /**     * Map from attribute names to methods to create nested types     * (String to NestedCreator).     */    private Hashtable nestedCreators = new Hashtable();    /**     * Vector of methods matching add[Configured](Class) pattern.     */    private List addTypeMethods = new ArrayList();    /**     * The method to invoke to add PCDATA.     */    private Method addText = null;    /**     * The class introspected by this instance.     */    private Class bean;    /**     * Sole constructor, which is private to ensure that all     * IntrospectionHelpers are created via {@link #getHelper(Class) getHelper}.     * Introspects the given class for bean-like methods.     * Each method is examined in turn, and the following rules are applied:     * <p>     * <ul>     * <li>If the method is <code>Task.setLocation(Location)</code>,     * <code>Task.setTaskType(String)</code>     * or <code>TaskContainer.addTask(Task)</code>, it is ignored. These     * methods are handled differently elsewhere.     * <li><code>void addText(String)</code> is recognised as the method for     * adding PCDATA to a bean.     * <li><code>void setFoo(Bar)</code> is recognised as a method for     * setting the value of attribute <code>foo</code>, so long as     * <code>Bar</code> is non-void and is not an array type. Non-String     * parameter types always overload String parameter types, but that is     * the only guarantee made in terms of priority.     * <li><code>Foo createBar()</code> is recognised as a method for     * creating a nested element called <code>bar</code> of type     * <code>Foo</code>, so long as <code>Foo</code> is not a primitive or     * array type.     * <li><code>void addConfiguredFoo(Bar)</code> is recognised as a     * method for storing a pre-configured element called     * <code>foo</code> and of type <code>Bar</code>, so long as     * <code>Bar</code> is not an array, primitive or String type.     * <code>Bar</code> must have an accessible constructor taking no     * arguments.     * <li><code>void addFoo(Bar)</code> is recognised as a method for storing     * an element called <code>foo</code> and of type <code>Bar</code>, so     * long as <code>Bar</code> is not an array, primitive or String type.     * <code>Bar</code> must have an accessible constructor taking no     * arguments. This is distinct from the 'addConfigured' idiom in that     * the nested element is added to the parent immediately after it is     * constructed; in practice this means that <code>addFoo(Bar)</code> should     * do little or nothing with its argument besides storing it for later use.     * </ul>     * Note that only one method is retained to create/set/addConfigured/add     * any element or attribute.     *     * @param bean The bean type to introspect.     *             Must not be <code>null</code>.     *     * @see #getHelper(Class)     */    private IntrospectionHelper(final Class bean) {        this.bean = bean;        Method[] methods = bean.getMethods();        for (int i = 0; i < methods.length; i++) {            final Method m = methods[i];            final String name = m.getName();            Class returnType = m.getReturnType();            Class[] args = m.getParameterTypes();            // check of add[Configured](Class) pattern            if (args.length == 1 && java.lang.Void.TYPE.equals(returnType)                    && ("add".equals(name) || "addConfigured".equals(name))) {                insertAddTypeMethod(m);                continue;            }            // not really user settable properties on tasks/project components            if (org.apache.tools.ant.ProjectComponent.class.isAssignableFrom(bean)                    && args.length == 1 && isHiddenSetMethod(name, args[0])) {                continue;            }            // hide addTask for TaskContainers            if (isContainer() && args.length == 1 && "addTask".equals(name)                    && org.apache.tools.ant.Task.class.equals(args[0])) {                continue;            }            if ("addText".equals(name) && java.lang.Void.TYPE.equals(returnType)                    && args.length == 1 && java.lang.String.class.equals(args[0])) {                addText = methods[i];            } else if (name.startsWith("set") && java.lang.Void.TYPE.equals(returnType)                    && args.length == 1 && !args[0].isArray()) {                String propName = getPropertyName(name, "set");                if (attributeSetters.get(propName) != null) {                    if (java.lang.String.class.equals(args[0])) {                        /*                            Ignore method m, as there is an overloaded                            form of this method that takes in a                            non-string argument, which gains higher                            priority.                        */                        continue;                    }                    /*                        If the argument is not a String and if there                        is an overloaded form of this method already defined,                        we just override that with the new one.                        This mechanism does not guarantee any specific order                        in which the methods will be selected: so any code                        that depends on the order in which "set" methods have                        been defined, is not guaranteed to be selected in any                        particular order.                    */                }                AttributeSetter as = createAttributeSetter(m, args[0], propName);                if (as != null) {                    attributeTypes.put(propName, args[0]);                    attributeSetters.put(propName, as);                }            } else if (name.startsWith("create") && !returnType.isArray()                    && !returnType.isPrimitive() && args.length == 0) {                String propName = getPropertyName(name, "create");                // Check if a create of this property is already present                // add takes preference over create for CB purposes                if (nestedCreators.get(propName) == null) {                    nestedTypes.put(propName, returnType);                    nestedCreators.put(propName, new CreateNestedCreator(m));                }            } else if (name.startsWith("addConfigured")                    && java.lang.Void.TYPE.equals(returnType) && args.length == 1                    && !java.lang.String.class.equals(args[0])                    && !args[0].isArray() && !args[0].isPrimitive()) {                try {                    Constructor constructor = null;                    try {                        constructor = args[0].getConstructor(new Class[] {});                    } catch (NoSuchMethodException ex) {                        constructor = args[0].getConstructor(new Class[] {Project.class});                    }                    String propName = getPropertyName(name, "addConfigured");                    nestedTypes.put(propName, args[0]);                    nestedCreators.put(propName, new AddNestedCreator(m,                        constructor, AddNestedCreator.ADD_CONFIGURED));                } catch (NoSuchMethodException nse) {                    // ignore                }            } else if (name.startsWith("add")                    && java.lang.Void.TYPE.equals(returnType) && args.length == 1                    && !java.lang.String.class.equals(args[0])                    && !args[0].isArray() && !args[0].isPrimitive()) {                try {                    Constructor constructor = null;                    try {                        constructor = args[0].getConstructor(new Class[] {});                    } catch (NoSuchMethodException ex) {                        constructor = args[0].getConstructor(new Class[] {Project.class});                    }                    String propName = getPropertyName(name, "add");                    if (nestedTypes.get(propName) != null) {                        /*                         *  Ignore this method as there is an addConfigured                         *  form of this method that has a higher                         *  priority                         */                        continue;                    }                    nestedTypes.put(propName, args[0]);                    nestedCreators.put(propName, new AddNestedCreator(m,                            constructor, AddNestedCreator.ADD));                } catch (NoSuchMethodException nse) {                    // ignore                }            }        }    }    /**     * Certain set methods are part of the Ant core interface to tasks and     * therefore not to be considered for introspection     *     * @param name the name of the set method     * @param type the type of the set method's parameter     * @return true if the given set method is to be hidden.     */    private boolean isHiddenSetMethod(String name, Class type) {        if ("setLocation".equals(name) && org.apache.tools.ant.Location.class.equals(type)) {            return true;        }        if ("setTaskType".equals(name) && java.lang.String.class.equals(type)) {            return true;        }        return false;    }    /**     * Returns a helper for the given class, either from the cache     * or by creating a new instance.     *     * @param c The class for which a helper is required.     *          Must not be <code>null</code>.     *     * @return a helper for the specified class     */    public static synchronized IntrospectionHelper getHelper(Class c) {        return getHelper(null, c);    }    /**     * Returns a helper for the given class, either from the cache     * or by creating a new instance.     *     * The method will make sure the helper will be cleaned up at the end of     * the project, and only one instance will be created for each class.     *     * @param p the project instance. Can be null, in which case the helper is not cached.     * @param c The class for which a helper is required.     *          Must not be <code>null</code>.     *     * @return a helper for the specified class     */    public static IntrospectionHelper getHelper(Project p, Class c) {        IntrospectionHelper ih = (IntrospectionHelper) HELPERS.get(c.getName());        // If a helper cannot be found, or if the helper is for another        // classloader, create a new IH        if (ih == null || ih.bean != c) {            ih = new IntrospectionHelper(c);            if (p != null) {                // #30162: do *not* cache this if there is no project, as we                // cannot guarantee that the cache will be cleared.                HELPERS.put(c.getName(), ih);            }        }        return ih;    }    /**     * Sets the named attribute in the given element, which is part of the     * given project.     *     * @param p The project containing the element. This is used when files     *          need to be resolved. Must not be <code>null</code>.     * @param element The element to set the attribute in. Must not be     *                <code>null</code>.     * @param attributeName The name of the attribute to set. Must not be     *                      <code>null</code>.     * @param value The value to set the attribute to. This may be interpreted     *              or converted to the necessary type if the setter method     *              doesn't just take a string. Must not be <code>null</code>.     *     * @exception BuildException if the introspected class doesn't support     *                           the given attribute, or if the setting     *                           method fails.     */    public void setAttribute(Project p, Object element, String attributeName,                             String value) throws BuildException {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -