Custom AttributeConverter
AdvancedAttributeConverter<X,Y> maps between a Java type and a DB column type; use for enums, JSON objects, encrypted values, or custom domain types not natively supported by JPA.
Overview
AttributeConverter<X, Y> is a JPA interface for writing custom type mappings. X is the Java type; Y is the DB column type. Implement convertToDatabaseColumn(X) and convertToEntityAttribute(Y). Annotate with @Converter; add autoApply=true to apply it to all attributes of type X without needing @Convert on every field. Common uses: storing Java enums by a code rather than name, serialising a POJO to JSON, encrypting sensitive fields, mapping custom domain types (Money, Period, PhoneNumber) to a string or numeric column.
Enum Converter — Store by Code Not Name
Storing enums by @Enumerated(STRING) breaks if the enum is renamed. A converter stores a stable code instead, decoupling the enum identifier from DB values.
public enum OrderStatus {
PENDING("P"), PLACED("PL"), SHIPPED("SH"), DELIVERED("DE"), CANCELLED("CA");
private final String code;
OrderStatus(String code) { this.code = code; }
public String getCode() { return code; }
public static OrderStatus fromCode(String code) {
return Arrays.stream(values())
.filter(s -> s.code.equals(code))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("Unknown code: " + code));
}
}
@Converter(autoApply = true) // auto-applies to all OrderStatus fields in all entities
public class OrderStatusConverter implements AttributeConverter<OrderStatus, String> {
@Override
public String convertToDatabaseColumn(OrderStatus status) {
return status == null ? null : status.getCode();
}
@Override
public OrderStatus convertToEntityAttribute(String code) {
return code == null ? null : OrderStatus.fromCode(code);
}
}JSON Converter — Store a POJO as JSON
Map a complex Java object to a single TEXT/JSON column. Useful for schemaless attributes or configurations stored inline with an entity.
@Converter
public class OrderMetadataConverter implements AttributeConverter<OrderMetadata, String> {
private static final ObjectMapper MAPPER = new ObjectMapper();
@Override
public String convertToDatabaseColumn(OrderMetadata metadata) {
if (metadata == null) return null;
try {
return MAPPER.writeValueAsString(metadata);
} catch (JsonProcessingException e) {
throw new IllegalArgumentException("Cannot serialise OrderMetadata", e);
}
}
@Override
public OrderMetadata convertToEntityAttribute(String json) {
if (json == null) return null;
try {
return MAPPER.readValue(json, OrderMetadata.class);
} catch (JsonProcessingException e) {
throw new IllegalArgumentException("Cannot deserialise OrderMetadata", e);
}
}
}
@Entity
public class Order {
@Convert(converter = OrderMetadataConverter.class)
@Column(columnDefinition = "TEXT")
private OrderMetadata metadata;
}Encrypted Field Converter
Converters are ideal for transparent field encryption: the Java code works with plaintext; the DB stores ciphertext. Inject a key management service via the Spring context.
@Component
@Converter
public class EncryptedStringConverter implements AttributeConverter<String, String> {
@Autowired
private EncryptionService encryptionService;
@Override
public String convertToDatabaseColumn(String plaintext) {
return plaintext == null ? null : encryptionService.encrypt(plaintext);
}
@Override
public String convertToEntityAttribute(String ciphertext) {
return ciphertext == null ? null : encryptionService.decrypt(ciphertext);
}
}
@Entity
public class PaymentMethod {
@Convert(converter = EncryptedStringConverter.class)
private String cardToken; // stored as ciphertext; loaded as plaintext
}Key Points to Remember
- 1AttributeConverter<X,Y>: X = Java type, Y = DB column type (usually String or primitives)
- 2autoApply=true applies the converter globally to all fields of that type — no @Convert needed
- 3Converters run on every read/write — keep them stateless and fast (avoid heavy I/O)
- 4Storing enums by code (not name) decouples code from DB; rename the enum freely without migration
- 5@Convert(converter=…) on a field overrides or disables autoApply for that specific field
- 6Spring-managed @Component converters can use @Autowired to inject services
Interview Questions
Sign in to ask AriaWhat are the two methods you must implement in AttributeConverter?
Why is storing enums via an AttributeConverter safer than @Enumerated(STRING)?
What does autoApply=true do in @Converter?
How would you implement transparent field encryption using a JPA AttributeConverter?
Can a @Converter class be a Spring @Component? What advantage does that provide?
Ask Aria about Custom AttributeConverter
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.