📄 introspectionhelper.java
字号:
* * @param element The element to describe. Must not be <code>null</code>. * * @return a description of the element type */ private String getElementName(Project project, Object element) { return project.getElementName(element); } /** * Extracts the name of a property from a method name by subtracting * a given prefix and converting into lower case. It is up to calling * code to make sure the method name does actually begin with the * specified prefix - no checking is done in this method. * * @param methodName The name of the method in question. Must not be <code>null</code>. * @param prefix The prefix to remove. Must not be <code>null</code>. * * @return the lower-cased method name with the prefix removed. */ private static String getPropertyName(String methodName, String prefix) { return methodName.substring(prefix.length()).toLowerCase(Locale.US); } /** * creator - allows use of create/store external * to IntrospectionHelper. * The class is final as it has a private constructor. */ public static final class Creator { private NestedCreator nestedCreator; private Object parent; private Project project; private Object nestedObject; private String polyType; /** * Creates a new Creator instance. * This object is given to the UnknownElement to create * objects for sub-elements. UnknownElement calls * create to create an object, the object then gets * configured and then UnknownElement calls store. * SetPolyType may be used to override the type used * to create the object with. SetPolyType gets called before create. * * @param project the current project * @param parent the parent object to create the object in * @param nestedCreator the nested creator object to use */ private Creator(Project project, Object parent, NestedCreator nestedCreator) { this.project = project; this.parent = parent; this.nestedCreator = nestedCreator; } /** * Used to override the class used to create the object. * * @param polyType a ant component type name */ public void setPolyType(String polyType) { this.polyType = polyType; } /** * Create an object using this creator, which is determined by introspection. * * @return the created object */ public Object create() { if (polyType != null) { if (!nestedCreator.isPolyMorphic()) { throw new BuildException( "Not allowed to use the polymorphic form for this element"); } ComponentHelper helper = ComponentHelper.getComponentHelper(project); nestedObject = helper.createComponent(polyType); if (nestedObject == null) { throw new BuildException("Unable to create object of type " + polyType); } } try { nestedObject = nestedCreator.create(project, parent, nestedObject); if (project != null) { project.setProjectReference(nestedObject); } return nestedObject; } catch (IllegalAccessException ex) { throw new BuildException(ex); } catch (InstantiationException ex) { throw new BuildException(ex); } catch (IllegalArgumentException ex) { if (polyType == null) { throw ex; } throw new BuildException("Invalid type used " + polyType); } catch (InvocationTargetException ex) { throw extractBuildException(ex); } } /** * @return the real object (used currently only for presetdef). */ public Object getRealObject() { return nestedCreator.getRealObject(); } /** * Stores the nested element object using a storage method determined by introspection. * */ public void store() { try { nestedCreator.store(parent, nestedObject); } catch (IllegalAccessException ex) { throw new BuildException(ex); } catch (InstantiationException ex) { throw new BuildException(ex); } catch (IllegalArgumentException ex) { if (polyType == null) { throw ex; } throw new BuildException("Invalid type used " + polyType); } catch (InvocationTargetException ex) { throw extractBuildException(ex); } } } /** * Internal interface used to create nested elements. Not documented * in detail for reasons of source code readability. */ private abstract static class NestedCreator { private Method method; // the method called to add/create the nested element protected NestedCreator(Method m) { method = m; } Method getMethod() { return method; } boolean isPolyMorphic() { return false; } Object getRealObject() { return null; } abstract Object create(Project project, Object parent, Object child) throws InvocationTargetException, IllegalAccessException, InstantiationException; void store(Object parent, Object child) throws InvocationTargetException, IllegalAccessException, InstantiationException { // DO NOTHING } } private static class CreateNestedCreator extends NestedCreator { CreateNestedCreator(Method m) { super(m); } Object create(Project project, Object parent, Object ignore) throws InvocationTargetException, IllegalAccessException { return getMethod().invoke(parent, new Object[] {}); } } /** Version to use for addXXX and addConfiguredXXX */ private static class AddNestedCreator extends NestedCreator { static final int ADD = 1; static final int ADD_CONFIGURED = 2; private Constructor constructor; private int behavior; // ADD or ADD_CONFIGURED AddNestedCreator(Method m, Constructor c, int behavior) { super(m); this.constructor = c; this.behavior = behavior; } boolean isPolyMorphic() { return true; } Object create(Project project, Object parent, Object child) throws InvocationTargetException, IllegalAccessException, InstantiationException { if (child == null) { child = constructor.newInstance( constructor.getParameterTypes().length == 0 ? new Object[] {} : new Object[] {project}); } if (child instanceof PreSetDef.PreSetDefinition) { child = ((PreSetDef.PreSetDefinition) child).createObject(project); } if (behavior == ADD) { istore(parent, child); } return child; } void store(Object parent, Object child) throws InvocationTargetException, IllegalAccessException, InstantiationException { if (behavior == ADD_CONFIGURED) { istore(parent, child); } } private void istore(Object parent, Object child) throws InvocationTargetException, IllegalAccessException, InstantiationException { getMethod().invoke(parent, new Object[] {child}); } } /** * Internal interface used to setting element attributes. Not documented * in detail for reasons of source code readability. */ private abstract static class AttributeSetter { private Method method; // the method called to set the attribute protected AttributeSetter(Method m) { method = m; } abstract void set(Project p, Object parent, String value) throws InvocationTargetException, IllegalAccessException, BuildException; } /** * Clears the static cache of on build finished. */ public static void clearCache() { HELPERS.clear(); } /** * Create a NestedCreator for the given element. * @param project owning project * @param parent Parent object used to create the instance. * @param elementName name of the element * @return a nested creator, or null if there is no component of the given name, or it * has no matching add type methods * @throws BuildException */ private NestedCreator createAddTypeCreator( Project project, Object parent, String elementName) throws BuildException { if (addTypeMethods.size() == 0) { return null; } ComponentHelper helper = ComponentHelper.getComponentHelper(project); Object addedObject = null; Method addMethod = null; Class clazz = helper.getComponentClass(elementName); if (clazz == null) { return null; } addMethod = findMatchingMethod(clazz, addTypeMethods); if (addMethod == null) { return null; } addedObject = helper.createComponent(elementName); if (addedObject == null) { return null; } Object rObject = addedObject; if (addedObject instanceof PreSetDef.PreSetDefinition) { rObject = ((PreSetDef.PreSetDefinition) addedObject).createObject(project); } final Object nestedObject = addedObject; final Object realObject = rObject; return new NestedCreator(addMethod) { Object create(Project project, Object parent, Object ignore) throws InvocationTargetException, IllegalAccessException { if (!getMethod().getName().endsWith("Configured")) { getMethod().invoke(parent, new Object[] {realObject}); } return nestedObject; } Object getRealObject() { return realObject; } void store(Object parent, Object child) throws InvocationTargetException, IllegalAccessException, InstantiationException { if (getMethod().getName().endsWith("Configured")) { getMethod().invoke(parent, new Object[] {realObject}); } } }; } /** * Inserts an add or addConfigured method into * the addTypeMethods array. The array is * ordered so that the more derived classes are first. * If both add and addConfigured are present, the addConfigured will take priority. * @param method the <code>Method</code> to insert. */ private void insertAddTypeMethod(Method method) { Class argClass = method.getParameterTypes()[0]; for (int c = 0; c < addTypeMethods.size(); ++c) { Method current = (Method) addTypeMethods.get(c); if (current.getParameterTypes()[0].equals(argClass)) { if (method.getName().equals("addConfigured")) { // add configured replaces the add method addTypeMethods.set(c, method); } return; // Already present } if (current.getParameterTypes()[0].isAssignableFrom(argClass)) { addTypeMethods.add(c, method); return; // higher derived } } addTypeMethods.add(method); } /** * Search the list of methods to find the first method * that has a parameter that accepts the nested element object. * @param paramClass the <code>Class</code> type to search for. * @param methods the <code>List</code> of methods to search. * @return a matching <code>Method</code>; null if none found. */ private Method findMatchingMethod(Class paramClass, List methods) { Class matchedClass = null; Method matchedMethod = null; for (int i = 0; i < methods.size(); ++i) { Method method = (Method) methods.get(i); Class methodClass = method.getParameterTypes()[0]; if (methodClass.isAssignableFrom(paramClass)) { if (matchedClass == null) { matchedClass = methodClass; matchedMethod = method; } else if (!methodClass.isAssignableFrom(matchedClass)) { throw new BuildException("ambiguous: types " + matchedClass.getName() + " and " + methodClass.getName() + " match " + paramClass.getName()); } } } return matchedMethod; } private String condenseText(final String text) { if (text.length() <= MAX_REPORT_NESTED_TEXT) { return text; } int ends = (MAX_REPORT_NESTED_TEXT - ELLIPSIS.length()) / 2; return new StringBuffer(text).replace(ends, text.length() - ends, ELLIPSIS).toString(); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -