views:

383

answers:

3

Got a class that serializes into xml with XMLEncoder nicely with all the variables there. Except for the one that holds java.util.Locale. What could be the trick? TIA.

A: 

Sorry, don't you mean java.util.Locale? The javadocs say that java.util.Locale implements Serializable, so you should have no problem using the Locale class from the lang package.

Miguel Ping
Yeah, it's in java.util. Unfortunately, the thing doesn't serialize.
alex
The question is to do with using java.beans XMLEncoder, not java.io. binary serialisation.
Tom Hawtin - tackline
+7  A: 

The problem is that java.util.Locale is not a bean. From the XMLEncoder doc:

The XMLEncoder class is a complementary alternative to the ObjectOutputStream and can used to generate a textual representation of a JavaBean in the same way that the ObjectOutputStream can be used to create binary representation of Serializable objects.

However, the API allows you to use PersistenceDelegates to serialize non-bean types:

Sample bean:

public class MyBean implements Serializable {

    private static final long serialVersionUID = 1L;

    private Locale locale;
    private String foo;

    public MyBean() {
    }

    public Locale getLocale() {
     return locale;
    }

    public void setLocale(Locale locale) {
     this.locale = locale;
    }

    public String getFoo() {
     return foo;
    }

    public void setFoo(String foo) {
     this.foo = foo;
    }

}

Serializing a data graph that includes a Locale type:

public class MyBeanTest {

    public static void main(String[] args) throws Exception {
     // quick and dirty test

     MyBean c = new MyBean();
     c.setLocale(Locale.CHINA);
     c.setFoo("foo");

     ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
     XMLEncoder encoder = new XMLEncoder(outputStream);
     encoder.setPersistenceDelegate(Locale.class, new PersistenceDelegate() {
      protected Expression instantiate(Object oldInstance, Encoder out) {
       Locale l = (Locale) oldInstance;
       return new Expression(oldInstance, oldInstance.getClass(),
         "new", new Object[] { l.getLanguage(), l.getCountry(),
           l.getVariant() });
      }
     });
     encoder.writeObject(c);
     encoder.flush();
     encoder.close();

     System.out.println(outputStream.toString("UTF-8"));

     ByteArrayInputStream bain = new ByteArrayInputStream(outputStream
       .toByteArray());
     XMLDecoder decoder = new XMLDecoder(bain);

     c = (MyBean) decoder.readObject();

     System.out.println("===================");
     System.out.println(c.getLocale());
     System.out.println(c.getFoo());
    }

}

This is the section of code that describes how the object should be instantiated on deserialization - it sets the constructor arguments to three string values:

 new PersistenceDelegate() {
  protected Expression instantiate(Object oldInstance, Encoder out) {
   Locale l = (Locale) oldInstance;
   return new Expression(oldInstance, oldInstance.getClass(),
     "new", new Object[] { l.getLanguage(), l.getCountry(),
       l.getVariant() });
  }
 }

Read Using XMLEncoder by Philip Milne for more info.

All this aside, it might be smarter to store the locale information in textual form and use it to look up the appropriate Locale object whenever it is needed. That way you don't need special case code when serializing your object and make it more portable.

McDowell
An excellent explanation and thanks for the link. BTW, you don't need to do encoder.flush() before encoder.close() as closing implicitly flushed encoder.
alex
A: 

This is a nice article in which its tell you how implement setPersistenceDelegate.

There is no link in your answer!?
Aaron Digulla