4

In a configuration file I have multiple array values, for example names for a phonebook.

<configuration>
    <phonebook>
        <name>John</name>
        <name>Mary</name>
    </phonebook>
</configuration>

I want to read these into this bean via BeanHelper (or another way):

public interface Phonebook {
    public void setName(String[] names);

    public String[] getName();
}

Or ideally with lists java.util.List<String> instead of arrays String[]. The implementation of the interface is simple:

public class MyPhonebook implements Phonebook {
    private String[] names;
    
    @Override
    public void setName(String[] names) {
        this.names = names;
    }

    @Override
    public String[] getName() {
        return names;
    }

    @Override
    public String toString() {
        return String.join("; ", names);
    }
}

The main looks like this:

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.ConfigurationRuntimeException;
import org.apache.commons.configuration.XMLConfiguration;
import org.apache.commons.configuration.beanutils.BeanHelper;
import org.apache.commons.configuration.beanutils.XMLBeanDeclaration;

public class Main {

    private static Phonebook myPhonebook;
    private static XMLConfiguration config;

    public static void main(String[] args) {
        // read the configuration
        String configFile = "config.xml";
        try {
            config = new XMLConfiguration();
//            config.setAttributeSplittingDisabled(true);
            config.setFileName(configFile);
            config.load();
        } catch (ConfigurationException e) {
            e.printStackTrace();
        }

        // this is to see which keys and values are inside the configuration
        config.getKeys().forEachRemaining(
                s -> System.out.println(s + " : " + config.getProperty(s)));

        // try to create the bean
        try {
            XMLBeanDeclaration declaration = new XMLBeanDeclaration(config,
                    "phonebook");

            declaration.getBeanProperties().forEach(
                    (k, v) -> System.out.println(k + " : " + v));

            myPhonebook = (Phonebook) BeanHelper.createBean(declaration,
                    MyPhonebook.class);
        } catch (ConfigurationRuntimeException e) {
            e.printStackTrace();
        }

        // print out the bean
        System.out.println(myPhonebook);
    }
}

This does not work when trying to create the bean, I get a ConfigurationRuntimeException caused by this UnsupportedOperationException:

java.lang.UnsupportedOperationException: Unable to handle collection of type : [Ljava.lang.String; for property name
    at org.apache.commons.configuration.beanutils.BeanHelper.createPropertyCollection(BeanHelper.java:335)
    at org.apache.commons.configuration.beanutils.BeanHelper.initBean(BeanHelper.java:213)
    at org.apache.commons.configuration.beanutils.DefaultBeanFactory.initBeanInstance(DefaultBeanFactory.java:108)
    at org.apache.commons.configuration.beanutils.DefaultBeanFactory.createBean(DefaultBeanFactory.java:64)
    at org.apache.commons.configuration.beanutils.BeanHelper.createBean(BeanHelper.java:390)
    ... 2 more

The first thing I had to change was the layout of the XML file to match the documentations of the XMLBeanDeclaration and the XMLConfiguration:

<configuration>
    <phonebook name="John,Mary" />
</configuration>

If I run the program then, it terminates normally and my output is:

phonebook[@name] : [John, Mary]
name : Mary
Mary

That means that the XMLConfiguration correctly identifies the configuration file having an array in the attribute name, but somehow the XMLBeanDeclaration does not. It always just takes the last value.

I came up with a solution which works, more or less, by abusing the fact that it is possible to read in arrays as single Strings. I added the line config.setAttributeSplittingDisabled(true);. The result is the following:

phonebook[@name] : John,Mary
name : John,Mary
John; Mary

In this case it seems that on creation of the bean the BeanHelper realizes the array and is able to choose the correct method.

Since this makes my configuration a little bit unflexible, I wonder if it is possible to get the XMLBeanDeclaration to handle arrays at an earlier stage to avoid the call to config.setAttributeSplittingDisabled(true);?

I am using Java 8, Configuration 1.10 and BeanUtils 1.9.2.

Community
  • 1
  • 1
Sebastian Höffner
  • 1,864
  • 2
  • 26
  • 37

0 Answers0