You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@commons.apache.org by Christian Migowski <ch...@gmail.com> on 2009/03/24 10:21:34 UTC

[commons-configuration] XMLConfiguration XPathExpressionEngine saving Lists error

Hi,

is this considered a bug:

If I load a list with commons-configuration, then add new entries to
that list and try to save it back to file, I get a
"java.lang.IllegalArgumentException: prepareAdd: Passed in key must
contain a whitespace!" exception.
If I do not modify the list, saving works.
If I remove entries from the list, saving works as well.

Very simple demo-program:

XML File:
<config>
   <liste>eintrag 1</liste>
   <liste>eintrag 2</liste>
   <liste>eintrag 3</liste>
</config>

program:

    public static void main(String[] args) {
        XMLConfiguration masterconfig;
        try {
            masterconfig = new XMLConfiguration("democonfig.xml");
            masterconfig.setExpressionEngine(new XPathExpressionEngine());

            List<String> test = masterconfig.getList("liste");

            masterconfig.setProperty("liste", test); //ok, no changes
            masterconfig.save();

            test.remove("eintrag 2");
            masterconfig.setProperty("liste", test); //ok, one <liste>
element is removed from file
            masterconfig.save();

            test.add("neuer eintrag");
            masterconfig.setProperty("liste", test); //exception
            masterconfig.save();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

I think commons-configuration should work consistent on all this cases.

best regards,
christian!

---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@commons.apache.org
For additional commands, e-mail: user-help@commons.apache.org


Re: [commons-configuration] XMLConfiguration XPathExpressionEngine saving Lists error

Posted by Christian Migowski <ch...@gmail.com>.
thanks for your explanation!

I browsed a little through the commons-configuration source, this
issue also seems hard to solve to me because of the "generic" approach
of commons-config and the "strict" structuring of XML.

Here is how I solved this issue, it may be a reference for others
facing similar problems or give you or the other developers an idea to
solve it better in commons-config. As you can see the code assumes the
last XML node to be the one that actually holds the list, which should
be almost always what you want to do (in opposite to having multiple
copies of the whole hierarchy). fileConfig is the XMLConfiguration (in
my case it is a HierarchicalConfiguration obtained with
configurationAt())

    protected void saveOrAddFileList(String key, List value) {
        fileConfig.clearProperty(key);

        if (key.contains("/")) {
            int lastElementPos = key.lastIndexOf('/');
            String parentElement = key.substring(0, lastElementPos);
            String newKey = parentElement + " " +
key.substring(lastElementPos + 1);
            if (!fileConfig.getKeys(parentElement).hasNext()) {
                fileConfig.addProperty(" " + parentElement, "");
            }
            fileConfig.addProperty(newKey, value);
        } else {
            fileConfig.addProperty(" " + key, value);
        }
}

christian!

On Tue, Mar 24, 2009 at 9:28 PM, Oliver Heger
<ol...@oliver-heger.de> wrote:
> Christian Migowski schrieb:
>>
>> Hi,
>>
>> is this considered a bug:
>>
>> If I load a list with commons-configuration, then add new entries to
>> that list and try to save it back to file, I get a
>> "java.lang.IllegalArgumentException: prepareAdd: Passed in key must
>> contain a whitespace!" exception.
>> If I do not modify the list, saving works.
>> If I remove entries from the list, saving works as well.
>>
>> Very simple demo-program:
>>
>> XML File:
>> <config>
>>   <liste>eintrag 1</liste>
>>   <liste>eintrag 2</liste>
>>   <liste>eintrag 3</liste>
>> </config>
>>
>> program:
>>
>>    public static void main(String[] args) {
>>        XMLConfiguration masterconfig;
>>        try {
>>            masterconfig = new XMLConfiguration("democonfig.xml");
>>            masterconfig.setExpressionEngine(new XPathExpressionEngine());
>>
>>            List<String> test = masterconfig.getList("liste");
>>
>>            masterconfig.setProperty("liste", test); //ok, no changes
>>            masterconfig.save();
>>
>>            test.remove("eintrag 2");
>>            masterconfig.setProperty("liste", test); //ok, one <liste>
>> element is removed from file
>>            masterconfig.save();
>>
>>            test.add("neuer eintrag");
>>            masterconfig.setProperty("liste", test); //exception
>>            masterconfig.save();
>>
>>        } catch (Exception e) {
>>            e.printStackTrace();
>>        }
>>    }
>>
>> I think commons-configuration should work consistent on all this cases.
>>
>> best regards,
>> christian!
>>
> At least I can explain what is happening here.
>
> When setProperty() is invoked with a list (or array) for the new property
> value, it does the following:
> - First it obtains the current values of the affected property (as a list).
> - It then iterates over both the list with the new values and the list with
> the current values.
> - As long as both lists have elements, the current elements are overridden
> by the new ones.
> - If at the end of the iteration the list with the current values has still
> more values (i.e. the list with the new values had fewer elements than the
> current values), the remaining elements are removed.
> - Otherwise, if the list with the new values has more elements, the
> additional values are added by calling addProperty().
>
> It is the last step that causes the problems you see. If an
> XPathExpressionEngine is used, addProperty() uses a special format for the
> properties keys: a path to an existing node (to which new data is to be
> added), followed by whitespace, followed by the name(s) of the new node(s)
> to be added. This is because we only can interpret XPath expressions on an
> existing nodes structure.
>
> Now, in your test program when you try to add a new element, addProperty()
> is called behind the scenes, but cannot interpret the passed in key.
>
> I agree that this is inconsistent, but unfortunately I don't know how to fix
> this. We might be able to work around the problem in some cases (e.g. if the
> property to be set has already some values, adding new elements can be
> performed directly on the nodes structure). But when setProperty() is used
> for adding a new property, I cannot see an easy solution.
>
> Oliver
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-unsubscribe@commons.apache.org
> For additional commands, e-mail: user-help@commons.apache.org
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@commons.apache.org
For additional commands, e-mail: user-help@commons.apache.org


Re: [commons-configuration] XMLConfiguration XPathExpressionEngine saving Lists error

Posted by Oliver Heger <ol...@oliver-heger.de>.
Christian Migowski schrieb:
> Hi,
> 
> is this considered a bug:
> 
> If I load a list with commons-configuration, then add new entries to
> that list and try to save it back to file, I get a
> "java.lang.IllegalArgumentException: prepareAdd: Passed in key must
> contain a whitespace!" exception.
> If I do not modify the list, saving works.
> If I remove entries from the list, saving works as well.
> 
> Very simple demo-program:
> 
> XML File:
> <config>
>    <liste>eintrag 1</liste>
>    <liste>eintrag 2</liste>
>    <liste>eintrag 3</liste>
> </config>
> 
> program:
> 
>     public static void main(String[] args) {
>         XMLConfiguration masterconfig;
>         try {
>             masterconfig = new XMLConfiguration("democonfig.xml");
>             masterconfig.setExpressionEngine(new XPathExpressionEngine());
> 
>             List<String> test = masterconfig.getList("liste");
> 
>             masterconfig.setProperty("liste", test); //ok, no changes
>             masterconfig.save();
> 
>             test.remove("eintrag 2");
>             masterconfig.setProperty("liste", test); //ok, one <liste>
> element is removed from file
>             masterconfig.save();
> 
>             test.add("neuer eintrag");
>             masterconfig.setProperty("liste", test); //exception
>             masterconfig.save();
> 
>         } catch (Exception e) {
>             e.printStackTrace();
>         }
>     }
> 
> I think commons-configuration should work consistent on all this cases.
> 
> best regards,
> christian!
> 
At least I can explain what is happening here.

When setProperty() is invoked with a list (or array) for the new 
property value, it does the following:
- First it obtains the current values of the affected property (as a list).
- It then iterates over both the list with the new values and the list 
with the current values.
- As long as both lists have elements, the current elements are 
overridden by the new ones.
- If at the end of the iteration the list with the current values has 
still more values (i.e. the list with the new values had fewer elements 
than the current values), the remaining elements are removed.
- Otherwise, if the list with the new values has more elements, the 
additional values are added by calling addProperty().

It is the last step that causes the problems you see. If an 
XPathExpressionEngine is used, addProperty() uses a special format for 
the properties keys: a path to an existing node (to which new data is to 
be added), followed by whitespace, followed by the name(s) of the new 
node(s) to be added. This is because we only can interpret XPath 
expressions on an existing nodes structure.

Now, in your test program when you try to add a new element, 
addProperty() is called behind the scenes, but cannot interpret the 
passed in key.

I agree that this is inconsistent, but unfortunately I don't know how to 
fix this. We might be able to work around the problem in some cases 
(e.g. if the property to be set has already some values, adding new 
elements can be performed directly on the nodes structure). But when 
setProperty() is used for adding a new property, I cannot see an easy 
solution.

Oliver

---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@commons.apache.org
For additional commands, e-mail: user-help@commons.apache.org