You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

IntrospectionHelper.java 74 kB

PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
22 years ago
11 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
22 years ago
11 years ago
8 years ago
8 years ago
11 years ago
11 years ago
8 years ago
8 years ago
8 years ago
8 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
22 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
22 years ago
8 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
22 years ago
11 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
22 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
22 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
9 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
8 years ago
8 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
8 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
22 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
22 years ago
11 years ago
8 years ago
11 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
22 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
22 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
22 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
22 years ago
11 years ago
11 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
22 years ago
8 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
22 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
22 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
22 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
22 years ago
11 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
22 years ago
11 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
22 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
22 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. package org.apache.tools.ant;
  19. import java.io.File;
  20. import java.lang.reflect.Constructor;
  21. import java.lang.reflect.InvocationTargetException;
  22. import java.lang.reflect.Method;
  23. import java.util.ArrayList;
  24. import java.util.Collections;
  25. import java.util.Enumeration;
  26. import java.util.HashMap;
  27. import java.util.Hashtable;
  28. import java.util.List;
  29. import java.util.Locale;
  30. import java.util.Map;
  31. import org.apache.tools.ant.taskdefs.PreSetDef;
  32. import org.apache.tools.ant.types.EnumeratedAttribute;
  33. import org.apache.tools.ant.types.Resource;
  34. import org.apache.tools.ant.types.resources.FileProvider;
  35. import org.apache.tools.ant.types.resources.FileResource;
  36. import org.apache.tools.ant.util.StringUtils;
  37. /**
  38. * Helper class that collects the methods a task or nested element
  39. * holds to set attributes, create nested elements or hold PCDATA
  40. * elements.
  41. *
  42. * It contains hashtables containing classes that use introspection
  43. * to handle all the invocation of the project-component specific methods.
  44. *
  45. * This class is somewhat complex, as it implements the O/X mapping between
  46. * Ant XML and Java class instances. This is not the best place for someone new
  47. * to Ant to start contributing to the codebase, as a change here can break the
  48. * entire system in interesting ways. Always run a full test of Ant before checking
  49. * in/submitting changes to this file.
  50. *
  51. * The class is final and has a private constructor.
  52. * To get an instance for a specific (class,project) combination,
  53. * use {@link #getHelper(Project,Class)}.
  54. * This may return an existing version, or a new one
  55. * ...do not make any assumptions about its uniqueness, or its validity after the Project
  56. * instance has finished its build.
  57. *
  58. */
  59. public final class IntrospectionHelper {
  60. /**
  61. * Helper instances we've already created (Class.getName() to IntrospectionHelper).
  62. */
  63. private static final Map<String, IntrospectionHelper> HELPERS = new Hashtable<>();
  64. /**
  65. * Map from primitive types to wrapper classes for use in
  66. * createAttributeSetter (Class to Class). Note that char
  67. * and boolean are in here even though they get special treatment
  68. * - this way we only need to test for the wrapper class.
  69. */
  70. private static final Map<Class<?>, Class<?>> PRIMITIVE_TYPE_MAP = new HashMap<>(8);
  71. // Set up PRIMITIVE_TYPE_MAP
  72. static {
  73. final Class<?>[] primitives = {Boolean.TYPE, Byte.TYPE, Character.TYPE, Short.TYPE,
  74. Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE};
  75. final Class<?>[] wrappers = {Boolean.class, Byte.class, Character.class, Short.class,
  76. Integer.class, Long.class, Float.class, Double.class};
  77. for (int i = 0; i < primitives.length; i++) {
  78. PRIMITIVE_TYPE_MAP.put (primitives[i], wrappers[i]);
  79. }
  80. }
  81. private static final int MAX_REPORT_NESTED_TEXT = 20;
  82. private static final String ELLIPSIS = "...";
  83. /**
  84. * Map from attribute names to attribute types
  85. * (String to Class).
  86. */
  87. private final Map<String, Class<?>> attributeTypes = new Hashtable<>();
  88. /**
  89. * Map from attribute names to attribute setter methods
  90. * (String to AttributeSetter).
  91. */
  92. private final Map<String, AttributeSetter> attributeSetters = new Hashtable<>();
  93. /**
  94. * Map from attribute names to nested types
  95. * (String to Class).
  96. */
  97. private final Map<String, Class<?>> nestedTypes = new Hashtable<>();
  98. /**
  99. * Map from attribute names to methods to create nested types
  100. * (String to NestedCreator).
  101. */
  102. private final Map<String, NestedCreator> nestedCreators = new Hashtable<>();
  103. /**
  104. * Vector of methods matching add[Configured](Class) pattern.
  105. */
  106. private final List<Method> addTypeMethods = new ArrayList<>();
  107. /**
  108. * The method to invoke to add PCDATA.
  109. */
  110. private final Method addText;
  111. /**
  112. * The class introspected by this instance.
  113. */
  114. private final Class<?> bean;
  115. /**
  116. * Sole constructor, which is private to ensure that all
  117. * IntrospectionHelpers are created via {@link #getHelper(Class) getHelper}.
  118. * Introspects the given class for bean-like methods.
  119. * Each method is examined in turn, and the following rules are applied:
  120. * <p>
  121. * <ul>
  122. * <li>If the method is <code>Task.setLocation(Location)</code>,
  123. * <code>Task.setTaskType(String)</code>
  124. * or <code>TaskContainer.addTask(Task)</code>, it is ignored. These
  125. * methods are handled differently elsewhere.
  126. * <li><code>void addText(String)</code> is recognised as the method for
  127. * adding PCDATA to a bean.
  128. * <li><code>void setFoo(Bar)</code> is recognised as a method for
  129. * setting the value of attribute <code>foo</code>, so long as
  130. * <code>Bar</code> is non-void and is not an array type.
  131. * As of Ant 1.8, a Resource or FileProvider parameter overrides a java.io.File parameter;
  132. * in practice the only effect of this is to allow objects rendered from
  133. * the 1.8 PropertyHelper implementation to be used as Resource parameters,
  134. * since Resources set from Strings are resolved as project-relative files
  135. * to preserve backward compatibility. Beyond this, non-String
  136. * parameter types always overload String parameter types; these are
  137. * the only guarantees made in terms of priority.
  138. * <li><code>Foo createBar()</code> is recognised as a method for
  139. * creating a nested element called <code>bar</code> of type
  140. * <code>Foo</code>, so long as <code>Foo</code> is not a primitive or
  141. * array type.
  142. * <li><code>void addConfiguredFoo(Bar)</code> is recognised as a
  143. * method for storing a pre-configured element called
  144. * <code>foo</code> and of type <code>Bar</code>, so long as
  145. * <code>Bar</code> is not an array, primitive or String type.
  146. * <code>Bar</code> must have an accessible constructor taking no
  147. * arguments.
  148. * <li><code>void addFoo(Bar)</code> is recognised as a method for storing
  149. * an element called <code>foo</code> and of type <code>Bar</code>, so
  150. * long as <code>Bar</code> is not an array, primitive or String type.
  151. * <code>Bar</code> must have an accessible constructor taking no
  152. * arguments. This is distinct from the 'addConfigured' idiom in that
  153. * the nested element is added to the parent immediately after it is
  154. * constructed; in practice this means that <code>addFoo(Bar)</code> should
  155. * do little or nothing with its argument besides storing it for later use.
  156. * </ul>
  157. * Note that only one method is retained to create/set/addConfigured/add
  158. * any element or attribute.
  159. *
  160. * @param bean The bean type to introspect.
  161. * Must not be <code>null</code>.
  162. *
  163. * @see #getHelper(Class)
  164. */
  165. private IntrospectionHelper(final Class<?> bean) {
  166. this.bean = bean;
  167. Method addTextMethod = null;
  168. for (final Method m : bean.getMethods()) {
  169. final String name = m.getName();
  170. final Class<?> returnType = m.getReturnType();
  171. final Class<?>[] args = m.getParameterTypes();
  172. // check of add[Configured](Class) pattern
  173. if (args.length == 1 && Void.TYPE.equals(returnType)
  174. && ("add".equals(name) || "addConfigured".equals(name))) {
  175. insertAddTypeMethod(m);
  176. continue;
  177. }
  178. // not really user settable properties on tasks/project components
  179. if (ProjectComponent.class.isAssignableFrom(bean)
  180. && args.length == 1 && isHiddenSetMethod(name, args[0])) {
  181. continue;
  182. }
  183. // hide addTask for TaskContainers
  184. if (isContainer() && args.length == 1 && "addTask".equals(name)
  185. && Task.class.equals(args[0])) {
  186. continue;
  187. }
  188. if ("addText".equals(name) && Void.TYPE.equals(returnType)
  189. && args.length == 1 && String.class.equals(args[0])) {
  190. addTextMethod = m;
  191. } else if (name.startsWith("set") && Void.TYPE.equals(returnType)
  192. && args.length == 1 && !args[0].isArray()) {
  193. final String propName = getPropertyName(name, "set");
  194. AttributeSetter as = attributeSetters.get(propName);
  195. if (as != null) {
  196. if (String.class.equals(args[0])) {
  197. /*
  198. Ignore method m, as there is an overloaded
  199. form of this method that takes in a
  200. non-string argument, which gains higher
  201. priority.
  202. */
  203. continue;
  204. }
  205. if (File.class.equals(args[0])) {
  206. // Ant Resources/FileProviders override java.io.File
  207. if (Resource.class.equals(as.type) || FileProvider.class.equals(as.type)) {
  208. continue;
  209. }
  210. }
  211. /*
  212. In cases other than those just explicitly covered,
  213. we just override that with the new one.
  214. This mechanism does not guarantee any specific order
  215. in which the methods will be selected: so any code
  216. that depends on the order in which "set" methods have
  217. been defined, is not guaranteed to be selected in any
  218. particular order.
  219. */
  220. }
  221. as = createAttributeSetter(m, args[0], propName);
  222. if (as != null) {
  223. attributeTypes.put(propName, args[0]);
  224. attributeSetters.put(propName, as);
  225. }
  226. } else if (name.startsWith("create") && !returnType.isArray()
  227. && !returnType.isPrimitive() && args.length == 0) {
  228. final String propName = getPropertyName(name, "create");
  229. // Check if a create of this property is already present
  230. // add takes preference over create for CB purposes
  231. if (nestedCreators.get(propName) == null) {
  232. nestedTypes.put(propName, returnType);
  233. nestedCreators.put(propName, new CreateNestedCreator(m));
  234. }
  235. } else if (name.startsWith("addConfigured")
  236. && Void.TYPE.equals(returnType) && args.length == 1
  237. && !String.class.equals(args[0])
  238. && !args[0].isArray() && !args[0].isPrimitive()) {
  239. try {
  240. Constructor<?> constructor = null;
  241. try {
  242. constructor = args[0].getConstructor();
  243. } catch (final NoSuchMethodException ex) {
  244. constructor = args[0].getConstructor(Project.class);
  245. }
  246. final String propName = getPropertyName(name, "addConfigured");
  247. nestedTypes.put(propName, args[0]);
  248. nestedCreators.put(propName, new AddNestedCreator(m,
  249. constructor, AddNestedCreator.ADD_CONFIGURED));
  250. } catch (final NoSuchMethodException nse) {
  251. // ignore
  252. }
  253. } else if (name.startsWith("add")
  254. && Void.TYPE.equals(returnType) && args.length == 1
  255. && !String.class.equals(args[0])
  256. && !args[0].isArray() && !args[0].isPrimitive()) {
  257. try {
  258. Constructor<?> constructor = null;
  259. try {
  260. constructor = args[0].getConstructor();
  261. } catch (final NoSuchMethodException ex) {
  262. constructor = args[0].getConstructor(Project.class);
  263. }
  264. final String propName = getPropertyName(name, "add");
  265. if (nestedTypes.get(propName) != null) {
  266. /*
  267. * Ignore this method as there is an addConfigured
  268. * form of this method that has a higher
  269. * priority
  270. */
  271. continue;
  272. }
  273. nestedTypes.put(propName, args[0]);
  274. nestedCreators.put(propName, new AddNestedCreator(m,
  275. constructor, AddNestedCreator.ADD));
  276. } catch (final NoSuchMethodException nse) {
  277. // ignore
  278. }
  279. }
  280. }
  281. addText = addTextMethod;
  282. }
  283. /**
  284. * Certain set methods are part of the Ant core interface to tasks and
  285. * therefore not to be considered for introspection
  286. *
  287. * @param name the name of the set method
  288. * @param type the type of the set method's parameter
  289. * @return true if the given set method is to be hidden.
  290. */
  291. private boolean isHiddenSetMethod(final String name, final Class<?> type) {
  292. return "setLocation".equals(name) && Location.class.equals(type)
  293. || "setTaskType".equals(name) && String.class.equals(type);
  294. }
  295. /**
  296. * Returns a helper for the given class, either from the cache
  297. * or by creating a new instance.
  298. *
  299. * @param c The class for which a helper is required.
  300. * Must not be <code>null</code>.
  301. *
  302. * @return a helper for the specified class
  303. */
  304. public static synchronized IntrospectionHelper getHelper(final Class<?> c) {
  305. return getHelper(null, c);
  306. }
  307. /**
  308. * Returns a helper for the given class, either from the cache
  309. * or by creating a new instance.
  310. *
  311. * The method will make sure the helper will be cleaned up at the end of
  312. * the project, and only one instance will be created for each class.
  313. *
  314. * @param p the project instance. Can be null, in which case the helper is not cached.
  315. * @param c The class for which a helper is required.
  316. * Must not be <code>null</code>.
  317. *
  318. * @return a helper for the specified class
  319. */
  320. public static synchronized IntrospectionHelper getHelper(final Project p, final Class<?> c) {
  321. IntrospectionHelper ih = HELPERS.get(c.getName());
  322. // If a helper cannot be found, or if the helper is for another
  323. // classloader, create a new IH
  324. if (ih == null || ih.bean != c) {
  325. ih = new IntrospectionHelper(c);
  326. if (p != null) {
  327. // #30162: do *not* cache this if there is no project, as we
  328. // cannot guarantee that the cache will be cleared.
  329. HELPERS.put(c.getName(), ih);
  330. }
  331. }
  332. return ih;
  333. }
  334. /**
  335. * Sets the named attribute in the given element, which is part of the
  336. * given project.
  337. *
  338. * @param p The project containing the element. This is used when files
  339. * need to be resolved. Must not be <code>null</code>.
  340. * @param element The element to set the attribute in. Must not be
  341. * <code>null</code>.
  342. * @param attributeName The name of the attribute to set. Must not be
  343. * <code>null</code>.
  344. * @param value The value to set the attribute to. This may be interpreted
  345. * or converted to the necessary type if the setter method
  346. * doesn't accept an object of the supplied type.
  347. *
  348. * @exception BuildException if the introspected class doesn't support
  349. * the given attribute, or if the setting
  350. * method fails.
  351. */
  352. public void setAttribute(final Project p, final Object element, final String attributeName,
  353. final Object value) throws BuildException {
  354. final AttributeSetter as = attributeSetters.get(
  355. attributeName.toLowerCase(Locale.ENGLISH));
  356. if (as == null && value != null) {
  357. if (element instanceof DynamicAttributeNS) {
  358. final DynamicAttributeNS dc = (DynamicAttributeNS) element;
  359. final String uriPlusPrefix = ProjectHelper.extractUriFromComponentName(attributeName);
  360. final String uri = ProjectHelper.extractUriFromComponentName(uriPlusPrefix);
  361. final String localName = ProjectHelper.extractNameFromComponentName(attributeName);
  362. final String qName = "".equals(uri) ? localName : uri + ":" + localName;
  363. dc.setDynamicAttribute(uri, localName, qName, value.toString());
  364. return;
  365. }
  366. if (element instanceof DynamicObjectAttribute) {
  367. final DynamicObjectAttribute dc = (DynamicObjectAttribute) element;
  368. dc.setDynamicAttribute(attributeName.toLowerCase(Locale.ENGLISH), value);
  369. return;
  370. }
  371. if (element instanceof DynamicAttribute) {
  372. final DynamicAttribute dc = (DynamicAttribute) element;
  373. dc.setDynamicAttribute(attributeName.toLowerCase(Locale.ENGLISH), value.toString());
  374. return;
  375. }
  376. if (attributeName.indexOf(':') >= 0) {
  377. return; // Ignore attribute from unknown uri's
  378. }
  379. final String msg = getElementName(p, element)
  380. + " doesn't support the \"" + attributeName + "\" attribute.";
  381. throw new UnsupportedAttributeException(msg, attributeName);
  382. }
  383. if (as != null) { // possible if value == null
  384. try {
  385. as.setObject(p, element, value);
  386. } catch (final IllegalAccessException ie) {
  387. // impossible as getMethods should only return public methods
  388. throw new BuildException(ie);
  389. } catch (final InvocationTargetException ite) {
  390. throw extractBuildException(ite);
  391. }
  392. }
  393. }
  394. /**
  395. * Sets the named attribute in the given element, which is part of the
  396. * given project.
  397. *
  398. * @param p The project containing the element. This is used when files
  399. * need to be resolved. Must not be <code>null</code>.
  400. * @param element The element to set the attribute in. Must not be
  401. * <code>null</code>.
  402. * @param attributeName The name of the attribute to set. Must not be
  403. * <code>null</code>.
  404. * @param value The value to set the attribute to. This may be interpreted
  405. * or converted to the necessary type if the setter method
  406. * doesn't just take a string. Must not be <code>null</code>.
  407. *
  408. * @exception BuildException if the introspected class doesn't support
  409. * the given attribute, or if the setting
  410. * method fails.
  411. */
  412. public void setAttribute(final Project p, final Object element, final String attributeName,
  413. final String value) throws BuildException {
  414. setAttribute(p, element, attributeName, (Object) value);
  415. }
  416. /**
  417. * Adds PCDATA to an element, using the element's
  418. * <code>void addText(String)</code> method, if it has one. If no
  419. * such method is present, a BuildException is thrown if the
  420. * given text contains non-whitespace.
  421. *
  422. * @param project The project which the element is part of.
  423. * Must not be <code>null</code>.
  424. * @param element The element to add the text to.
  425. * Must not be <code>null</code>.
  426. * @param text The text to add.
  427. * Must not be <code>null</code>.
  428. *
  429. * @exception BuildException if non-whitespace text is provided and no
  430. * method is available to handle it, or if
  431. * the handling method fails.
  432. */
  433. public void addText(final Project project, final Object element, String text)
  434. throws BuildException {
  435. if (addText == null) {
  436. text = text.trim();
  437. // Element doesn't handle text content
  438. if (text.length() == 0) {
  439. // Only whitespace - ignore
  440. return;
  441. }
  442. // Not whitespace - fail
  443. throw new BuildException(project.getElementName(element)
  444. + " doesn't support nested text data (\"" + condenseText(text) + "\").");
  445. }
  446. try {
  447. addText.invoke(element, text);
  448. } catch (final IllegalAccessException ie) {
  449. // impossible as getMethods should only return public methods
  450. throw new BuildException(ie);
  451. } catch (final InvocationTargetException ite) {
  452. throw extractBuildException(ite);
  453. }
  454. }
  455. /**
  456. * part of the error message created by {@link #throwNotSupported
  457. * throwNotSupported}.
  458. * @since Ant 1.8.0
  459. */
  460. protected static final String NOT_SUPPORTED_CHILD_PREFIX =
  461. " doesn't support the nested \"";
  462. /**
  463. * part of the error message created by {@link #throwNotSupported
  464. * throwNotSupported}.
  465. * @since Ant 1.8.0
  466. */
  467. protected static final String NOT_SUPPORTED_CHILD_POSTFIX = "\" element.";
  468. /**
  469. * Utility method to throw a NotSupported exception
  470. *
  471. * @param project the Project instance.
  472. * @param parent the object which doesn't support a requested element
  473. * @param elementName the name of the Element which is trying to be created.
  474. */
  475. public void throwNotSupported(final Project project, final Object parent, final String elementName) {
  476. final String msg = project.getElementName(parent)
  477. + NOT_SUPPORTED_CHILD_PREFIX + elementName
  478. + NOT_SUPPORTED_CHILD_POSTFIX;
  479. throw new UnsupportedElementException(msg, elementName);
  480. }
  481. /**
  482. * Get the specific NestedCreator for a given project/parent/element combination
  483. * @param project ant project
  484. * @param parentUri URI of the parent.
  485. * @param parent the parent class
  486. * @param elementName element to work with. This can contain
  487. * a URI,localname tuple of of the form uri:localname
  488. * @param child the bit of XML to work with
  489. * @return a nested creator that can handle the child elements.
  490. * @throws BuildException if the parent does not support child elements of that name
  491. */
  492. private NestedCreator getNestedCreator(
  493. final Project project, String parentUri, final Object parent,
  494. final String elementName, final UnknownElement child) throws BuildException {
  495. String uri = ProjectHelper.extractUriFromComponentName(elementName);
  496. final String name = ProjectHelper.extractNameFromComponentName(elementName);
  497. if (uri.equals(ProjectHelper.ANT_CORE_URI)) {
  498. uri = "";
  499. }
  500. if (parentUri.equals(ProjectHelper.ANT_CORE_URI)) {
  501. parentUri = "";
  502. }
  503. NestedCreator nc = null;
  504. if (uri.equals(parentUri) || uri.length() == 0) {
  505. nc = nestedCreators.get(name.toLowerCase(Locale.ENGLISH));
  506. }
  507. if (nc == null) {
  508. nc = createAddTypeCreator(project, parent, elementName);
  509. }
  510. if (nc == null &&
  511. (parent instanceof DynamicElementNS
  512. || parent instanceof DynamicElement)
  513. ) {
  514. final String qName = child == null ? name : child.getQName();
  515. final Object nestedElement =
  516. createDynamicElement(parent,
  517. child == null ? "" : child.getNamespace(),
  518. name, qName);
  519. if (nestedElement != null) {
  520. nc = new NestedCreator(null) {
  521. @Override
  522. Object create(final Project project, final Object parent, final Object ignore) {
  523. return nestedElement;
  524. }
  525. };
  526. }
  527. }
  528. if (nc == null) {
  529. throwNotSupported(project, parent, elementName);
  530. }
  531. return nc;
  532. }
  533. /**
  534. * Invokes the "correct" createDynamicElement method on parent in
  535. * order to obtain a child element by name.
  536. *
  537. * @since Ant 1.8.0.
  538. */
  539. private Object createDynamicElement(final Object parent, final String ns,
  540. final String localName, final String qName) {
  541. Object nestedElement = null;
  542. if (parent instanceof DynamicElementNS) {
  543. final DynamicElementNS dc = (DynamicElementNS) parent;
  544. nestedElement = dc.createDynamicElement(ns, localName, qName);
  545. }
  546. if (nestedElement == null && parent instanceof DynamicElement) {
  547. final DynamicElement dc = (DynamicElement) parent;
  548. nestedElement =
  549. dc.createDynamicElement(localName.toLowerCase(Locale.ENGLISH));
  550. }
  551. return nestedElement;
  552. }
  553. /**
  554. * Creates a named nested element. Depending on the results of the
  555. * initial introspection, either a method in the given parent instance
  556. * or a simple no-arg constructor is used to create an instance of the
  557. * specified element type.
  558. *
  559. * @param project Project to which the parent object belongs.
  560. * Must not be <code>null</code>. If the resulting
  561. * object is an instance of ProjectComponent, its
  562. * Project reference is set to this parameter value.
  563. * @param parent Parent object used to create the instance.
  564. * Must not be <code>null</code>.
  565. * @param elementName Name of the element to create an instance of.
  566. * Must not be <code>null</code>.
  567. *
  568. * @return an instance of the specified element type
  569. * @deprecated since 1.6.x.
  570. * This is not a namespace aware method.
  571. *
  572. * @exception BuildException if no method is available to create the
  573. * element instance, or if the creating method fails.
  574. */
  575. @Deprecated
  576. public Object createElement(final Project project, final Object parent, final String elementName)
  577. throws BuildException {
  578. final NestedCreator nc = getNestedCreator(project, "", parent, elementName, null);
  579. try {
  580. final Object nestedElement = nc.create(project, parent, null);
  581. if (project != null) {
  582. project.setProjectReference(nestedElement);
  583. }
  584. return nestedElement;
  585. } catch (final IllegalAccessException ie) {
  586. // impossible as getMethods should only return public methods
  587. throw new BuildException(ie);
  588. } catch (final InstantiationException ine) {
  589. // impossible as getMethods should only return public methods
  590. throw new BuildException(ine);
  591. } catch (final InvocationTargetException ite) {
  592. throw extractBuildException(ite);
  593. }
  594. }
  595. /**
  596. * returns an object that creates and stores an object
  597. * for an element of a parent.
  598. *
  599. * @param project Project to which the parent object belongs.
  600. * @param parentUri The namespace uri of the parent object.
  601. * @param parent Parent object used to create the creator object to
  602. * create and store and instance of a subelement.
  603. * @param elementName Name of the element to create an instance of.
  604. * @param ue The unknown element associated with the element.
  605. * @return a creator object to create and store the element instance.
  606. */
  607. public Creator getElementCreator(
  608. final Project project, final String parentUri, final Object parent, final String elementName, final UnknownElement ue) {
  609. final NestedCreator nc = getNestedCreator(project, parentUri, parent, elementName, ue);
  610. return new Creator(project, parent, nc);
  611. }
  612. /**
  613. * Indicates whether the introspected class is a dynamic one,
  614. * supporting arbitrary nested elements and/or attributes.
  615. *
  616. * @return <div><code>true</code> if the introspected class is dynamic;
  617. * <code>false</code> otherwise.</div>
  618. * @since Ant 1.6.3
  619. *
  620. * @see DynamicElement
  621. * @see DynamicElementNS
  622. */
  623. public boolean isDynamic() {
  624. return DynamicElement.class.isAssignableFrom(bean)
  625. || DynamicElementNS.class.isAssignableFrom(bean);
  626. }
  627. /**
  628. * Indicates whether the introspected class is a task container,
  629. * supporting arbitrary nested tasks/types.
  630. *
  631. * @return <code>true</code> if the introspected class is a container;
  632. * <code>false</code> otherwise.
  633. * @since Ant 1.6.3
  634. *
  635. * @see TaskContainer
  636. */
  637. public boolean isContainer() {
  638. return TaskContainer.class.isAssignableFrom(bean);
  639. }
  640. /**
  641. * Indicates if this element supports a nested element of the
  642. * given name.
  643. *
  644. * @param elementName the name of the nested element being checked
  645. *
  646. * @return true if the given nested element is supported
  647. */
  648. public boolean supportsNestedElement(final String elementName) {
  649. return supportsNestedElement("", elementName);
  650. }
  651. /**
  652. * Indicate if this element supports a nested element of the
  653. * given name.
  654. *
  655. * <p>Note that this method will always return true if the
  656. * introspected class is {@link #isDynamic dynamic} or contains a
  657. * method named "add" with void return type and a single argument.
  658. * To ge a more thorough answer, use the four-arg version of this
  659. * method instead.</p>
  660. *
  661. * @param parentUri the uri of the parent
  662. * @param elementName the name of the nested element being checked
  663. *
  664. * @return true if the given nested element is supported
  665. */
  666. public boolean supportsNestedElement(final String parentUri, final String elementName) {
  667. return isDynamic() || !addTypeMethods.isEmpty()
  668. || supportsReflectElement(parentUri, elementName);
  669. }
  670. /**
  671. * Indicate if this element supports a nested element of the
  672. * given name.
  673. *
  674. * <p>Note that this method will always return true if the
  675. * introspected class is {@link #isDynamic dynamic}, so be
  676. * prepared to catch an exception about unsupported children when
  677. * calling {@link #getElementCreator getElementCreator}.</p>
  678. *
  679. * @param parentUri the uri of the parent
  680. * @param elementName the name of the nested element being checked
  681. * @param project currently executing project instance
  682. * @param parent the parent element
  683. *
  684. * @return true if the given nested element is supported
  685. * @since Ant 1.8.0.
  686. */
  687. public boolean supportsNestedElement(final String parentUri, final String elementName,
  688. final Project project, final Object parent) {
  689. return !addTypeMethods.isEmpty()
  690. && createAddTypeCreator(project, parent, elementName) != null
  691. || isDynamic() || supportsReflectElement(parentUri, elementName);
  692. }
  693. /**
  694. * Check if this element supports a nested element from reflection.
  695. *
  696. * @param parentUri the uri of the parent
  697. * @param elementName the name of the nested element being checked
  698. *
  699. * @return true if the given nested element is supported
  700. * @since Ant 1.8.0
  701. */
  702. public boolean supportsReflectElement(
  703. String parentUri, final String elementName) {
  704. final String name = ProjectHelper.extractNameFromComponentName(elementName);
  705. if (!nestedCreators.containsKey(name.toLowerCase(Locale.ENGLISH))) {
  706. return false;
  707. }
  708. String uri = ProjectHelper.extractUriFromComponentName(elementName);
  709. if (uri.equals(ProjectHelper.ANT_CORE_URI)) {
  710. uri = "";
  711. }
  712. if ("".equals(uri)) {
  713. return true;
  714. }
  715. if (parentUri.equals(ProjectHelper.ANT_CORE_URI)) {
  716. parentUri = "";
  717. }
  718. return uri.equals(parentUri);
  719. }
  720. /**
  721. * Stores a named nested element using a storage method determined
  722. * by the initial introspection. If no appropriate storage method
  723. * is available, this method returns immediately.
  724. *
  725. * @param project Ignored in this implementation.
  726. * May be <code>null</code>.
  727. *
  728. * @param parent Parent instance to store the child in.
  729. * Must not be <code>null</code>.
  730. *
  731. * @param child Child instance to store in the parent.
  732. * Should not be <code>null</code>.
  733. *
  734. * @param elementName Name of the child element to store.
  735. * May be <code>null</code>, in which case
  736. * this method returns immediately.
  737. *
  738. * @exception BuildException if the storage method fails.
  739. */
  740. public void storeElement(final Project project, final Object parent, final Object child,
  741. final String elementName) throws BuildException {
  742. if (elementName == null) {
  743. return;
  744. }
  745. final NestedCreator ns = nestedCreators.get(elementName.toLowerCase(Locale.ENGLISH));
  746. if (ns == null) {
  747. return;
  748. }
  749. try {
  750. ns.store(parent, child);
  751. } catch (final IllegalAccessException ie) {
  752. // impossible as getMethods should only return public methods
  753. throw new BuildException(ie);
  754. } catch (final InstantiationException ine) {
  755. // impossible as getMethods should only return public methods
  756. throw new BuildException(ine);
  757. } catch (final InvocationTargetException ite) {
  758. throw extractBuildException(ite);
  759. }
  760. }
  761. /**
  762. * Helper method to extract the inner fault from an {@link InvocationTargetException}, and turn
  763. * it into a BuildException. If it is already a BuildException, it is type cast and returned; if
  764. * not a new BuildException is created containing the child as nested text.
  765. * @param ite the exception
  766. * @return the nested exception
  767. */
  768. private static BuildException extractBuildException(final InvocationTargetException ite) {
  769. final Throwable t = ite.getTargetException();
  770. if (t instanceof BuildException) {
  771. return (BuildException) t;
  772. }
  773. return new BuildException(t);
  774. }
  775. /**
  776. * Returns the type of a named nested element.
  777. *
  778. * @param elementName The name of the element to find the type of.
  779. * Must not be <code>null</code>.
  780. *
  781. * @return the type of the nested element with the specified name.
  782. * This will never be <code>null</code>.
  783. *
  784. * @exception BuildException if the introspected class does not
  785. * support the named nested element.
  786. */
  787. public Class<?> getElementType(final String elementName) throws BuildException {
  788. final Class<?> nt = nestedTypes.get(elementName);
  789. if (nt == null) {
  790. throw new UnsupportedElementException("Class "
  791. + bean.getName() + " doesn't support the nested \""
  792. + elementName + "\" element.", elementName);
  793. }
  794. return nt;
  795. }
  796. /**
  797. * Returns the type of a named attribute.
  798. *
  799. * @param attributeName The name of the attribute to find the type of.
  800. * Must not be <code>null</code>.
  801. *
  802. * @return the type of the attribute with the specified name.
  803. * This will never be <code>null</code>.
  804. *
  805. * @exception BuildException if the introspected class does not
  806. * support the named attribute.
  807. */
  808. public Class<?> getAttributeType(final String attributeName) throws BuildException {
  809. final Class<?> at = attributeTypes.get(attributeName);
  810. if (at == null) {
  811. throw new UnsupportedAttributeException("Class "
  812. + bean.getName() + " doesn't support the \""
  813. + attributeName + "\" attribute.", attributeName);
  814. }
  815. return at;
  816. }
  817. /**
  818. * Returns the addText method when the introspected
  819. * class supports nested text.
  820. *
  821. * @return the method on this introspected class that adds nested text.
  822. * Cannot be <code>null</code>.
  823. * @throws BuildException if the introspected class does not
  824. * support the nested text.
  825. * @since Ant 1.6.3
  826. */
  827. public Method getAddTextMethod() throws BuildException {
  828. if (!supportsCharacters()) {
  829. throw new BuildException("Class " + bean.getName()
  830. + " doesn't support nested text data.");
  831. }
  832. return addText;
  833. }
  834. /**
  835. * Returns the adder or creator method of a named nested element.
  836. *
  837. * @param elementName The name of the attribute to find the setter
  838. * method of. Must not be <code>null</code>.
  839. * @return the method on this introspected class that adds or creates this
  840. * nested element. Can be <code>null</code> when the introspected
  841. * class is a dynamic configurator!
  842. * @throws BuildException if the introspected class does not
  843. * support the named nested element.
  844. * @since Ant 1.6.3
  845. */
  846. public Method getElementMethod(final String elementName) throws BuildException {
  847. final Object creator = nestedCreators.get(elementName);
  848. if (creator == null) {
  849. throw new UnsupportedElementException("Class "
  850. + bean.getName() + " doesn't support the nested \""
  851. + elementName + "\" element.", elementName);
  852. }
  853. return ((NestedCreator) creator).method;
  854. }
  855. /**
  856. * Returns the setter method of a named attribute.
  857. *
  858. * @param attributeName The name of the attribute to find the setter
  859. * method of. Must not be <code>null</code>.
  860. * @return the method on this introspected class that sets this attribute.
  861. * This will never be <code>null</code>.
  862. * @throws BuildException if the introspected class does not
  863. * support the named attribute.
  864. * @since Ant 1.6.3
  865. */
  866. public Method getAttributeMethod(final String attributeName) throws BuildException {
  867. final Object setter = attributeSetters.get(attributeName);
  868. if (setter == null) {
  869. throw new UnsupportedAttributeException("Class "
  870. + bean.getName() + " doesn't support the \""
  871. + attributeName + "\" attribute.", attributeName);
  872. }
  873. return ((AttributeSetter) setter).method;
  874. }
  875. /**
  876. * Returns whether or not the introspected class supports PCDATA.
  877. *
  878. * @return whether or not the introspected class supports PCDATA.
  879. */
  880. public boolean supportsCharacters() {
  881. return addText != null;
  882. }
  883. /**
  884. * Returns an enumeration of the names of the attributes supported by the introspected class.
  885. *
  886. * @return an enumeration of the names of the attributes supported by the introspected class.
  887. * @see #getAttributeMap
  888. */
  889. public Enumeration<String> getAttributes() {
  890. return Collections.enumeration(attributeSetters.keySet());
  891. }
  892. /**
  893. * Returns a read-only map of attributes supported by the introspected class.
  894. *
  895. * @return an attribute name to attribute <code>Class</code>
  896. * unmodifiable map. Can be empty, but never <code>null</code>.
  897. * @since Ant 1.6.3
  898. */
  899. public Map<String, Class<?>> getAttributeMap() {
  900. return attributeTypes.isEmpty()
  901. ? Collections.emptyMap() : Collections.unmodifiableMap(attributeTypes);
  902. }
  903. /**
  904. * Returns an enumeration of the names of the nested elements supported
  905. * by the introspected class.
  906. *
  907. * @return an enumeration of the names of the nested elements supported
  908. * by the introspected class.
  909. * @see #getNestedElementMap
  910. */
  911. public Enumeration<String> getNestedElements() {
  912. return Collections.enumeration(nestedTypes.keySet());
  913. }
  914. /**
  915. * Returns a read-only map of nested elements supported
  916. * by the introspected class.
  917. *
  918. * @return a nested-element name to nested-element <code>Class</code>
  919. * unmodifiable map. Can be empty, but never <code>null</code>.
  920. * @since Ant 1.6.3
  921. */
  922. public Map<String, Class<?>> getNestedElementMap() {
  923. return nestedTypes.isEmpty()
  924. ? Collections.emptyMap() : Collections.unmodifiableMap(nestedTypes);
  925. }
  926. /**
  927. * Returns a read-only list of extension points supported
  928. * by the introspected class.
  929. * <p>
  930. * A task/type or nested element with void methods named <code>add()</code>
  931. * or <code>addConfigured()</code>, taking a single class or interface
  932. * argument, supports extensions point. This method returns the list of
  933. * all these <em>void add[Configured](type)</em> methods.
  934. *
  935. * @return a list of void, single argument add() or addConfigured()
  936. * <code>Method</code>s of all supported extension points.
  937. * These methods are sorted such that if the argument type of a
  938. * method derives from another type also an argument of a method
  939. * of this list, the method with the most derived argument will
  940. * always appear first. Can be empty, but never <code>null</code>.
  941. * @since Ant 1.6.3
  942. */
  943. public List<Method> getExtensionPoints() {
  944. return addTypeMethods.isEmpty()
  945. ? Collections.emptyList() : Collections.unmodifiableList(addTypeMethods);
  946. }
  947. /**
  948. * Creates an implementation of AttributeSetter for the given
  949. * attribute type. Conversions (where necessary) are automatically
  950. * made for the following types:
  951. * <ul>
  952. * <li>String (left as it is)
  953. * <li>Character/char (first character is used)
  954. * <li>Boolean/boolean
  955. * ({@link Project#toBoolean(String) Project.toBoolean(String)} is used)
  956. * <li>Class (Class.forName is used)
  957. * <li>File (resolved relative to the appropriate project)
  958. * <li>Path (resolve relative to the appropriate project)
  959. * <li>Resource (resolved as a FileResource relative to the appropriate project)
  960. * <li>FileProvider (resolved as a FileResource relative to the appropriate project)
  961. * <li>EnumeratedAttribute (uses its own
  962. * {@link EnumeratedAttribute#setValue(String) setValue} method)
  963. * <li>Other primitive types (wrapper classes are used with constructors
  964. * taking String)
  965. * </ul>
  966. *
  967. * If none of the above covers the given parameters, a constructor for the
  968. * appropriate class taking a String parameter is used if it is available.
  969. *
  970. * @param m The method to invoke on the bean when the setter is invoked.
  971. * Must not be <code>null</code>.
  972. * @param arg The type of the single argument of the bean's method.
  973. * Must not be <code>null</code>.
  974. * @param attrName the name of the attribute for which the setter is being
  975. * created.
  976. *
  977. * @return an appropriate AttributeSetter instance, or <code>null</code>
  978. * if no appropriate conversion is available.
  979. */
  980. private AttributeSetter createAttributeSetter(final Method m,
  981. final Class<?> arg,
  982. final String attrName) {
  983. // use wrappers for primitive classes, e.g. int and
  984. // Integer are treated identically
  985. final Class<?> reflectedArg = PRIMITIVE_TYPE_MAP.containsKey(arg)
  986. ? PRIMITIVE_TYPE_MAP.get(arg) : arg;
  987. // Object.class - it gets handled differently by AttributeSetter
  988. if (java.lang.Object.class == reflectedArg) {
  989. return new AttributeSetter(m, arg) {
  990. @Override
  991. public void set(final Project p, final Object parent, final String value)
  992. throws InvocationTargetException,
  993. IllegalAccessException {
  994. throw new BuildException(
  995. "Internal ant problem - this should not get called");
  996. }
  997. };
  998. }
  999. // simplest case - setAttribute expects String
  1000. if (String.class.equals(reflectedArg)) {
  1001. return new AttributeSetter(m, arg) {
  1002. @Override
  1003. public void set(final Project p, final Object parent, final String value)
  1004. throws InvocationTargetException, IllegalAccessException {
  1005. m.invoke(parent, (Object[]) new String[] {value});
  1006. }
  1007. };
  1008. }
  1009. // char and Character get special treatment - take the first character
  1010. if (java.lang.Character.class.equals(reflectedArg)) {
  1011. return new AttributeSetter(m, arg) {
  1012. @Override
  1013. public void set(final Project p, final Object parent, final String value)
  1014. throws InvocationTargetException, IllegalAccessException {
  1015. if (value.length() == 0) {
  1016. throw new BuildException("The value \"\" is not a "
  1017. + "legal value for attribute \"" + attrName + "\"");
  1018. }
  1019. m.invoke(parent, (Object[]) new Character[] {value.charAt(0)});
  1020. }
  1021. };
  1022. }
  1023. // boolean and Boolean get special treatment because we have a nice method in Project
  1024. if (java.lang.Boolean.class.equals(reflectedArg)) {
  1025. return new AttributeSetter(m, arg) {
  1026. @Override
  1027. public void set(final Project p, final Object parent, final String value)
  1028. throws InvocationTargetException, IllegalAccessException {
  1029. m.invoke(parent, (Object[]) new Boolean[] {
  1030. Project.toBoolean(value) ? Boolean.TRUE : Boolean.FALSE });
  1031. }
  1032. };
  1033. }
  1034. // Class doesn't have a String constructor but a decent factory method
  1035. if (java.lang.Class.class.equals(reflectedArg)) {
  1036. return new AttributeSetter(m, arg) {
  1037. @Override
  1038. public void set(final Project p, final Object parent, final String value)
  1039. throws InvocationTargetException, IllegalAccessException, BuildException {
  1040. try {
  1041. m.invoke(parent, Class.forName(value));
  1042. } catch (final ClassNotFoundException ce) {
  1043. throw new BuildException(ce);
  1044. }
  1045. }
  1046. };
  1047. }
  1048. // resolve relative paths through Project
  1049. if (java.io.File.class.equals(reflectedArg)) {
  1050. return new AttributeSetter(m, arg) {
  1051. @Override
  1052. public void set(final Project p, final Object parent, final String value)
  1053. throws InvocationTargetException, IllegalAccessException {
  1054. m.invoke(parent, p.resolveFile(value));
  1055. }
  1056. };
  1057. }
  1058. // resolve relative nio paths through Project
  1059. if (java.nio.file.Path.class.equals(reflectedArg)) {
  1060. return new AttributeSetter(m, arg) {
  1061. @Override
  1062. public void set(final Project p, final Object parent, final String value)
  1063. throws InvocationTargetException, IllegalAccessException {
  1064. m.invoke(parent, p.resolveFile(value).toPath());
  1065. }
  1066. };
  1067. }
  1068. // resolve Resources/FileProviders as FileResources relative to Project:
  1069. if (Resource.class.equals(reflectedArg) || FileProvider.class.equals(reflectedArg)) {
  1070. return new AttributeSetter(m, arg) {
  1071. @Override
  1072. void set(final Project p, final Object parent, final String value)
  1073. throws InvocationTargetException, IllegalAccessException, BuildException {
  1074. m.invoke(parent, new FileResource(p, p.resolveFile(value)));
  1075. }
  1076. };
  1077. }
  1078. // EnumeratedAttributes have their own helper class
  1079. if (EnumeratedAttribute.class.isAssignableFrom(reflectedArg)) {
  1080. return new AttributeSetter(m, arg) {
  1081. @Override
  1082. public void set(final Project p, final Object parent, final String value)
  1083. throws InvocationTargetException, IllegalAccessException, BuildException {
  1084. try {
  1085. final EnumeratedAttribute ea = (EnumeratedAttribute) reflectedArg.newInstance();
  1086. ea.setValue(value);
  1087. m.invoke(parent, ea);
  1088. } catch (final InstantiationException ie) {
  1089. throw new BuildException(ie);
  1090. }
  1091. }
  1092. };
  1093. }
  1094. final AttributeSetter setter = getEnumSetter(reflectedArg, m, arg);
  1095. if (setter != null) {
  1096. return setter;
  1097. }
  1098. if (java.lang.Long.class.equals(reflectedArg)) {
  1099. return new AttributeSetter(m, arg) {
  1100. @Override
  1101. public void set(final Project p, final Object parent, final String value)
  1102. throws InvocationTargetException, IllegalAccessException, BuildException {
  1103. try {
  1104. m.invoke(parent, StringUtils.parseHumanSizes(value));
  1105. } catch (final NumberFormatException e) {
  1106. throw new BuildException("Can't assign non-numeric"
  1107. + " value '" + value + "' to"
  1108. + " attribute " + attrName);
  1109. } catch (final InvocationTargetException e) {
  1110. throw e;
  1111. } catch (final IllegalAccessException e) {
  1112. throw e;
  1113. } catch (final Exception e) {
  1114. throw new BuildException(e);
  1115. }
  1116. }
  1117. };
  1118. }
  1119. // worst case. look for a public String constructor and use it
  1120. // also supports new Whatever(Project, String) as for Path or Reference
  1121. // This is used (deliberately) for all primitives/wrappers other than
  1122. // char, boolean, and long.
  1123. boolean includeProject;
  1124. Constructor<?> c;
  1125. try {
  1126. // First try with Project.
  1127. c = reflectedArg.getConstructor(Project.class, String.class);
  1128. includeProject = true;
  1129. } catch (final NoSuchMethodException nme) {
  1130. // OK, try without.
  1131. try {
  1132. c = reflectedArg.getConstructor(String.class);
  1133. includeProject = false;
  1134. } catch (final NoSuchMethodException nme2) {
  1135. // Well, no matching constructor.
  1136. return null;
  1137. }
  1138. }
  1139. final boolean finalIncludeProject = includeProject;
  1140. final Constructor<?> finalConstructor = c;
  1141. return new AttributeSetter(m, arg) {
  1142. @Override
  1143. public void set(final Project p, final Object parent, final String value)
  1144. throws InvocationTargetException, IllegalAccessException, BuildException {
  1145. try {
  1146. final Object[] args = finalIncludeProject
  1147. ? new Object[] {p, value} : new Object[] {value};
  1148. final Object attribute = finalConstructor.newInstance(args);
  1149. if (p != null) {
  1150. p.setProjectReference(attribute);
  1151. }
  1152. m.invoke(parent, attribute);
  1153. } catch (final InvocationTargetException e) {
  1154. final Throwable cause = e.getCause();
  1155. if (cause instanceof IllegalArgumentException) {
  1156. throw new BuildException("Can't assign value '" + value
  1157. + "' to attribute " + attrName
  1158. + ", reason: "
  1159. + cause.getClass()
  1160. + " with message '"
  1161. + cause.getMessage() + "'");
  1162. }
  1163. throw e;
  1164. } catch (final InstantiationException ie) {
  1165. throw new BuildException(ie);
  1166. }
  1167. }
  1168. };
  1169. }
  1170. private AttributeSetter getEnumSetter(
  1171. final Class<?> reflectedArg, final Method m, final Class<?> arg) {
  1172. if (reflectedArg.isEnum()) {
  1173. return new AttributeSetter(m, arg) {
  1174. @Override
  1175. public void set(final Project p, final Object parent, final String value)
  1176. throws InvocationTargetException, IllegalAccessException,
  1177. BuildException {
  1178. Enum<?> setValue;
  1179. try {
  1180. @SuppressWarnings({ "unchecked", "rawtypes" })
  1181. final Enum<?> enumValue = Enum.valueOf((Class<? extends Enum>) reflectedArg,
  1182. value);
  1183. setValue = enumValue;
  1184. } catch (final IllegalArgumentException e) {
  1185. // there is a specific logic here for the value
  1186. // being out of the allowed set of enumerations.
  1187. throw new BuildException("'" + value + "' is not a permitted value for "
  1188. + reflectedArg.getName());
  1189. }
  1190. m.invoke(parent, setValue);
  1191. }
  1192. };
  1193. }
  1194. return null;
  1195. }
  1196. /**
  1197. * Returns a description of the type of the given element in
  1198. * relation to a given project. This is used for logging purposes
  1199. * when the element is asked to cope with some data it has no way of handling.
  1200. *
  1201. * @param project The project the element is defined in. Must not be <code>null</code>.
  1202. *
  1203. * @param element The element to describe. Must not be <code>null</code>.
  1204. *
  1205. * @return a description of the element type
  1206. */
  1207. private String getElementName(final Project project, final Object element) {
  1208. return project.getElementName(element);
  1209. }
  1210. /**
  1211. * Extracts the name of a property from a method name by subtracting
  1212. * a given prefix and converting into lower case. It is up to calling
  1213. * code to make sure the method name does actually begin with the
  1214. * specified prefix - no checking is done in this method.
  1215. *
  1216. * @param methodName The name of the method in question. Must not be <code>null</code>.
  1217. * @param prefix The prefix to remove. Must not be <code>null</code>.
  1218. *
  1219. * @return the lower-cased method name with the prefix removed.
  1220. */
  1221. private static String getPropertyName(final String methodName, final String prefix) {
  1222. return methodName.substring(prefix.length()).toLowerCase(Locale.ENGLISH);
  1223. }
  1224. /**
  1225. * creator - allows use of create/store external
  1226. * to IntrospectionHelper.
  1227. * The class is final as it has a private constructor.
  1228. */
  1229. public static final class Creator {
  1230. private final NestedCreator nestedCreator;
  1231. private final Object parent;
  1232. private final Project project;
  1233. private Object nestedObject;
  1234. private String polyType;
  1235. /**
  1236. * Creates a new Creator instance.
  1237. * This object is given to the UnknownElement to create
  1238. * objects for sub-elements. UnknownElement calls
  1239. * create to create an object, the object then gets
  1240. * configured and then UnknownElement calls store.
  1241. * SetPolyType may be used to override the type used
  1242. * to create the object with. SetPolyType gets called before create.
  1243. *
  1244. * @param project the current project
  1245. * @param parent the parent object to create the object in
  1246. * @param nestedCreator the nested creator object to use
  1247. */
  1248. private Creator(final Project project, final Object parent, final NestedCreator nestedCreator) {
  1249. this.project = project;
  1250. this.parent = parent;
  1251. this.nestedCreator = nestedCreator;
  1252. }
  1253. /**
  1254. * Used to override the class used to create the object.
  1255. *
  1256. * @param polyType a ant component type name
  1257. */
  1258. public void setPolyType(final String polyType) {
  1259. this.polyType = polyType;
  1260. }
  1261. /**
  1262. * Create an object using this creator, which is determined by introspection.
  1263. *
  1264. * @return the created object
  1265. */
  1266. public Object create() {
  1267. if (polyType != null) {
  1268. if (!nestedCreator.isPolyMorphic()) {
  1269. throw new BuildException(
  1270. "Not allowed to use the polymorphic form for this element");
  1271. }
  1272. final ComponentHelper helper = ComponentHelper.getComponentHelper(project);
  1273. nestedObject = helper.createComponent(polyType);
  1274. if (nestedObject == null) {
  1275. throw new BuildException("Unable to create object of type " + polyType);
  1276. }
  1277. }
  1278. try {
  1279. nestedObject = nestedCreator.create(project, parent, nestedObject);
  1280. if (project != null) {
  1281. project.setProjectReference(nestedObject);
  1282. }
  1283. return nestedObject;
  1284. } catch (final IllegalAccessException ex) {
  1285. throw new BuildException(ex);
  1286. } catch (final InstantiationException ex) {
  1287. throw new BuildException(ex);
  1288. } catch (final IllegalArgumentException ex) {
  1289. if (polyType == null) {
  1290. throw ex;
  1291. }
  1292. throw new BuildException("Invalid type used " + polyType);
  1293. } catch (final InvocationTargetException ex) {
  1294. throw extractBuildException(ex);
  1295. }
  1296. }
  1297. /**
  1298. * @return the real object (used currently only for presetdef).
  1299. */
  1300. public Object getRealObject() {
  1301. return nestedCreator.getRealObject();
  1302. }
  1303. /**
  1304. * Stores the nested element object using a storage method determined by introspection.
  1305. *
  1306. */
  1307. public void store() {
  1308. try {
  1309. nestedCreator.store(parent, nestedObject);
  1310. } catch (final IllegalAccessException ex) {
  1311. throw new BuildException(ex);
  1312. } catch (final InstantiationException ex) {
  1313. throw new BuildException(ex);
  1314. } catch (final IllegalArgumentException ex) {
  1315. if (polyType == null) {
  1316. throw ex;
  1317. }
  1318. throw new BuildException("Invalid type used " + polyType);
  1319. } catch (final InvocationTargetException ex) {
  1320. throw extractBuildException(ex);
  1321. }
  1322. }
  1323. }
  1324. /**
  1325. * Internal interface used to create nested elements. Not documented
  1326. * in detail for reasons of source code readability.
  1327. */
  1328. private abstract static class NestedCreator {
  1329. private final Method method; // the method called to add/create the nested element
  1330. protected NestedCreator(final Method m) {
  1331. method = m;
  1332. }
  1333. Method getMethod() {
  1334. return method;
  1335. }
  1336. boolean isPolyMorphic() {
  1337. return false;
  1338. }
  1339. Object getRealObject() {
  1340. return null;
  1341. }
  1342. abstract Object create(Project project, Object parent, Object child)
  1343. throws InvocationTargetException, IllegalAccessException, InstantiationException;
  1344. void store(final Object parent, final Object child)
  1345. throws InvocationTargetException, IllegalAccessException, InstantiationException {
  1346. // DO NOTHING
  1347. }
  1348. }
  1349. private static class CreateNestedCreator extends NestedCreator {
  1350. CreateNestedCreator(final Method m) {
  1351. super(m);
  1352. }
  1353. @Override
  1354. Object create(final Project project, final Object parent, final Object ignore)
  1355. throws InvocationTargetException, IllegalAccessException {
  1356. return getMethod().invoke(parent);
  1357. }
  1358. }
  1359. /** Version to use for addXXX and addConfiguredXXX */
  1360. private static class AddNestedCreator extends NestedCreator {
  1361. static final int ADD = 1;
  1362. static final int ADD_CONFIGURED = 2;
  1363. private final Constructor<?> constructor;
  1364. private final int behavior; // ADD or ADD_CONFIGURED
  1365. AddNestedCreator(final Method m, final Constructor<?> c, final int behavior) {
  1366. super(m);
  1367. this.constructor = c;
  1368. this.behavior = behavior;
  1369. }
  1370. @Override
  1371. boolean isPolyMorphic() {
  1372. return true;
  1373. }
  1374. @Override
  1375. Object create(final Project project, final Object parent, Object child)
  1376. throws InvocationTargetException, IllegalAccessException, InstantiationException {
  1377. if (child == null) {
  1378. child = constructor.newInstance(
  1379. constructor.getParameterTypes().length == 0
  1380. ? new Object[] {} : new Object[] {project});
  1381. }
  1382. if (child instanceof PreSetDef.PreSetDefinition) {
  1383. child = ((PreSetDef.PreSetDefinition) child).createObject(project);
  1384. }
  1385. if (behavior == ADD) {
  1386. istore(parent, child);
  1387. }
  1388. return child;
  1389. }
  1390. @Override
  1391. void store(final Object parent, final Object child)
  1392. throws InvocationTargetException, IllegalAccessException, InstantiationException {
  1393. if (behavior == ADD_CONFIGURED) {
  1394. istore(parent, child);
  1395. }
  1396. }
  1397. private void istore(final Object parent, final Object child)
  1398. throws InvocationTargetException, IllegalAccessException {
  1399. getMethod().invoke(parent, child);
  1400. }
  1401. }
  1402. /**
  1403. * Internal interface used to setting element attributes. Not documented
  1404. * in detail for reasons of source code readability.
  1405. */
  1406. private abstract static class AttributeSetter {
  1407. private final Method method; // the method called to set the attribute
  1408. private final Class<?> type;
  1409. protected AttributeSetter(final Method m, final Class<?> type) {
  1410. method = m;
  1411. this.type = type;
  1412. }
  1413. void setObject(final Project p, final Object parent, final Object value)
  1414. throws InvocationTargetException, IllegalAccessException, BuildException {
  1415. if (type != null) {
  1416. Class<?> useType = type;
  1417. if (type.isPrimitive()) {
  1418. if (value == null) {
  1419. throw new BuildException(
  1420. "Attempt to set primitive "
  1421. + getPropertyName(method.getName(), "set")
  1422. + " to null on " + parent);
  1423. }
  1424. useType = PRIMITIVE_TYPE_MAP.get(type);
  1425. }
  1426. if (value == null || useType.isInstance(value)) {
  1427. method.invoke(parent, value);
  1428. return;
  1429. }
  1430. }
  1431. set(p, parent, value.toString());
  1432. }
  1433. abstract void set(Project p, Object parent, String value)
  1434. throws InvocationTargetException, IllegalAccessException, BuildException;
  1435. }
  1436. /**
  1437. * Clears the static cache of on build finished.
  1438. */
  1439. public static synchronized void clearCache() {
  1440. HELPERS.clear();
  1441. }
  1442. /**
  1443. * Create a NestedCreator for the given element.
  1444. * @param project owning project
  1445. * @param parent Parent object used to create the instance.
  1446. * @param elementName name of the element
  1447. * @return a nested creator, or null if there is no component of the given name, or it
  1448. * has no matching add type methods
  1449. * @throws BuildException if something goes wrong
  1450. */
  1451. private NestedCreator createAddTypeCreator(
  1452. final Project project, final Object parent, final String elementName) throws BuildException {
  1453. if (addTypeMethods.isEmpty()) {
  1454. return null;
  1455. }
  1456. final ComponentHelper helper = ComponentHelper.getComponentHelper(project);
  1457. final MethodAndObject restricted = createRestricted(helper, elementName, addTypeMethods);
  1458. final MethodAndObject topLevel = createTopLevel(helper, elementName, addTypeMethods);
  1459. if (restricted == null && topLevel == null) {
  1460. return null;
  1461. }
  1462. if (restricted != null && topLevel != null) {
  1463. throw new BuildException(
  1464. "ambiguous: type and component definitions for "
  1465. + elementName);
  1466. }
  1467. final MethodAndObject methodAndObject = restricted == null ? topLevel : restricted;
  1468. Object rObject = methodAndObject.object;
  1469. if (methodAndObject.object instanceof PreSetDef.PreSetDefinition) {
  1470. rObject = ((PreSetDef.PreSetDefinition) methodAndObject.object)
  1471. .createObject(project);
  1472. }
  1473. final Object nestedObject = methodAndObject.object;
  1474. final Object realObject = rObject;
  1475. return new NestedCreator(methodAndObject.method) {
  1476. @Override
  1477. Object create(final Project project, final Object parent, final Object ignore)
  1478. throws InvocationTargetException, IllegalAccessException {
  1479. if (!getMethod().getName().endsWith("Configured")) {
  1480. getMethod().invoke(parent, realObject);
  1481. }
  1482. return nestedObject;
  1483. }
  1484. @Override
  1485. Object getRealObject() {
  1486. return realObject;
  1487. }
  1488. @Override
  1489. void store(final Object parent, final Object child) throws InvocationTargetException,
  1490. IllegalAccessException, InstantiationException {
  1491. if (getMethod().getName().endsWith("Configured")) {
  1492. getMethod().invoke(parent, realObject);
  1493. }
  1494. }
  1495. };
  1496. }
  1497. /**
  1498. * Inserts an add or addConfigured method into
  1499. * the addTypeMethods array. The array is
  1500. * ordered so that the more derived classes are first.
  1501. * If both add and addConfigured are present, the addConfigured will take priority.
  1502. * @param method the <code>Method</code> to insert.
  1503. */
  1504. private void insertAddTypeMethod(final Method method) {
  1505. final Class<?> argClass = method.getParameterTypes()[0];
  1506. final int size = addTypeMethods.size();
  1507. for (int c = 0; c < size; ++c) {
  1508. final Method current = addTypeMethods.get(c);
  1509. if (current.getParameterTypes()[0].equals(argClass)) {
  1510. if ("addConfigured".equals(method.getName())) {
  1511. // add configured replaces the add method
  1512. addTypeMethods.set(c, method);
  1513. }
  1514. return; // Already present
  1515. }
  1516. if (current.getParameterTypes()[0].isAssignableFrom(argClass)) {
  1517. addTypeMethods.add(c, method);
  1518. return; // higher derived
  1519. }
  1520. }
  1521. addTypeMethods.add(method);
  1522. }
  1523. /**
  1524. * Search the list of methods to find the first method
  1525. * that has a parameter that accepts the nested element object.
  1526. * @param paramClass the <code>Class</code> type to search for.
  1527. * @param methods the <code>List</code> of methods to search.
  1528. * @return a matching <code>Method</code>; null if none found.
  1529. */
  1530. private Method findMatchingMethod(final Class<?> paramClass, final List<Method> methods) {
  1531. if (paramClass == null) {
  1532. return null;
  1533. }
  1534. Class<?> matchedClass = null;
  1535. Method matchedMethod = null;
  1536. for (final Method method : methods) {
  1537. final Class<?> methodClass = method.getParameterTypes()[0];
  1538. if (methodClass.isAssignableFrom(paramClass)) {
  1539. if (matchedClass == null) {
  1540. matchedClass = methodClass;
  1541. matchedMethod = method;
  1542. } else if (!methodClass.isAssignableFrom(matchedClass)) {
  1543. throw new BuildException("ambiguous: types " + matchedClass.getName() + " and "
  1544. + methodClass.getName() + " match " + paramClass.getName());
  1545. }
  1546. }
  1547. }
  1548. return matchedMethod;
  1549. }
  1550. private String condenseText(final String text) {
  1551. if (text.length() <= MAX_REPORT_NESTED_TEXT) {
  1552. return text;
  1553. }
  1554. final int ends = (MAX_REPORT_NESTED_TEXT - ELLIPSIS.length()) / 2;
  1555. return new StringBuffer(text).replace(ends, text.length() - ends, ELLIPSIS).toString();
  1556. }
  1557. private static class MethodAndObject {
  1558. private final Method method;
  1559. private final Object object;
  1560. public MethodAndObject(final Method method, final Object object) {
  1561. this.method = method;
  1562. this.object = object;
  1563. }
  1564. }
  1565. /**
  1566. *
  1567. */
  1568. private AntTypeDefinition findRestrictedDefinition(
  1569. final ComponentHelper helper, final String componentName, final List<Method> methods) {
  1570. AntTypeDefinition definition = null;
  1571. Class<?> matchedDefinitionClass = null;
  1572. final List<AntTypeDefinition> definitions = helper.getRestrictedDefinitions(componentName);
  1573. if (definitions == null) {
  1574. return null;
  1575. }
  1576. synchronized (definitions) {
  1577. for (final AntTypeDefinition d : definitions) {
  1578. final Class<?> exposedClass = d.getExposedClass(helper.getProject());
  1579. if (exposedClass == null) {
  1580. continue;
  1581. }
  1582. final Method method = findMatchingMethod(exposedClass, methods);
  1583. if (method == null) {
  1584. continue;
  1585. }
  1586. if (matchedDefinitionClass != null) {
  1587. throw new BuildException(
  1588. "ambiguous: restricted definitions for "
  1589. + componentName + " "
  1590. + matchedDefinitionClass + " and " + exposedClass);
  1591. }
  1592. matchedDefinitionClass = exposedClass;
  1593. definition = d;
  1594. }
  1595. }
  1596. return definition;
  1597. }
  1598. private MethodAndObject createRestricted(
  1599. final ComponentHelper helper, final String elementName, final List<Method> addTypeMethods) {
  1600. final Project project = helper.getProject();
  1601. final AntTypeDefinition restrictedDefinition =
  1602. findRestrictedDefinition(helper, elementName, addTypeMethods);
  1603. if (restrictedDefinition == null) {
  1604. return null;
  1605. }
  1606. final Method addMethod = findMatchingMethod(
  1607. restrictedDefinition.getExposedClass(project), addTypeMethods);
  1608. if (addMethod == null) {
  1609. throw new BuildException("Ant Internal Error - contract mismatch for "
  1610. + elementName);
  1611. }
  1612. final Object addedObject = restrictedDefinition.create(project);
  1613. if (addedObject == null) {
  1614. throw new BuildException(
  1615. "Failed to create object " + elementName
  1616. + " of type " + restrictedDefinition.getTypeClass(project));
  1617. }
  1618. return new MethodAndObject(addMethod, addedObject);
  1619. }
  1620. private MethodAndObject createTopLevel(
  1621. final ComponentHelper helper, final String elementName, final List<Method> methods) {
  1622. final Class<?> clazz = helper.getComponentClass(elementName);
  1623. if (clazz == null) {
  1624. return null;
  1625. }
  1626. final Method addMethod = findMatchingMethod(clazz, addTypeMethods);
  1627. if (addMethod == null) {
  1628. return null;
  1629. }
  1630. final Object addedObject = helper.createComponent(elementName);
  1631. return new MethodAndObject(addMethod, addedObject);
  1632. }
  1633. }