Hibernate 6.3.1.Final Mariadb @Enumerated(EnumType.STRING) not working

1.1k views Asked by At

Using a legacy db schema with newest Hibernate 6.3.1.Final with Spring Boot 3.1.4 has had quite a few code migration work needed for JPA models. Most of my issues currently are with Enum types. I've had issue with Enums in the mysql database that were stored as int(11) producing "expecting #TINYINT" errors, which I could only solve by changing the column type in the db (something that would break legacy code). I tried these changes to the annotation to no avail, and I couldn't find any other solution in blogs. Note: I did not have these validation issues with Hibernate 6.0.1.Final:

@Column(name="status", columnDefinition = "INTEGER") or @Column(name="status", columnDefinition = "int2")

Another issue was with "@Enumerated(EnumType.STRING)", which doesn't seem to work at all. Documentation from https://docs.jboss.org/hibernate/orm/6.3/introduction/html_single/Hibernate_Introduction.html#enums isn't complete or no longer accurate. I have an enum in a legacy database stored as "varchar(255)", with the following JPA definition:

@Column(name = "status", nullable = false)
@Enumerated(EnumType.STRING)
@Basic(optional=false)
private ActiveOrInactive status;

And I get the following error on validation:

found [varchar (Types#VARCHAR)], but expecting [enum ('active','inactive') (Types#ENUM)]

Again, I did not get this issue with Hibernate 6.0.1.Final.

What changes should I make to my annotation for Enums stored as int(11) or varchar(255) in Mysql db?

import java.util.HashMap;
import java.util.Map;

public enum ActiveOrInactive {
    
    Active, Inactive;
    
    static final Map<String, ActiveOrInactive> _activeOrInactive = new HashMap<String, ActiveOrInactive>();
    static {
        for (ActiveOrInactive activeOrInactive : ActiveOrInactive.values()) {
            _activeOrInactive.put(activeOrInactive.toString(), activeOrInactive);
        }
    }
    
    public static Map<String, ActiveOrInactive> getPublishedStateTypes() {
        return _activeOrInactive;
    }
    

}
2

There are 2 answers

1
korsgaard On BEST ANSWER

According to https://docs.jboss.org/hibernate/orm/6.3/introduction/html_single/Hibernate_Introduction.html @Enumerated(EnumType.STRING) is mapped to varchar, except for Mysql (and maybe MariaDB) where it is mapped to an ENUM column type.

If you change: @Column(name = "status", nullable = false) to:

@Column(name = "status", nullable = false, columnDefinition = "varchar")

you can make hibernate understand that it's a varchar column.

0
Asgar On

I believe you should use a Custom Converter for this. I am giving an example for datatype varchar in your database i.e., @Enumerated(EnumType.STRING), if it is for int, changes in your custom converter class can be made accordingly.

@Converter
public class ActiveOrInactiveConverter implements Serializable,  AttributeConverter<ActiveOrInactive, String> {

    @Override
    public String convertToDatabaseColumn(ActiveOrInactive attribute) {
        if (attribute == null) {
            return null;
        }
        return attribute.name();
    }

    @Override
    public ActiveOrInactive convertToEntityAttribute(String dbData) {
        if (dbData == null) {
            return null;
        }
        return ActiveOrInactive.valueOf(dbData);
    }
}

And

You should replace your

@Enumerated(EnumType.STRING)

with

@Convert(converter = ActiveOrInactiveConverter.class)

It should look like:

@Column(name = "status", nullable = false)
@Convert(converter = ActiveOrInactiveConverter.class)
@Basic(optional=false)
private ActiveOrInactive status;

Here is a reference