पाठ 7 / 25
Basic Types, Enums, Embeddables and Converters
Map Java types, enums, value objects and custom conversions.
Mapping more than strings and numbers
JPA maps common Java types automatically: primitives and wrappers, String, BigDecimal, and the java.time types (LocalDate, LocalDateTime, Instant, OffsetDateTime). Enums are stored as ordinals by default (EnumType.ORDINAL), which silently corrupts data if anyone reorders or inserts enum constants, so always use @Enumerated(EnumType.STRING). Embeddables model value objects without their own identity: an @Embeddable Address with street, city and pin code is stored in the owning entity's table, mapped with @Embedded (and @AttributeOverrides to rename columns when embedding twice). Attribute converters (@Converter implementing AttributeConverter<X, Y>) map custom types such as a Money value object or an encrypted string to a database column. Hibernate 6 and later also map JSON columns with @JdbcTypeCode(SqlTypes.JSON), and large text or binary data with @Lob. Use @Column(columnDefinition = ...) sparingly, since it ties mappings to one database.
Value objects inside an entity row
An embeddable's fields become columns of the owning entity's table.
Enum, embeddable and converter mappings
Each mapping keeps the domain model expressive and the schema stable.
@Embeddable
public class Address {
private String street;
private String city;
@Column(name = "pin_code", length = 6)
private String pinCode;
protected Address() { }
public Address(String street, String city, String pinCode) { /* validate and assign */ }
}
public enum OrderStatus { PLACED, PAID, SHIPPED, CANCELLED }
@Converter(autoApply = false)
public class PhoneConverter implements AttributeConverter<PhoneNumber, String> {
public String convertToDatabaseColumn(PhoneNumber p) { return p == null ? null : p.e164(); }
public PhoneNumber convertToEntityAttribute(String s) { return s == null ? null : PhoneNumber.parse(s); }
}
@Entity
public class CustomerOrder {
@Id @GeneratedValue private Long id;
@Enumerated(EnumType.STRING) // stores 'PAID', not 1
@Column(nullable = false, length = 16)
private OrderStatus status;
@Embedded
@AttributeOverride(name = "street", column = @Column(name = "ship_street"))
@AttributeOverride(name = "city", column = @Column(name = "ship_city"))
@AttributeOverride(name = "pinCode", column = @Column(name = "ship_pin"))
private Address shippingAddress;
@Convert(converter = PhoneConverter.class)
private PhoneNumber contactPhone;
@JdbcTypeCode(SqlTypes.JSON) // Hibernate 6+: JSON column
private Map<String, String> giftOptions;
private Instant placedAt;
}Never use EnumType.ORDINAL
Adding REFUNDED between PAID and SHIPPED shifts the ordinals, so every existing row silently changes meaning. String-mapped enums survive reordering and are readable in the database.
त्वरित जाँच: Why is @Enumerated(EnumType.STRING) preferred over the default ORDINAL?
- Ordinals change meaning when enum constants are reordered or inserted, corrupting existing data
- Strings are faster to compare
- ORDINAL is not supported by Hibernate
- STRING uses less storage
Answer
Ordinals change meaning when enum constants are reordered or inserted, corrupting existing data — Stored ordinals depend on declaration order, which changes as the code evolves.