Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to enable enum inheritance

I'm writing a library, which has a predefined set of values for an enum. Let say, my enum looks as below.

public enum EnumClass {
    FIRST("first"),
    SECOND("second"),
    THIRD("third");

    private String httpMethodType;

}

Now the client, who is using this library may need to add few more values. Let say, the client needs to add CUSTOM_FIRST and CUSTOM_SECOND. This is not overwriting any existing values, but makes the enum having 5 values.

After this, I should be able to use something like <? extends EnumClass> to have 5 constant possibilities.

What would be the best approach to achieve this?

like image 584
Kiran A B Avatar asked Feb 26 '16 11:02

Kiran A B


People also ask

How do you inherit an enum?

Enums cannot inherit from other enums. In fact all enums must actually inherit from System. Enum . C# allows syntax to change the underlying representation of the enum values which looks like inheritance, but in actuality they still inherit from System.

Can enums use inheritance?

2.2. Inheritance Is Not Allowed for Enums.

Can enum inherit in C++?

Not possible. There is no inheritance with enums. You can instead use classes with named const ints.

Can we inherit enum in C#?

Nope. it is not possible. Enum can not inherit in derived class because by default Enum is sealed.


2 Answers

You cannot have an enum extend another enum, and you cannot "add" values to an existing enum through inheritance.

However, enums can implement interfaces.

What I would do is have the original enum implement a marker interface (i.e. no method declarations), then your client could create their own enum implementing the same interface.

Then your enum values would be referred to by their common interface.

In order to strenghten the requirements, you could have your interface declare relevant methods, e.g. in your case, something in the lines of public String getHTTPMethodType();.

That would force implementing enums to provide an implementation for that method.

This setting coupled with adequate API documentation should help adding functionality in a relatively controlled way.

Self-contained example (don't mind the lazy names here)

package test;

import java.util.ArrayList;
import java.util.List;

public class Main {

    public static void main(String[] args) {
        List<HTTPMethodConvertible> blah = new ArrayList<>();
        blah.add(LibraryEnum.FIRST);
        blah.add(ClientEnum.BLABLABLA);
        for (HTTPMethodConvertible element: blah) {
            System.out.println(element.getHTTPMethodType());
        }
    }

    static interface HTTPMethodConvertible {
        public String getHTTPMethodType();
    }
    static enum LibraryEnum implements HTTPMethodConvertible {
        FIRST("first"),
        SECOND("second"),
        THIRD("third");
        String httpMethodType;
        LibraryEnum(String s) {
            httpMethodType = s;
        }
        public String getHTTPMethodType() {
            return httpMethodType;
        }
    }
    static enum ClientEnum implements HTTPMethodConvertible {
        FOO("GET"),BAR("PUT"),BLAH("OPTIONS"),MEH("DELETE"),BLABLABLA("POST");
        String httpMethodType;
        ClientEnum(String s){
            httpMethodType = s;
        }
        public String getHTTPMethodType() {
            return httpMethodType;
        }
    }
}

Output

first
POST
like image 104
Mena Avatar answered Oct 18 '22 22:10

Mena


Enums are not extensible. To solve your problem simply

  • turn the enum in a class
  • create constants for the predefined types
  • if you want a replacement for Enum.valueOf: track all instances of the class in a static map

For example:

public class MyType {
    private static final HashMap<String,MyType> map = new HashMap<>();
    private String name;
    private String httpMethodType;

    // replacement for Enum.valueOf
    public static MyType valueOf(String name) {
         return map.get(name);
    }

    public MyType(String  name, String httpMethodType) {
         this.name = name;
         this.httpMethodType = httpMethodType;
         map.put(name, this);
    }

    // accessors
    public String name() { return name; }
    public String httpMethodType() { return httpMethodType; }

    // predefined constants
    public static final MyType FIRST = new MyType("FIRST", "first");
    public static final MyType SECOND = new MyType("SECOND", "second");
    ...
}
like image 13
wero Avatar answered Oct 18 '22 22:10

wero