3

I'm trying to retrieve an enum from a database and Hibernate doesn't find the property value and therefore throws the following Exception java.lang.IllegalArgumentException: No enum constant com.intrawa.qx.validator.models.entity.Group.CONFIGTAB.false

The problem occurs when hibernate calls the valueof method of the enum: at java.lang.Enum.valueOf(Enum.java:238)

I'm working with a Database where I cannot change it's column names.

For example look at the code:

@Entity
@Data
@Table(name = "bm_host_groups")
public class Group {

    @Enumerated(EnumType.STRING)
    private CONFIGTAB configTab;

    @AllArgsConstructor
    private enum CONFIGTAB {
        TRUE("true"),
        FALSE("false");


        @Getter @Setter
        private String value;
    }
}

The DB has a column called configTab with enum value type and two possible values ("true", "false"), when hibernate call valueof("true") it doesn't find TRUE and throws the exception.

One solution I found it's on this post: What is the reason for java.lang.IllegalArgumentException: No enum const class even though iterating through values() works just fine?

However, it needs a custom method that takes for example "true" as argument from the DB then capitallize it in order to find the value of the enum.

I searched a way to override Enum's valueof() but this post says it's not possible and basically suggest the same as the first solution, make a custom method and make the client calls it. Post: Override valueof() and toString() in Java enum

Is there a way to make hibernate call a custom method instead of valueof()?

1 Answers1

3

It is not possible to override valueOf(). But it is possible to manipulate the value that valueOf() will get. Namely, the correct solution is to use AttributConverter and discard the @Enumerated annotation, like:

@Getter @Setter
//@Enumerated(EnumType.STRING)
@Convert(converter=ConfigTabConverter.class)
private CONFIGTAB configTab;

Converter is quite simple:

@Converter(autoApply=true)
public class ConfigTabConverter
        implements AttributeConverter<CONFIGTAB,, String> {

    @Override
    public String convertToDatabaseColumn(CONFIGTAB attribute) {
        return attribute.getValue();
    }

    @Override
    public CONFIGTAB convertToEntityAttribute(String dbData) {
        return CONFIGTAB.valueOf(dbData.toUpperCase());
    }
}
pirho
  • 11,565
  • 12
  • 43
  • 70
  • Thanks! this made the trick, now i'm looking for a way to make an abstraction of this because I have 4 more enums that have the same fields (TRUE("true"), FALSE("false") and I basically created 4 classes with almost the same code. – David Salas Boscan Nov 18 '18 at 19:57
  • @DavidSalasBoscan You might want to ask another question regarding that. Guess it is doable by using generics. – pirho Nov 18 '18 at 20:28
  • @DavidSalasBoscan Did you find my answer useful? If you did consider accepting and/or upvoting it. If you did not not please comment my answer what is wrong with it. If you found better solution create a new answer based on it. – pirho Nov 22 '18 at 10:01
  • Hello @pirho , I did vote you because your answer solves my issue, but I have less than 15 points so it doesn't count in the vote count of stackoverflow, thanks a lot. – David Salas Boscan Nov 23 '18 at 13:48
  • @DavidSalasBoscan Thanks for the reply. But you should be able accept by clicking the check it gives you also +2 Rep :). But not meaning you have to if you have a reason to not. – pirho Nov 23 '18 at 14:04