Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to make JPA ignore invalid types of enum?

There's a Microservice I'm working on, that used to have one kind of Enum related to one of it's columns, but now I had to change it.

@Convert(converter = TypeEnumConverter.class)
@Enumerated(EnumType.STRING)
@Column(name = "TIPO", length = 40, nullable = false)
private TypeEnum type;

It's mapped like that, but the enums names and types are imcompatible, is there a way to tell JPA to ignore it if it can't transform back to that enum?

like image 613
Bruno Pezzi Avatar asked Oct 25 '25 04:10

Bruno Pezzi


2 Answers

You can implement a custom enum mapping using an AttributeConverter. Within the converter, you could then map unknown enum values to null. But please be aware that the next update operation would then remove the value from that database column.

You already reference your TypeEnumConverter attribute converter in the @Convert annotation in your mapping. If you want to use it, you need to remove the @Enumerated annotation. The JPA specification doesn't allow you to use these 2 annotations together because both define how the Enum values get mapped.

Implementation Example

Here is an example of how such a mapping could look like.

My Enum

I use this simple Vehicle enum:

public enum Vehicle {
 
    BUS, CAR, TRAIN, PLANE;
}

My Attribute Converter

The attribute converter implements the mapping between the Java object and the value stored in your database. It's a simple Java class that implements the AttributeConverter interface and is annotated with @Converter. If you set the autoApply attribute to true, it will be automatically used for all entity attributes of the converted type.

@Converter(autoApply = true)
public class VehicleConverter implements AttributeConverter<Vehicle, String> {
 
    @Override
    public String convertToDatabaseColumn(Vehicle vehicle) {
        switch (vehicle) {
        case Vehicle.BUS:
            return "B";
 
        case Vehicle.CAR:
            return "C";
 
        case Vehicle.TRAIN:
            return "T";
 
        case Vehicle.PLANE:
            return "P";
        }
    }
 
    @Override
    public Vehicle convertToEntityAttribute(String dbData) {
        switch (dbData) {
        case "B":
            return Vehicle.BUS;
 
        case "C":
            return Vehicle.CAR;
 
        case "T":
            return Vehicle.TRAIN;
 
        case "P":
            return Vehicle.PLANE;
 
        default:
            // ignore unknown values
            return null;
        }
    }
 
}

My Entity Class

You can then use the enum without any additional mapping annotations in your entity class.

@Entity
public class Trip {
     
    private Vehicle vehicle;
 
    ...
}
like image 145
Thorben Janssen Avatar answered Oct 27 '25 18:10

Thorben Janssen


If you don't mind losing the legacy values in the DB that are incompatible with the current Enum then @Thorben response is the way to go.

If you want to preserve them, then one solution would be to declare your field as a String, and provide accessory methods to manipulate the value as an enum. Something like:

@Column(name = "TIPO", length = 40, nullable = false)
private String type;

public String getType() {
    return type;
}

public void setType(String type) {
    this.type = type;
}

public TypeEnum getTypeEnum() {
    try {
        return TypeEnum.valueOf(type);
    } catch (IllegalArgumentException e) {
        return null;
    }
}
  
public void setTypeEnum(TypeEnum typeEnum) {
    if (typeEnum != null) {
        type = typeEnum.toString();
    }
}
like image 42
areus Avatar answered Oct 27 '25 18:10

areus