The Source for Java Technology Collaboration
User: Password:



Sergey Malenkov

Sergey Malenkov's Blog

How to encode Enums?

Posted by malenkov on August 07, 2006 at 06:00 PM | Comments (5)

As you may know, Enums were introduced in Tiger, but they are not supported by XMLEncoder.
This article describes how to encode them into XML properly.

Let's create a simple Enum with static method to test encoding into XML:

import java.beans.XMLEncoder;
import java.io.ByteArrayOutputStream;

public enum TestEnum {
    LEFT, RIGHT;

    public static void main( String[] args ) {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();

        XMLEncoder encoder = new XMLEncoder( stream );
        encoder.writeObject( TestEnum.LEFT );
        encoder.writeObject( TestEnum.RIGHT );
        encoder.close();

        System.out.println( stream );
    }
}

If the test method is executed it will print the following result:

java.lang.InstantiationException: TestEnum
Continuing ...
java.lang.Exception: XMLEncoder: discarding statement XMLEncoder.writeObject(TestEnum);
Continuing ...
java.lang.InstantiationException: TestEnum
Continuing ...
java.lang.Exception: XMLEncoder: discarding statement XMLEncoder.writeObject(TestEnum);
Continuing ...
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.5.0_07" class="java.beans.XMLDecoder">
</java>

As you can see, some exceptions were thrown during encoding and XML does not contain any object.

Let's change the test program. We should create persistence delegate and register it before encoding:

import java.beans.Encoder;
import java.beans.Expression;
import java.beans.PersistenceDelegate;
import java.beans.XMLEncoder;
import java.io.ByteArrayOutputStream;

public enum TestEnum {
    LEFT, RIGHT;

    public static void main( String[] args ) {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();

        XMLEncoder encoder = new XMLEncoder( stream );
        encoder.setPersistenceDelegate( TestEnum.class, new EnumPersistenceDelegate() );
        encoder.writeObject( TestEnum.LEFT );
        encoder.writeObject( TestEnum.RIGHT );
        encoder.close();

        System.out.println( stream );
    }
}

class EnumPersistenceDelegate extends PersistenceDelegate {
    protected boolean mutatesTo( Object oldInstance, Object newInstance ) {
        return oldInstance == newInstance;
    }

    protected Expression instantiate( Object oldInstance, Encoder out ) {
        Enum e = ( Enum )oldInstance;
        return new Expression( e, e.getClass(), "valueOf", new Object[]{e.name()} );
    }
}

Note that EnumPersistenceDelegate does not depend on concrete Enum.
So, it is possible to use one instance of such persistence delegate with any Enum,
but it is necessary to register it with concrete class of required Enum.

As a result, XML contains both encoded objects:

<?xml version="1.0" encoding="UTF-8"?>
<java version="1.5.0_07" class="java.beans.XMLDecoder">
 <object class="TestEnum" method="valueOf">
  <string>LEFT</string>
 </object>
 <object class="TestEnum" method="valueOf">
  <string>RIGHT</string>
 </object>
</java>

I have good news for you: JDK 6 already supports Enum encoding.
So, you should not create persistence delegate and register it for your Enum anymore.


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • Yay! I love JavaBeans Long-term Persistence. It is one of the under-valued gems of the JDK. I'm so glad to find that someone at Sun is still keeping an eye on it.
    Hope you won't mind a few suggestions for further enhancements: (and yes, I have filed requests for enhancement on some of these)
    Have you considered adding support to it for other XML sources. That is, instead of having it read an InputStream, how about being driven as a SAX ContentHandler? This would make it easy to do things like transform some other XML schema into Long-Term persistence on the fly. (Or, support for stylesheets could be built in.)
    Also, what about using a namespace for the schema? And creating an XML Schema for it?

    Posted by: erickson on August 08, 2006 at 11:27 AM

  • Hi Erickson,

    Thank you for your suggestion. I am working on RFE 4864117 now. You can vote for it.

    I'll think about ContentHandler, but I'm not sure about stylesheets. It is possible to download DTD from here, but XML Schema is not accessible. Could you explain why do you need schema and namespaces?

    Sergey

    Posted by: malenkov on August 09, 2006 at 03:23 AM

  • Having a schema would give better hints to XML editors about what is valid, and they, in turn, could prompt users for what's needed as they edit the files. (Yeah, I do this by hand a lot).

    Using namespaces has been best practice for quite a while... not having one is akin to not putting your Java class into a package. I think XML namespaces were developed around the same time as the XML codec, so it just missed this wave. This is not too important, and it might be hard to do while retaining backward compatibility, but it would make the format look a bit more respectable in some folk's eyes.

    Posted by: erickson on August 09, 2006 at 10:57 AM

  • Hmmm... I think it is impossible. Let's see:

    <void method="setName">
    <string>NAME</string>
    </void>

    The code above is valid, but the code below is invalid,
    because method getName does not have parameters.

    <void method="getName">
    <string>NAME</string>
    </void>

    I can create only the simple schema that can not validate Java-related information.

    Posted by: malenkov on August 10, 2006 at 12:44 AM

  • erickson - checkout JAXB 2.0

    Posted by: phlogistic on August 10, 2006 at 04:18 PM



Only logged in users may post comments. Login Here.


Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds