Bug 49891 - Nested subant does not allow override of properties.
Summary: Nested subant does not allow override of properties.
Alias: None
Product: Ant
Classification: Unclassified
Component: Documentation (show other bugs)
Version: 1.8.0
Hardware: All All
: P2 regression with 1 vote (vote)
Target Milestone: ---
Assignee: Ant Notifications List
Depends on:
Reported: 2010-09-07 09:22 UTC by Ben Hale
Modified: 2014-06-25 09:19 UTC (History)
1 user (show)

Adding checks in addAlmostAll (1.35 KB, patch)
2014-02-02 18:46 UTC, Christian Hartmann
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Ben Hale 2010-09-07 09:22:06 UTC
When using <subant/> more than one level deep, properties are not overridden properly after the first level.

The test case works as follows:

Level 1:
  * A property is defined
  * <subant/> is called redefining the value of the property

Level 2:
 * The property is expected to be the redefined value (and is for 1.7.x and 1.8.x)
 * <subant/> is called redefining the value of the property again.

Level 3:
 * The property is expected to be the redefined value (and is for 1.7.x but is *not* for 1.8.x)

Using the attached build.xml file you'll see an output of the following with 1.7.1

Buildfile: build.xml


     [echo] Expecting 'bravo', actual 'bravo'

     [echo] Expecting 'charlie', actual 'charlie'

Total time: 0 seconds

You'll see the following with 1.8.1.
Buildfile: /Users/benhale/Desktop/build.xml


     [echo] Expecting 'bravo', actual 'bravo'

     [echo] Expecting 'charlie', actual 'bravo'

Total time: 0 seconds
Comment 1 Stefan Bodewig 2010-09-21 11:02:05 UTC
I assume the build file looks similar to this

<project default="level-1">
  <target name="level-1">
    <property name="p" value="alpha"/>
    <subant target="level-2">
      <file file="subant.xml"/>
      <property name="p" value="bravo"/>

  <target name="level-2">
    <echo>Expecting 'bravo', actual '${p}'</echo>
    <subant target="level-3">
      <file file="subant.xml"/>
      <property name="p" value="charlie"/>

  <target name="level-3">
    <echo>Expecting 'charlie', actual '${p}'</echo>
Comment 2 Stefan Bodewig 2010-09-21 11:15:49 UTC
In the twisted way Ant properties are supposed to work Ant 1.8.x's behavior is correct.

If you take the <ant> task manual page it says 

> Properties defined on the command line cannot be overridden
> by nested <property> elements.

in the "Description" section and

> These properties become equivalent to properties you define on
> the command line.

in the section describing the nested property element of <ant>.

What happens is that starting with the project executing level-2 the property
p (in my build file) looks as if it had been set on the command line and
so the next subant call is unable to override its value.
Comment 3 Ben Hale 2010-09-21 11:33:49 UTC
Sorry about the attachment being missing, not sure what happened there.  In addition, I don't dispute that it's working per those instructions it's just that it's a undocumented change from the 1.7 line behavior.
Comment 4 Stefan Bodewig 2010-09-22 03:46:35 UTC
so what we need is better documentation, I'll look into it.

It is a bit too late to note this as a breaking change, maybe we can do that as part of the FAQ.  My guess is we've "fixed" subant by accident and didn't realize the change at all.
Comment 5 Stefan Bodewig 2010-09-22 03:57:44 UTC
svn revision 999791
Comment 6 Christian Hartmann 2014-02-02 18:46:42 UTC
Created attachment 31280 [details]
Adding checks in addAlmostAll

I came across the same problem and think I found the behaviour-changing cause between 1.7.1 and 1.8 (till 1.9.3).

In 1.8.0 a new method addAlmostAll() for copying properties was introduced in Ant.java. In the past that task was delegated to PropertyHelper.java and its copyXYProperties() methods. These methods check whether the target project already contains the property and don't override existing values. AFAIK these checks are missing in addAlmostAll().

Here's the implementation in copyUserProperties() with it's containsKey-check:

    public void copyUserProperties(Project other) {
        //avoid concurrent modification:
        synchronized (userProperties) {
            Enumeration<String> e = userProperties.keys();
            while (e.hasMoreElements()) {
                Object arg = e.nextElement();
                if (inheritedProperties.containsKey(arg)) {
                Object value = userProperties.get(arg);
                other.setUserProperty(arg.toString(), value.toString());

And here's the snippet from addAlmostAll()

    } else if (type == PropertyType.USER) {
        newProject.setUserProperty(key, value);

BTW, you can produce the same effect in 1.7.1, if you remove "continue".

The attached patch adds the same checks in addAlmostAll():

    } else if (type == PropertyType.USER) {
        if (!PropertyHelper.getPropertyHelper(this.getProject()).getInheritedProperties().containsKey(key)) {
            newProject.setUserProperty(key, value);

I am using this patch for several months without any (other) problem, but perhaps there are effects I don't see.

Here's the output of your example with the patched version:


     [echo] Expecting 'bravo', actual 'bravo'

     [echo] Expecting 'charlie', actual 'charlie'
Comment 7 Sjoerd van Leent 2014-06-25 09:19:13 UTC
Recently, at our office (Realworld Systems) we experienced issues with the same underlying problem. We usually use a build.properties file to override or introduce properties. However, on our CI (Jenkins) we encode these properties into the Jenkins environment.

This time, we had a certain property, which was altered with subant. On the command-line, on the developer's box, this was alright. However, the behavior of Ant inside the CI was quite different.

After experimenting a bit, we found out that these properies are set through the command-line, creating the same problem as already described.

Aside from the change to addAlmostAll, we would like to be able to have a tertiary property, indicating whether command-line properties should take precedence, or at least a way to indicate which command-line properties should be excluded from precedence.

To our understanding, the behavior, although documented, is illogical and contradicts with the normal expectation of the properties to be reset.