0

Is "Dynamic enumerations" an oxymoron, like "static variables"? ;-)

I've only been soaking in Spring for a short time, and I suspect I'm not thinking Spring-like yet. I would like to have a type-safe, dynamic enumeration. I've used this pattern for things like events or error codes where you want to allow subsequent sub-classes to expand the enumeration. Since "enum" can't be extended you're left with an enumeration pattern class. For example (stripped down):

public class EventType {

    private String name;    

    private static HashMap<String, EventType> cache 
                     = new HashMap<String, EventType>();

    protected EventType(String name) {
        if (cache.containsKey(name)) {
            throw new RuntimeException("EventType '" + name + "' already exists!");
        } else {
             this.name = name;
             cache.put(name, this);
        }
    }

    public static AuditEventType parse(String name) {
        return cache.get(name);
    }

    public static final EventType EVENT_START = new AuditEventType("Start");
    public static final EventType EVENT_END   = new AuditEventType("End");
    public static final EventType EVENT_FAIL  = new AuditEventType("Fail");
}

The problems start when I add Spring to the mix. Since it's only a string, I've annotated EventType as "@Embeddable", and classes that use it annotate that member as "@Embedded". This seemed to work great until it came time for querying using queryDSL-jpa. DSL would try to convert the DB text to an EventType, which then would have a type mismatch with strings. That is, I couldn't say: WHERE EventType = "Start". I got around this (not elegantly) by having the class with such a field store it as a String, and parse it to an EventType object in the getter. So now it's just a plain ol' string as far as JPA is concerned.

Now I'm running into an issue with the service API. I have a method with an EventType parameter. The problem is that the JsonRpcServer class is trying to convert the String to an EventType by instantiating it. This of course throws an "already exists!" exception.

I can probably solve this second issue with @JsonTypeResolver (which I'm reading up on now). But all of these shenanigans feel wrong. This must be a common issue and there's got to be a better solution. What's the proper way of handling such classes in Spring? (where it's not a bean, really, and has a protected constructor).

(I'm leaving out some specifics about some proprietary libraries our code uses, and which might not let me adopt an answer like "Oh, you should be using 'X' instead." Thanks for understanding.)

Didjit
  • 785
  • 2
  • 8
  • 26

1 Answers1

1

For the Spring side take a look at the conversionService. This lets you register custom converters. So you should be able to register your EventTypeToStringConverter and StringToEventTypeConverter. They will have "full" control to resolve from/to your eventtype.

For the Hibernate side it might be a solution to use a specific UserType for your EventType so Hibernate is able to store and read it as a column value. (which is what i expect you need) I had a similar requirement with a status on each entity which i did not want to model as an entity itself. I did not manage to use a string parameter in a query directly yet but There are plenty of interfaces that you might implement most likely there is one that allows a string recognition for parameters.

Martin Frey
  • 10,025
  • 4
  • 25
  • 30
  • Thanks for the suggestions, Martin. The `conversionService` sounds promising. As for the UserType, yes I've already done that (thank you again, StackOverflow!) In the end, what I needed for the immediate job was to add `@JsonDeserize(using=...)`. This worked beautifully to keep the JSON-RCP conversion from trying to re-instantiate my static instances. Once I get a chance, I'll tryout the `converionService` and update the thread. Thanks again! – Didjit Mar 13 '13 at 00:08