77

This question is basically an extension of my previous question . I asked the previous question to be sure that the Enum constants are populated when the class loads . Here's is my class again with the addition of a simple method getByName :

public enum PropName {

  CONTENTS("contents"),
  USE_QUOTES("useQuotes"),
  ONKEYDOWN("onkeydown"),
  BROWSER_ENTIRE_TABLE("browseEntireTable"),
  COLUMN_HEADINGS("columnHeadings"),
  PAGE_SIZE("pageSize"),
  POPUP_TITLE("popupTitle"),
  FILTER_COL("filterCol"),
  SQL_SELECT("sqlSelect"),
  ;

  private String name;

  private PropName(String name) {
    this.name = name;
  }

  public String getName() {
    return name;
  }

  public static PropName getByName(String name){
    return   PropName.valueOf(name);
  }
}

A call to the method getByName("columnHeadings") is throwing java.lang.IllegalArgumentException: No enum const class labware.web.component.limsgrid.PropName.columnHeadings but if I replace this method with the following code it just works .

 public static PropName getByName(String name){
    for(PropName prop : values()){
      if(prop.getName().equals(name)){
        return prop;
      }
    }

    throw new IllegalArgumentException(name + " is not a valid PropName");
  }

Any ideas as to what I am doing wrong here ?

Community
  • 1
  • 1
Geek
  • 26,489
  • 43
  • 149
  • 227
  • 4
    You really should not define a property named "name" in your enum. You'll have name() and getName() returning different value... – Denys Séguret Sep 28 '12 at 12:13

4 Answers4

107

Enum.valueOf() only checks the constant name, so you need to pass it "COLUMN_HEADINGS" instead of "columnHeadings". Your name property has nothing to do with Enum internals.


To address the questions/concerns in the comments:

The enum's "builtin" (implicitly declared) valueOf(String name) method will look up an enum constant with that exact name. If your input is "columnHeadings", you have (at least) three choices:

  1. Forget about the naming conventions for a bit and just name your constants as it makes most sense: enum PropName { contents, columnHeadings, ...}. This is obviously the most convenient.
  2. Convert your camelCase input into UPPER_SNAKE_CASE before calling valueOf, if you're really fond of naming conventions.
  3. Implement your own lookup method instead of the builtin valueOf to find the corresponding constant for an input. This makes most sense if there are multiple possible mappings for the same set of constants.
Costi Ciudatu
  • 37,042
  • 7
  • 56
  • 92
  • What if you need to map that exactly that way? You have "columnHeadings" coming from somewhere else and need to use it as COLUMN_HEADINGS enum in the code? – Ville Jun 05 '17 at 20:18
  • 1
    Thanks for the clarification here! One might ask what the point is of the associated type if you can't map to an enum using the raw value. I might be missing something. – Matt Mc Apr 02 '18 at 10:07
12

That's because you defined your own version of name for your enum, and getByName doesn't use that.

getByName("COLUMN_HEADINGS") would probably work.

Guillaume
  • 22,694
  • 14
  • 56
  • 70
3

Instead of defining: COLUMN_HEADINGS("columnHeadings")

Try defining it as: COLUMNHEADINGS("columnHeadings")

Then when you call getByName(String name) method, call it with the upper-cased String like this: getByName(myStringVariable.toUpperCase())

I had the same problem as you, and this worked for me.

Prasanna Kumar H A
  • 3,341
  • 6
  • 24
  • 52
LuvCode
  • 31
  • 1
  • This force you to have exactly (caseinsensitive) same enum name and property value. – Jon Jan 06 '17 at 12:59
1

I had parsing enum problem when i was trying to pass Nullable Enum that we get from Backend. Of course it was working when we get value, but it was problem when the null comes up.

java.lang.IllegalArgumentException: No enum constant

Also the problem was when we at Parcelize read moment write some short if.

My solution for this was

1.Create companion object with parsing method.

enum class CarsType {
    @Json(name = "SMALL")
    SMALL,
    @Json(name = "BIG")
    BIG;

    companion object {
        fun nullableValueOf(name: String?) = when (name) {
            null -> null
            else -> valueOf(name)
        }
    }
}

2. In Parcerable read place use it like this

data class CarData(
    val carId: String? = null,
    val carType: CarsType?,
    val data: String?
) : Parcelable {
    constructor(parcel: Parcel) : this(
        parcel.readString(),
        CarsType.nullableValueOf(parcel.readString()),
        parcel.readString())
Jakub S.
  • 5,580
  • 2
  • 42
  • 37