Skip to content

Instantly share code, notes, and snippets.

@iampaul83
Last active April 23, 2024 09:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save iampaul83/f23c913801bf329ff5ed4435d04fec86 to your computer and use it in GitHub Desktop.
Save iampaul83/f23c913801bf329ff5ed4435d04fec86 to your computer and use it in GitHub Desktop.
Spring Data JPA Enum converter

Spring Data JPA Enum converter

Column 使用 NUMBER 型別,如何在 JPA 中用 Enum 做 mapping,且不使用 @Enumerated(EnumType.ORDINAL)

CREATE TABLE CHALLENGE_LOG (
  ACTION NUMBER(1) NOT NULL
);
COMMENT ON COLUMN CHALLENGE_LOG.ACTION IS '0=Send OTP, 1=Verify OTP';

1. 新增 PersistableEnum interface,要 mapping 的 Enum 需要實作此介面

public interface PersistableEnum<T> {
  T getCode();
}

2. 新增一個通用的 AbstractEnumConverter,實作 javax.persistence.AttributeConverter

import javax.persistence.AttributeConverter;

/*
 Base Enum converter for JPA
*/
public abstract class AbstractEnumConverter<T extends Enum<T> & PersistableEnum<E>, E>
    implements AttributeConverter<T, E> {

  private final Class<T> clazz;

  public AbstractEnumConverter(Class<T> clazz) {
    this.clazz = clazz;
  }

  @Override
  public E convertToDatabaseColumn(T attribute) {
    return attribute != null ? attribute.getCode() : null;
  }

  @Override
  public T convertToEntityAttribute(E dbData) {
    T[] enums = clazz.getEnumConstants();

    for (T e : enums) {
      if (e.getCode().equals(dbData)) {
        return e;
      }
    }

    throw new UnsupportedOperationException(
        String.format("%s cannot convert to %s enum value.", dbData, clazz));
  }
}

3. 新增 Enum. 實作 PersistableEnum 並新增 converter

@Getter
@AllArgsConstructor
public enum ChallengeAction implements PersistableEnum<Integer> {
  // 0=Send OTP, 1=Verify OTP
  SEND_OTP(0),
  VERIFY_OTP(1);

  private final Integer code;

  // JPA converter
  @javax.persistence.Converter(autoApply = true)
  public static class Converter extends AbstractEnumConverter<ChallengeAction, Integer> {
    public Converter() {
      super(ChallengeAction.class);
    }
  }
}

4. Entity. action 欄位使用 ChallengeAction enum

@Entity
@Data
public class ChallengeLog  {
  @Id
  @GeneratedValue(generator = "UUID")
  @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
  @Column(name = "UUID")
  private String id;
  
  private ChallengeAction action;

}

5. 測試

Insert

ChallengeLog challengeLog = new ChallengeLog();
challengeCodeLog.setAction(ChallengeAction.SEND_OTP);
challengeCodeRepository.save(challengeCodeLog);
// -> action 欄位為 0

Query

challengeCodeRepository.findAll();
// -> 正確將 action 欄位 mapping 成 ChallengeAction enum
@amirnikjoo
Copy link

hi,
could you help me to resolve get empty field from the db?
the error is
org.springframework.orm.jpa.JpaSystemException: Error attempting to apply AttributeConverter; nested exception is javax.persistence.PersistenceException: Error attempting to apply AttributeConverter, in class ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment