Details

    • Type: Improvement
    • Status: Open
    • Priority: Minor
    • Resolution: Unresolved
    • Affects Version/s: 1.1
    • Fix Version/s: 2.x
    • Component/s: None
    • Labels:
      None
    • Bugzilla Id:
      35804

      Description

      It would be nice if org.apache.commons.configuration.Configuration extended java.io.Serializable and its implementations were serializable as well. Theoretically, most configurations are constructed from "serialized" data sources.

        Issue Links

          Activity

          Hide
          ebourg Emmanuel Bourg added a comment -
              • COM-2230 has been marked as a duplicate of this bug. ***
          Show
          ebourg Emmanuel Bourg added a comment - COM-2230 has been marked as a duplicate of this bug. ***
          Hide
          ebourg Emmanuel Bourg added a comment -

          That would make sense since java.util.Properties and ExtendedProperties are
          Serializable. We may want to implement Clonable as well.

          Show
          ebourg Emmanuel Bourg added a comment - That would make sense since java.util.Properties and ExtendedProperties are Serializable. We may want to implement Clonable as well.
          Hide
          ebourg Emmanuel Bourg added a comment -

          Actually it may not be wise to mark Configuration as Serializable, the
          configurations bound to an external resource like JNDIConfiguration,
          DatabaseConfiguration and the web configurations cannot be serialized. The
          FileConfiguration interface is a better candidate for extending Serializable.

          Show
          ebourg Emmanuel Bourg added a comment - Actually it may not be wise to mark Configuration as Serializable, the configurations bound to an external resource like JNDIConfiguration, DatabaseConfiguration and the web configurations cannot be serialized. The FileConfiguration interface is a better candidate for extending Serializable.
          Hide
          ebourg Emmanuel Bourg added a comment - - edited

          This is not as trivial as I thought initially... I made FileConfiguration
          extends Serializable and wrote a test case serializing a PropertiesConfiguration
          to a file. This led me to the following changes:

          • make ReloadingStrategy extend Serializable as well
          • change the type of the reloadLock in AbtractFileConfiguration to something
            else than Object that is serializable. I picked String. I tried to make it
            transient, but it resulted in a NullPointerException when accessing the
            deserialized configuration because it was not initialized. I tried to move the
            initialization in the no arg constructor but it didn't work, I'm not sure to
            understand why this constructor isn't called when the deserialized instance is
            build.

          It still failed after these changes, because the deserialized configuration was
          actually empty. It appears that the Map in BaseConfiguration is not serialized.
          I put a similar Map in AbstractFileConfiguration and it got serialized property,
          but by simply moving this Map to BaseConfiguration it disappeared from the
          serialized file, I have no idea why.

          I tested with the JDK 1.4.2_08.

          Here is the test added to TestPropertiesConfiguration:

              public void testSerialization() throws Exception {
                  // remove the previous serialization file
                  File file = new File("target/configuration.ser");
                  if (file.exists()) {
                      file.delete();
                  }
          
                  // write the configuration to the configuration.ser file
                  ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
                  out.writeObject(conf);
                  out.close();
          
                  // load the configuration from the file
                  ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
                  PropertiesConfiguration conf2 = (PropertiesConfiguration) in.readObject();
                  in.close();
          
                  // check the deserialized configuration
                  assertNotNull("deserialized configuration null", conf2);
                  assertEquals("filename", conf.getFileName(), conf2.getFileName());
                  assertEquals("basepath", conf.getBasePath(), conf2.getBasePath());
                  assertEquals("header", conf.getHeader(), conf2.getHeader());
          
                  assertFalse("deserialized configuration empty", conf2.isEmpty());
                  Iterator keys = conf.getKeys();
                  while (keys.hasNext())
                  {
                      String key = (String) keys.next();
                      assertTrue("missing key from the deserialized configuration : " +
          key, conf2.containsKey(key));
                      assertEquals("wrong value in the deserialized configuration for the
          key " + key, conf.getProperty(key), conf2.getProperty(key));
                  }
              }
          
          Show
          ebourg Emmanuel Bourg added a comment - - edited This is not as trivial as I thought initially... I made FileConfiguration extends Serializable and wrote a test case serializing a PropertiesConfiguration to a file. This led me to the following changes: make ReloadingStrategy extend Serializable as well change the type of the reloadLock in AbtractFileConfiguration to something else than Object that is serializable. I picked String. I tried to make it transient, but it resulted in a NullPointerException when accessing the deserialized configuration because it was not initialized. I tried to move the initialization in the no arg constructor but it didn't work, I'm not sure to understand why this constructor isn't called when the deserialized instance is build. It still failed after these changes, because the deserialized configuration was actually empty. It appears that the Map in BaseConfiguration is not serialized. I put a similar Map in AbstractFileConfiguration and it got serialized property, but by simply moving this Map to BaseConfiguration it disappeared from the serialized file, I have no idea why. I tested with the JDK 1.4.2_08. Here is the test added to TestPropertiesConfiguration: public void testSerialization() throws Exception { // remove the previous serialization file File file = new File( "target/configuration.ser" ); if (file.exists()) { file.delete(); } // write the configuration to the configuration.ser file ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream(file)); out.writeObject(conf); out.close(); // load the configuration from the file ObjectInputStream in = new ObjectInputStream( new FileInputStream(file)); PropertiesConfiguration conf2 = (PropertiesConfiguration) in.readObject(); in.close(); // check the deserialized configuration assertNotNull( "deserialized configuration null " , conf2); assertEquals( "filename" , conf.getFileName(), conf2.getFileName()); assertEquals( "basepath" , conf.getBasePath(), conf2.getBasePath()); assertEquals( "header" , conf.getHeader(), conf2.getHeader()); assertFalse( "deserialized configuration empty" , conf2.isEmpty()); Iterator keys = conf.getKeys(); while (keys.hasNext()) { String key = ( String ) keys.next(); assertTrue( "missing key from the deserialized configuration : " + key, conf2.containsKey(key)); assertEquals("wrong value in the deserialized configuration for the key " + key, conf.getProperty(key), conf2.getProperty(key)); } }
          Hide
          ebourg Emmanuel Bourg added a comment -

          Marking BaseConfiguration as Serializable fixes that, a patch is on the way!

          Show
          ebourg Emmanuel Bourg added a comment - Marking BaseConfiguration as Serializable fixes that, a patch is on the way!
          Hide
          oliver.heger@t-online.de Oliver Heger added a comment -

          I fully agree that serializable configurations are a useful feature.

          However an implementation may be complicated and tricky, especially because a
          configuration may hold references to some other objects: a reloading strategy
          has already been mentioned, an XML document (XMLConfiguration), later maybe
          event listeners, helper objects for interpolation, or strategies for locating
          the source files. Forcing all of these objects to be serializable is a too
          strong restriction IMO. And declaring all these fields as transient may cause
          other problems.

          As an alternative approach: What if not the configuration objects as a whole are
          serialized, but only the important portions (containing the properties)? There
          could be an interface like that:

          public interface SerializableConfiguration
          {
          /** Returns serializable data of this configuration.*/
          Serializable getSerializable();

          /** Initializes this configuration from serialized data.*/
          void initFromSerializable(Serializable data) throws ConfigurationException;
          }

          This is a bit less convenient to use, but will probably save us a lot of trouble.

          Show
          oliver.heger@t-online.de Oliver Heger added a comment - I fully agree that serializable configurations are a useful feature. However an implementation may be complicated and tricky, especially because a configuration may hold references to some other objects: a reloading strategy has already been mentioned, an XML document (XMLConfiguration), later maybe event listeners, helper objects for interpolation, or strategies for locating the source files. Forcing all of these objects to be serializable is a too strong restriction IMO. And declaring all these fields as transient may cause other problems. As an alternative approach: What if not the configuration objects as a whole are serialized, but only the important portions (containing the properties)? There could be an interface like that: public interface SerializableConfiguration { /** Returns serializable data of this configuration.*/ Serializable getSerializable(); /** Initializes this configuration from serialized data.*/ void initFromSerializable(Serializable data) throws ConfigurationException; } This is a bit less convenient to use, but will probably save us a lot of trouble.
          Hide
          ebourg Emmanuel Bourg added a comment -

          Or simply use ConfigurationUtils to convert the configuration into a Properties
          which is Serializable, or load/save the configuration on a stream.

          However I'm not sure this solution will suit the needs. I can think of two use
          cases that would require serializable configurations:
          1. access to a configuration through RMI
          2. restoring a configuration put in a HttpSession when the web container is
          restarted

          In these cases the state of the configuration also matters, we cannot just save
          the properties.

          Another issue worth noting, the delimiter declared in AbstractConfiguration is
          currently static, and consequently not serialized. We will have to change it
          into an instance variable, this has been already discussed but implementing the
          serialization is an additional motivation.

          Show
          ebourg Emmanuel Bourg added a comment - Or simply use ConfigurationUtils to convert the configuration into a Properties which is Serializable, or load/save the configuration on a stream. However I'm not sure this solution will suit the needs. I can think of two use cases that would require serializable configurations: 1. access to a configuration through RMI 2. restoring a configuration put in a HttpSession when the web container is restarted In these cases the state of the configuration also matters, we cannot just save the properties. Another issue worth noting, the delimiter declared in AbstractConfiguration is currently static, and consequently not serialized. We will have to change it into an instance variable, this has been already discussed but implementing the serialization is an additional motivation.
          Hide
          joehni Joerg Schaible added a comment -

          You may consider implementing the writeReplace method. This allows you to serialize every Configuration into a tailored version especially designed for serialization. You may even have different impls e.g. a different one for hierarchical configs. However, some features like reloading do not make really sense for some sources ... what is a file URL really worth after serialization?

          Show
          joehni Joerg Schaible added a comment - You may consider implementing the writeReplace method. This allows you to serialize every Configuration into a tailored version especially designed for serialization. You may even have different impls e.g. a different one for hierarchical configs. However, some features like reloading do not make really sense for some sources ... what is a file URL really worth after serialization?
          Hide
          ralph.goers@dslextreme.com Ralph Goers added a comment -

          I'm trying to understand the use case for this. Under what circumstances would this be useful? Why wouldn't "serialization" simply mean calling save?

          Show
          ralph.goers@dslextreme.com Ralph Goers added a comment - I'm trying to understand the use case for this. Under what circumstances would this be useful? Why wouldn't "serialization" simply mean calling save?
          Hide
          joehni Joerg Schaible added a comment -

          No, it means also passing it as argument in a EJB call or saving it in a session.

          Show
          joehni Joerg Schaible added a comment - No, it means also passing it as argument in a EJB call or saving it in a session.
          Hide
          jcbollinger John Bollinger added a comment -

          I would recommend that org.apache.commons.configuration.Configuration not be modified to extend Serializable, because that imposes a requirement on all implementations to be serializable. I think that's far too strong. Moreover, it is not necessary for enabling clients to be serializable: an otherwise serializable object that refers to a org.apache.commons.configuration.Configuration (by that formal type) is serializable if the Configuration implementation is Serializable, regardless of whether the Configuration interface extends java.io.Serializable.

          With that said, it is highly desirable to make the provided concrete Configuration implementations serializable wherever possible. That will enable them to be passed over RMI (including to remote EJBs) and to be held by passivated objects (sessions, EJB instances, etc.), among other uses. On the other hand, implementations tied to live sources (JNDI, database) are unlikely candidates for being serializable.

          This is a big endeavor, even in the more limited form I'm suggesting. Perhaps it would be useful to split it up.

          Show
          jcbollinger John Bollinger added a comment - I would recommend that org.apache.commons.configuration.Configuration not be modified to extend Serializable, because that imposes a requirement on all implementations to be serializable. I think that's far too strong. Moreover, it is not necessary for enabling clients to be serializable: an otherwise serializable object that refers to a org.apache.commons.configuration.Configuration (by that formal type) is serializable if the Configuration implementation is Serializable, regardless of whether the Configuration interface extends java.io.Serializable. With that said, it is highly desirable to make the provided concrete Configuration implementations serializable wherever possible. That will enable them to be passed over RMI (including to remote EJBs) and to be held by passivated objects (sessions, EJB instances, etc.), among other uses. On the other hand, implementations tied to live sources (JNDI, database) are unlikely candidates for being serializable. This is a big endeavor, even in the more limited form I'm suggesting. Perhaps it would be useful to split it up.
          Hide
          jcbollinger John Bollinger added a comment -

          Also, I'd guess that implementing this task properly probably requires some refactoring that would make it more suitable for release 2.0 than for release 1.x. For example, BaseConfiguration probably should be serializable, but some of its subclasses (i.e. AbstractFileConfiguration and its descendents) probably shouldn't.

          Show
          jcbollinger John Bollinger added a comment - Also, I'd guess that implementing this task properly probably requires some refactoring that would make it more suitable for release 2.0 than for release 1.x. For example, BaseConfiguration probably should be serializable, but some of its subclasses (i.e. AbstractFileConfiguration and its descendents) probably shouldn't.
          Hide
          oliver.heger@t-online.de Oliver Heger added a comment -

          John, I agree with most of your points.

          However, I wonder whether we really can make a concrete Configuration implementation serializable. The problem is that each important implementation is associated with a bunch of helper objects like interpolators, lookups, expression strategies, etc. Many of these objects would have to be made serializable, too, and its questionable whether this is feasible or even desired.

          Maybe we need a different approach. One way could be to have a method like Serializable getContent() in the Configuration interface. This method would return a serializable object storing the pure data of the configuration. In addition, concrete Configuration implementations could define a constructor that takes a Serializable object and initializes the configuration with this data.

          Based on this mechanism we could define a "canonical configuration serialization format", probably XML-based as XML is capable of storing all the hierarchical structure. This would allow for easy data conversion, e.g. the data from a PropertiesConfiguration is fetched and then an XMLConfiguration is constructed with it.

          Of course, this is not as convenient as serializing Configuration objects directly. But maybe it's the closest thing we can get?

          Show
          oliver.heger@t-online.de Oliver Heger added a comment - John, I agree with most of your points. However, I wonder whether we really can make a concrete Configuration implementation serializable. The problem is that each important implementation is associated with a bunch of helper objects like interpolators, lookups, expression strategies, etc. Many of these objects would have to be made serializable, too, and its questionable whether this is feasible or even desired. Maybe we need a different approach. One way could be to have a method like Serializable getContent() in the Configuration interface. This method would return a serializable object storing the pure data of the configuration. In addition, concrete Configuration implementations could define a constructor that takes a Serializable object and initializes the configuration with this data. Based on this mechanism we could define a "canonical configuration serialization format", probably XML-based as XML is capable of storing all the hierarchical structure. This would allow for easy data conversion, e.g. the data from a PropertiesConfiguration is fetched and then an XMLConfiguration is constructed with it. Of course, this is not as convenient as serializing Configuration objects directly. But maybe it's the closest thing we can get?
          Hide
          ralph.goers@dslextreme.com Ralph Goers added a comment - - edited

          Frankly, I don't really understand how having a Configuration being Serializable is particularly useful and the complexity involved in this seems to be way out of proportion with the benefit.

          In the case of a CompositeConfiguration that would mean serializing all the configurations that participate and then including them in the serialized composite. What is the benefit vs creating a new Composite using the configurations that make it up. In the case of DefaultConfigurationBuilder, which is an "extended" XMLConfiguration, the serialized form of this would be extremely complex. Some of this could be mitigated by having the serialized form embed the initial configuration file used by DefaultConfigurationBuilder and marking the fields transient, but if you do that why not just go the whole route and have it build a new CombinedConfiguration?

          And what would be the point of storing an XML serialized format of the Configuration when the configuration data itself is an XML document? That is just seems silly.

          Also, at the very least it seems highly unlikely this will be accomplished in 1.x. So if this isn't closed as wontfix then I would suggest the version be changed to 2.0.

          Show
          ralph.goers@dslextreme.com Ralph Goers added a comment - - edited Frankly, I don't really understand how having a Configuration being Serializable is particularly useful and the complexity involved in this seems to be way out of proportion with the benefit. In the case of a CompositeConfiguration that would mean serializing all the configurations that participate and then including them in the serialized composite. What is the benefit vs creating a new Composite using the configurations that make it up. In the case of DefaultConfigurationBuilder, which is an "extended" XMLConfiguration, the serialized form of this would be extremely complex. Some of this could be mitigated by having the serialized form embed the initial configuration file used by DefaultConfigurationBuilder and marking the fields transient, but if you do that why not just go the whole route and have it build a new CombinedConfiguration? And what would be the point of storing an XML serialized format of the Configuration when the configuration data itself is an XML document? That is just seems silly. Also, at the very least it seems highly unlikely this will be accomplished in 1.x. So if this isn't closed as wontfix then I would suggest the version be changed to 2.0.
          Hide
          oliver.heger@t-online.de Oliver Heger added a comment -

          Serializing a Configuration only to make it persistent certainly does not make much sense. But the other use cases listed in this ticket seem valid to me.

          Consider a web application that creates a Configuration with settings for a user on log in. This Configuration should be stored in the Session, so it should be serializable. It may also be used as a parameter of a call to a remote EJB, which also requires it to be serializable.

          But as I said, I don't believe that we can make concrete Configuration implementations themselves serializable, only the pure data they contain. In the case of combined configurations that would mean creating a serializable data object containing the data of all child configurations involved.

          Anyway, I agree that this issue will probably not be addressed in the 1.x series. So I am going to change the fix version.

          Show
          oliver.heger@t-online.de Oliver Heger added a comment - Serializing a Configuration only to make it persistent certainly does not make much sense. But the other use cases listed in this ticket seem valid to me. Consider a web application that creates a Configuration with settings for a user on log in. This Configuration should be stored in the Session, so it should be serializable. It may also be used as a parameter of a call to a remote EJB, which also requires it to be serializable. But as I said, I don't believe that we can make concrete Configuration implementations themselves serializable, only the pure data they contain. In the case of combined configurations that would mean creating a serializable data object containing the data of all child configurations involved. Anyway, I agree that this issue will probably not be addressed in the 1.x series. So I am going to change the fix version.
          Hide
          ralph.goers@dslextreme.com Ralph Goers added a comment -

          With regards to the situations you mentioned I would strongly argue that there are much better solutions than serializing the whole configuration. Especially in the case of the EJB, in a properly designed system the client side and the server side would usually have completely different configuration data so passing the full set of configuration would be a waste. Furthermore, passing the data would hardly be better than having the server side just read its configuration.

          If we assume that the configuration itself wouldn't be Serializable, as we both seem to agree, then storing something else in the session isn't of much value since you would have to keep reconstructing the Configuration to actually access the data. If you really wanted to do this it would make much more sense to just add save(OutputStream) to the base Configuration interface. Then the application could save any configuration to a byte array and load it back in again later. As for the end user data in the session, that really should be some sort of UserPreferences object, not a serialized configuration object. The UserPreferences object could certainly be backed by a Configuration, but once the object is built the Configuration would never be needed again in that session unless the user changes a setting.

          I have no problem setting this to 2.0. I am just stating my doubts that anything will ever happen with this issue.

          Show
          ralph.goers@dslextreme.com Ralph Goers added a comment - With regards to the situations you mentioned I would strongly argue that there are much better solutions than serializing the whole configuration. Especially in the case of the EJB, in a properly designed system the client side and the server side would usually have completely different configuration data so passing the full set of configuration would be a waste. Furthermore, passing the data would hardly be better than having the server side just read its configuration. If we assume that the configuration itself wouldn't be Serializable, as we both seem to agree, then storing something else in the session isn't of much value since you would have to keep reconstructing the Configuration to actually access the data. If you really wanted to do this it would make much more sense to just add save(OutputStream) to the base Configuration interface. Then the application could save any configuration to a byte array and load it back in again later. As for the end user data in the session, that really should be some sort of UserPreferences object, not a serialized configuration object. The UserPreferences object could certainly be backed by a Configuration, but once the object is built the Configuration would never be needed again in that session unless the user changes a setting. I have no problem setting this to 2.0. I am just stating my doubts that anything will ever happen with this issue.
          Hide
          jcbollinger John Bollinger added a comment -

          The argument that developers just shouldn't do that isn't very appealing to me, though it is an accurate description of one of the outcomes of the fact that Configurations aren't serializable. Moreover, it misses the point of why serializability is useful: the main use case is not the client passing configuration to the server to configure it (or vise versa); rather it is serialization of objects on either side that hold references to their own configuration so that they can be passed over RMI (including to remote EJBs) or written to external storage (e.g. to passivate the object). It doesn't matter how or whether the configuration is used after serialization / deserialization because you don't even get there successfully.

          With that said, I agree that many of the concrete Configuration implementations probably resist being made serializable. If enabling externalization of configuration objects were a priority then I would argue for a redesign of the API to separate the data structure(s) for configuration from the mechanisms for loading / reloading them. That would be a rather dramatic shift, however, and I suspect there isn't going to be much support for doing that.

          As for adding a save(OutputStream) method to Configuration, I don't think that is meaningfully different from making Configuration extend Serializable. If a configuration can implement save(OutputStream) then it can also implement the readObject() and writeObject() methods that would enable it to be serialized and deserialized by the standard mechanism.

          Show
          jcbollinger John Bollinger added a comment - The argument that developers just shouldn't do that isn't very appealing to me, though it is an accurate description of one of the outcomes of the fact that Configurations aren't serializable. Moreover, it misses the point of why serializability is useful: the main use case is not the client passing configuration to the server to configure it (or vise versa); rather it is serialization of objects on either side that hold references to their own configuration so that they can be passed over RMI (including to remote EJBs) or written to external storage (e.g. to passivate the object). It doesn't matter how or whether the configuration is used after serialization / deserialization because you don't even get there successfully. With that said, I agree that many of the concrete Configuration implementations probably resist being made serializable. If enabling externalization of configuration objects were a priority then I would argue for a redesign of the API to separate the data structure(s) for configuration from the mechanisms for loading / reloading them. That would be a rather dramatic shift, however, and I suspect there isn't going to be much support for doing that. As for adding a save(OutputStream) method to Configuration, I don't think that is meaningfully different from making Configuration extend Serializable. If a configuration can implement save(OutputStream) then it can also implement the readObject() and writeObject() methods that would enable it to be serialized and deserialized by the standard mechanism.
          Hide
          oliver.heger@t-online.de Oliver Heger added a comment -

          In times of CDI, wouldn't it be possible to write an extension which loads a configuration and injects it into interested beans based on annotation? Or even inject only specific configuration property values? This approach allows using configuration objects in a JEE environment without requiring that they have to be serializable. Maybe something for the DeltaSpike project?

          Show
          oliver.heger@t-online.de Oliver Heger added a comment - In times of CDI, wouldn't it be possible to write an extension which loads a configuration and injects it into interested beans based on annotation? Or even inject only specific configuration property values? This approach allows using configuration objects in a JEE environment without requiring that they have to be serializable. Maybe something for the DeltaSpike project?

            People

            • Assignee:
              Unassigned
              Reporter:
              thedew Joe Wolf
            • Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated:

                Development