11

Let's say I have 2 different sets of enums: fruits and vegetables.

public static enum Fruits{
    APPLE ("Apple"),
    PEAR ("Pear");

    //constructor
    //getName()
    ... 
}
public static enum Vegetables{
    CARROT ("Carrot"),
    LETTUCE ("Lettuce");

    //constructor
    //getName()
    ...
}

I display all this in a JComboBox. After someone selects something, I want to use a getter method to get back the Enum.

For a single enum, I would do something like:

public static Fruits getEnum(String name) {
  for(Fruits fruit: Fruits.values()) {
    if(name.equals(fruit.getName())) {
      return fruit;
    }
  }
  return null;
}

Any ideas what the return type is? I tried using Enum instead of Fruits. When I do that, I don't seem to have access to the getName() methods.

5 Answers 5

21

Here is another demonstration of what you're looking for. The difference between this and previous solutions is that this one is more generic and reusable pattern. This in fact goes beyond the original problem, to show some other benefits of this approach. So you might just comment the bits you don't need. I also attach a unit test to demonstrate the behaviour.

So basically to look for name Apple or APPLE in one of these enums just write:

FruitVeg<?> fvg = getEnum("APPLE", Fruits.class, Vegetables.class);

FruitVeg<> is an interface, which allows to also tap inside of Enum, this interface allows to do some very interesting things with enums below. Here are just some of the things you could do with that:

  • Enum.valueOf(fvg.getDeclaringClass(), fvg.name()): returns enum Value e.g. APPLE

  • fvg.getRaw(): returns enum Value e.g. APPLE

  • fvg.name() : returns enum's String Name e.g. APPLE

  • fvg.getFriendlyName() : e.g. Apple

  • fvg.getDeclaringClass() : returns Class<Enum<?>> e.g. class ox.dummy.dummyTest$Fruits

  • fvg.getClass() : class ox.dummy.dummyTest$Fruits returns Class<?>

  • EnumSet.allOf(fvg.getDeclaringClass())) : e.g. [APPLE, PEAR]

Here is code

   @Test
public void doSimpleTest() throws Exception {

    FruitVeg<?> fvg = getEnum("APPLE", Fruits.class, Vegetables.class);
    log.info("{} : {} : {} : {} : {}", fvg.name(), fvg.getFriendlyName(), fvg.getClass(), fvg.getDeclaringClass(), EnumSet.allOf(fvg.getDeclaringClass()));
    log.info("get enum: {} ", Enum.valueOf(fvg.getDeclaringClass(), fvg.name()));

}


public interface FruitVeg<T extends Enum<T>> {
    String name();

    String getFriendlyName();

    Class<T> getDeclaringClass();

    T getRaw();

}

enum Fruits implements FruitVeg<Fruits> {
    APPLE("Apple"),
    PEAR("Pear");

    Fruits(String friendlyName) {
        this.friendlyName = friendlyName;
    }

    private final String friendlyName;

    @Override
    public String getFriendlyName() {
        return friendlyName;
    }
    @Override
    public Fruits getRaw() {
        return this;
    }
}


enum Vegetables implements FruitVeg<Vegetables> {
    CARROT("Carrot"),
    LETTUCE("Lettuce");

    Vegetables(String friendlyName) {
        this.friendlyName = friendlyName;
    }

    private final String friendlyName;

    @Override
    public String getFriendlyName() {
        return friendlyName;
    }

    @Override
    public Vegetables getRaw() {
        return this;
    }
}


public static FruitVeg<?> getEnum(String name, Class<? extends FruitVeg<?>>... fvgClasses) {
    for (Class<? extends FruitVeg<?>> fruitVegCLass : Arrays.asList(fvgClasses)) {
        for (FruitVeg<?> fvg : fruitVegCLass.getEnumConstants()) {
            if (name.equals(fvg.name()) || name.equals(fvg.getFriendlyName())) {
                return fvg;
            }
        }
    }
    return null;
}
Sign up to request clarification or add additional context in comments.

1 Comment

Nice! this is what I needed. Since it seems impossible to restrict the getEnum method to enums only, I would add an assert class.isEnum()
3

Option 1.
Create one method that returns Enum

public static Enum getEnum(String name) {
    Enum selectedEnum = null;
    for (Fruits fruit : Fruits.values()) {
        if (name.equals(fruit.getName())) {
            selectedEnum = fruit;
        }
    }

    for (Vegetables vegetables : Vegetables.values()) {
        if (name.equals(vegetables.getName())) {
            selectedEnum = vegetables;
        }
    }
    return selectedEnum;
}

and to get the name of enum you can use this method

public static String getName(final Enum value) {
    String name = null;
    if (value instanceof Fruits) {
        name = ((Fruits) value).getName();
    } else if (value instanceof Vegetables) {
        name = ((Vegetables) value).getName();
    }
    return name;
}

Option 2.
You can combine 2 enum as

public static enum FruitsAndVegitables{
    APPLE ("Apple" , true),
    PEAR ("Pear", true),
    CARROT ("Carrot", false),
    LETTUCE ("Lettuce", false);

    private String name;
    private boolean isFurit;
    //constructor
    //getName()
    ... 
}

3 Comments

Since I don't want to combine the enums, I guess my only option is 1.
@dalawh If you found any answer helpful to you. Then upvote and accept that ans so that in future it will be helpful for others.I found you asked so many question but yet not accept any answer. So if any answer solves your problem so please accept that answer.
So there is not way of getting the enum type within the enum without having to combine the enums?
1

Pass in the Enums themselves as values. Then use getSelectedItem to retrieve the selected object, and do a test to see what type the object is.

Make the return type of your method an Object, not an enum of a specific type. This would fix your problem.

However, I think your approach is wrong. If I wanted fruits and vegetables displayed in a list and broken into categories, I'd create an object to do so, and an enum to represent type of food like so:

public enum FoodType{FRUIT, VEGETABLE}
public class Food{
    FoodType type;
    String name;
    public Food(FoodType type, String name){
        this.type = type;
        this.name = name;
    }
    public String toString(){return this.name;}
}

//and then when you want to use it...
Food lettuce = new Food(FoodType.VEGETABLE, "Lettuce");
Food berry = new Food(FoodType.FRUIT, "Berry");
comboBox.add(lettuces);
comboBox.add(berry);

And only add Food items to your JComboBox. Return Food items when a selection is made, and test for food type using the FoodType enum.

Comments

0

It sounds like what you're looking for is the ability to apply inheritance to enums, but this is not possible in java, as enums implicity extend java.lang.Enum and java does not support multiple inheritance.

Nonetheless, I think that using "nested enums" could solve your problem. By nested, I mean implementing an interface to get around the multiple inheritance issue. There are a few different approaches in the answers in the link, I assume one of them will suffice.

Comments

0

You could use Object instead of explicitly using Fruit or Vegetables

public static Object getEnum(String name) 
{    
    for(Fruits fruit: Fruits.values()) 
    {
        if(name.equals(fruit.getName())) 
        {
              return fruit;
        }
    }
    for(Vegetables vege: Vegetables.values()) 
    {
        if(name.equals(Vegetables.getName())) 
        {
              return vege;
        }
    }
  return null;
}

Downside of this however is that you will then have to compare and cast the result to what you want

Object o = getEnum("Carrot")
if(o instanceof Vegetable)
{
     Vegetable v = (Vegetable)o;
     v.getName();
}
//.. and again for fruit

2 Comments

I was hoping that I did not have to compare and cast the results.
Unfortunately, this option means I would have to create an if and else if statement for every different enum and a copy of the code would have to reside in each one.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.