Extending Java Enums


Posted by Steven

I often stumble over ideas that are cool in some way and that I would never have thought about it. One of those ideas is extending Java Enums. Often frameworks and toolkits bring some kind of enumeration with them. For most of the tasks at hand, the elements in those Enums are sufficient. For the other cases, they can be extended to include more status. Of cause the library cannot handle the added elements in the Enum, so the methods working with it may have to be overridden. In this article I want to show how Java Enums can be extended.

First, let's have a look at the Enum:

  1. package closedLibrary;
  2.  
  3. public enum ClosedEnum implements ClosedEnumExtensionInterface {
  4.  
  5. ONE(1), TWO(2);
  6.  
  7. private int value;
  8.  
  9. ClosedEnum(int value) {
  10. this.value = value;
  11. }
  12.  
  13. public int getValue() {
  14. return value;
  15. }
  16. }

To make this Enum extendable, the following points must hold true:

  1. An extension-interface has to be delivered with the Enum. This interface defines all methods that the Enum and its extension should provide.
  2. The Enum has to implement that interface.
  1. package closedLibrary;
  2.  
  3. public interface ClosedEnumExtensionInterface {
  4.  
  5. public int getValue();
  6.  
  7. }

With that interface, an extension can be written:

  1. package ownProject;
  2.  
  3. import closedLibrary.ClosedEnumExtensionInterface;
  4.  
  5. public enum OwnExtendedEnum implements ClosedEnumExtensionInterface {
  6.  
  7. ONE(1), TWO(2), THREE(3), FOUR(4);
  8.  
  9. private int value;
  10.  
  11. private OwnExtendedEnum(int value) {
  12. this.value = value;
  13. }
  14.  
  15. @Override
  16. public int getValue() {
  17. return value;
  18. }
  19. }

As you can see, extending Enums is easy if the framework provides the interface for it. By either providing it or not, an API can be designed to have its Enums extended or not. As far as I see, there is no way to extend an Enum if there isn’t an interface for it within the API.

One weak point of that technique is that the user of the API has to implement the already existing elements of the Enum which causes code duplication.

Although this seems to be quite interesting, I have never seen this technique in the projects I worked in.

Share: 

Comments

Yes, I it is an option if some method needs to accept enum elements and something else. But replacing 
public void method(EnumType enumElement);
with
public void method(EnumInterface enumElement);
you lose the major feature of enums - compiletime knowledge about all instances. And if you throw this away, do you really need the enumeration?


Hi Gleb,

I'm not sure if I understand what you mean. If the user of the API (= programmer who extends the enum) copies all instances of the original enum into his own, they are not lost. During compile time, he can see the original plus the new instances in the extended enum. So the knowledge about all instances is not lost.


Hi, Steven

I mean, that It is strange idea to me - to copy instances of existing enum into another one for adding few own instances.

It is ok to use enum for defining all possible arguments for some functions. Another common way is to use integer constants and enum can be more readable and failproof. For this case enum has excelent feature - compilier can check if all cases were mentioned in switch-case.

Also it is ok to define interface as argument type. But IMHO in this case you mean that your function dont know and dont care of actual argumetn type, while it keeps that contract of the interface. Of course you can provide few default implementations of the interface, and it can be useful to store them in enum instead of constants. But i dont see the reason why user can need to create its own enum and copy default implementations there. If you need your own InputStream you just make class with needed behaviour and use it, aren`t you?


Hi Gleb,

you're right, the duplication of existing code is weird. Additionally a software will loose the ability to be updated once the technique from my article is implemented: The developer of the library cannot add instances in the enum that might be added by the users of the lib. Also, as you mentioned, using an interface as the paramter of a method weakens the contract of this method. I agree that there are many problems with this approach. Maybe this is the reason why I've never seen it in real code.

However, the compiler can check the possible instances of the enum (not the interface!) at any time. This way, the developer of the library can see all instances of the original enum and the developer of the code using the library can see of his added instances.

This article is meant as a report of a possibility. I am not recommending this, just pointing to it because it was interesting to me. So: Don't try this at home. ;)