Home | JSP | EJB | JDBC | Java Servlets | WAP  | Free JSP Hosting  | Spring Framework | Web Services | BioInformatics | Java Server Faces | Jboss 3.0 tutorial | Hibernate 3.0 | XML
 
 
Hot Web Programming Job

 

Tutorial Categories: Ajax | Articles | JSP | Bioinformatics | Database | Free Books | Hibernate | J2EE | J2ME | Java | JavaScript | JDBC | JMS | Linux | MS Technology | PHP | RMI | Web-Services | Servlets | Struts | UML


 

Search Host

Monthly Fee($)
Disk Space (MB)
Register With us for Newsletter!
Visit Forum! Post Questions!
Jobs At RoseIndia.net!

Have tutorials?
Add your tutorial to our Java Resource and get tons of hits.

We offer free hosting for your tutorials. and exposure for thousands of readers. drop a mail
roseindia_net@yahoo.com
 
   

Tutorials

Java Server Pages

JAXB

Java Beans

JDBC

MySQL

Java Servlets

Struts

Bioinformatics

Java Code Examples

Interview Questions

 
Join For Newsletter

Powered by groups.yahoo.com
Visit Group! Post Questions!

Web Promotion

Web Submission

Submit Sites

Manual Submission?

Web Promotion Guide

Hosting Companies

Web Hosting Guide

Web Hosting

Linux

Beginner Guide to Linux Server

Frameworks

Persistence Framework

Web Frameworks

Free EAI Tools

Web Servers

Aspect Oriented Programming

Free Proxy Servers

Softwares

Adware & Spyware Remover

Open Source Softwares

Enum Inversion Problem

       

This Article Discusses about Enum Inversion Problem.

2005-08-29 The Java Specialists' Newsletter [Issue 113] - Enum Inversion Problem

Author: Dr. Heinz M. Kabutz

JDK version: Sun JDK 5.0

If you are reading this, and have not subscribed, please consider doing it now by going to our subscribe page. You can subscribe either via email or RSS.


Welcome to the 113th edition of The Java(tm) Specialists' Newsletter. First off, I would like to send a special welcome to Uzbekistan, bringing the total number of countries on our list to 111. In Europe we still need subscribers in Albania, so if you know of Java programmers there, please forward them our newsletter and ask them to subscribe :)

I would like to thank Dr Wolfgang Laun from Alcatel Austria for the question that led to this newsletter. We had an inspiring exchange of emails that has culminated in this newsletter. According to Dr Laun's colleagues, he is the resident guru at Alcatel Austria, so I was honoured to join him on this quest for an answer to this problem.

One of the benefits of you coming to one of our courses is that you get free life-time email support from The Java Specialists for Java related questions. Most of our courses are run in-house at companies, so please let us know if your company is desperate to spend a little bit of their training budget :)

Enum Inversion Problem

A problem that I encountered when I first started using enums was how to serialize them to some persistent store. My initial approach was to write the ordinal to the database. (The ordinal is an integer representing the order of the enum value, starting at zero.) Then I started receiving phone calls from clients, asking what value 3 meant in the Status column of the Postboxsendlog table. Since I was using the automatic values of the ordinal, I did not know the answer immediately.

Another problem is that when you change the order of the enum values or add an enum in the middle, you also modify the ordinal value. Instead of using the ordinal int, you could use the toString() value, and then convert the String back to the enum using Enum.valueOf(). Whilst this would be less brittle than using the ordinal, it will break if we rename the enum values.

A solution to the problem is to have a reverse lookup from some value to an enum. Ideally we would like this to be type safe using the new generics construct. We are limited with the Java 5 enums, since we cannot subclass them.

The initial idea was to embed a reverse lookup table inside each enum, but I rejected that because it did not result in a clean design and would cause the copy-and-paste anti-pattern.

We could map the enum to any value that we wanted to, but in this example, I am using a byte. If you had some weird application where you needed more than 256 different enum values, you could use either a short or an int.

This interface defines the convert method that will be implemented by each of the enums and should return a byte that would be used to represent this enum.

public interface EnumConverter {
  public byte convert();
}
  

Here are two example enums, Animal and Tree:

public enum Animal implements EnumConverter {
  Ape(100), Bee(50), Cat(80);

  private final byte value;

  Animal(int value) {
    this.value = (byte) value;
  }

  public byte convert() {
    return value;
  }
}

public enum Tree implements EnumConverter {
  Acorn(30), Birch(60), Cedar(40);

  private final byte value;

  Tree(int value) {
    this.value = (byte) value;
  }

  public byte convert() {
    return value;
  }
}
  

In order to lookup the enum based on a byte value, we define the ReverseEnumMap, for which you have to pass in a class object that is an enum and implements EnumConverter. This allows us to get all the enum values from the class, and to then call the convert() method on them. Note the special syntax that allows us to specify that a generic must implement several interfaces is done with the &, such as <V extends Enum<V> & EnumConverter>.

import java.util.*;

public class ReverseEnumMap<V extends Enum<V> & EnumConverter> {
  private Map<Byte, V> map = new HashMap<Byte, V>();
  public ReverseEnumMap(Class<V> valueType) {
    for (V v : valueType.getEnumConstants()) {
      map.put(v.convert(), v);
    }
  }

  public V get(byte num) {
    return map.get(num);
  }
}

You could also hold the reverse map inside an array of size 256. Even though you cannot directly construct an instance of an array of generics, you can do so using reflection. We have the enum type class available in the constructor of the ReverseEnumMap, so it is a matter of simply calling Array.newInstance(valueType, 256);

We can now use the ReverseEnumMap to lookup the enum matching a byte value. For example, it could be used in the Communication class as follows:

import java.io.*;

public class Communication<E extends Enum<E> & EnumConverter> {
  private final ReverseEnumMap<E> reverse;

  public Communication(Class<E> ec) {
    reverse = new ReverseEnumMap<E>(ec);
  }

  public void sendOne(OutputStream out, E e) throws IOException {
    out.write(e.convert());
  }

  public E receiveOne(InputStream in) throws IOException {
    int b = in.read();
    if (b == -1) throw new EOFException();
    return reverse.get((byte) b);
  }
}
  

We can use this by creating a ByteArrayOutputStream, then write an Animal Enum to that, and read it back again:

import java.io.*;

public class CommunicationTest {
  public static void main(String[] args) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    Communication<Animal> acom = new Communication<Animal>(Animal.class);
    acom.sendOne(baos, Animal.Ape);
    baos.close();
    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
    Animal animal = acom.receiveOne(bais);
    System.out.println(animal);
  }
}
  

This is one approach that we can use to read back enums from some byte value.

Alternative Approach

Enums in Java have a disadvantage, in that you cannot have a common superclass for your own enums. They are all automatically derived from the java.lang.Enum class, which you cannot modify.

Dr Laun was not happy that we were moving the complexity of constructing the ReverseEnumMap inside our client code (in this case the Communication class). I was not happy with putting it into each enum because that would result in unnecessary copy & paste code. However, Dr Laun has convinced me that the fault lies with the enum and therefore any copy & paste code belongs inside them and not in the client code.

There is a slight catch. You cannot declare static methods inside interfaces. Ideally we would declare that EnumConverter has a static method that we need to implement and which could then contain the functionality for converting from a byte to the enum value. My idea was to simply declare it as a non-static method, and let the client call the method on any instance of the enum.

First, we define an additional method inside EnumConverter:

public interface EnumConverter <E extends Enum<E> & EnumConverter<E>> {
  byte convert();
  E convert(byte val);
}
  

We also move the ReverseEnumMap into the Animal definition:

public enum Animal implements EnumConverter<Animal> {
  Ape(100), Bee(50), Cat(80);

  private static ReverseEnumMap<Animal> map =
      new ReverseEnumMap<Animal>(Animal.class);

  private final byte value;

  Animal(int value) {
    this.value = (byte) value;
  }

  public byte convert() {
    return value;
  }

  public Animal convert(byte val) {
    return map.get(val);
  }
}
  

We now construct the Communication instance with a sample enum of the type that we want to convert, such as: Communication<Animal> acom = new Communication<Animal>(Animal.Ape). The Communication class would need to change slightly as well:

import java.io.*;

public class Communication<E extends Enum<E> & EnumConverter<E>> {
  private final E enumSample;
  public Communication(E enumSample) {
    this.enumSample = enumSample;
  }

  public void sendOne(OutputStream out, E e) throws IOException {
    out.write(e.convert());
  }

  public E receiveOne(InputStream in) throws IOException {
    int b = in.read();
    if (b == -1) throw new EOFException();
    return enumSample.convert((byte) b);
  }
}
  

Neither approach satisfies me completely, but both will work.

Kind regards

Heinz

This material from The Java(tm) Specialists' Newsletter by Maximum Solutions (South Africa). Please contact Maximum Solutions for more information.

       

Useful Links
  JDO Tutorials
  EAI Articles
  Struts Tutorials
  Java Tutorials
  Java Certification

Tell A Friend
Your Friend Name
Search Tutorials

 

 
 
Browse all Java Tutorials
Java JSP Struts Servlets Hibernate XML
Ajax JDBC EJB MySQL JavaScript JSF
Maven2 Tutorial JEE5 Tutorial Java Threading Tutorial Photoshop Tutorials Linux Technology
Technology Revolutions Eclipse Spring Tutorial Bioinformatics Tutorials Tools SQL
 

Home | JSP | EJB | JDBC | Java Servlets | WAP  | Free JSP Hosting  | Search Engine | News Archive | Jboss 3.0 tutorial | Free Linux CD's | Forum | Blogs

About Us | Advertising On RoseIndia.net

Send your comments, Suggestions or Queries regarding this site at roseindia_net@yahoo.com.

Copyright © 2007. All rights reserved.