Embeddable classes
Embeddable classes group properties for entity classes.
Embeddable definition
Here is an example of how to define an embeddable class:
@Embeddable
public class Address {
final String city;
final String street;
@Column(name = "ZIP_CODE")
final String zip;
public Address(String city, String street, String zip) {
this.city = city;
this.street = street;
this.zip = zip;
}
}
You can apply the @Embeddable
annotation to both classes and records:
@Embeddable
public record Address(
String city,
String street,
@Column(name = "ZIP_CODE")String zip) {
}
The embeddable class is used as the entity field type:
@Entity
public class Employee {
@Id
Integer id;
Address address;
}
The above entity definition is equivalent to following one:
@Entity
public class Employee {
@Id
Integer id;
String city;
String street;
@Column(name = "ZIP_CODE")
String zip;
}
Naming convention
The naming convention is inherited from the enclosing entity class.
Field definition
By default, all fields are persistent and correspond to database columns or result set columns.
The field type must be one of the following:
java.util.Optional, whose element is either Basic classes or Domain classes
java.util.OptionalInt
java.util.OptionalLong
java.util.OptionalDouble
@Embeddable
public class Address {
...
String street;
}
Column
You can specify the corresponding column name with the @Column
annotation:
@Column(name = "ZIP_CODE")
final String zip;
Transient
If an embeddable has fields that you don’t want to persist, you can annotate them using @Transient
:
Method definition
There are no limitations in the use of methods.
Using @Embedded annotation
You can use the @Embedded
annotation to embed the same embeddable type multiple times within a single entity with different column name prefixes.
Basic usage
@Embeddable
public record Address(String street, String city, String zipCode) {}
@Entity(naming = NamingType.SNAKE_LOWER_CASE)
public class Customer {
@Id
Integer customerId;
@Embedded(prefix = "billing_")
Address billingAddress;
@Embedded(prefix = "shipping_")
Address shippingAddress;
}
This will generate the following columns in the SQL statements:
billing_street
billing_city
billing_zip_code
shipping_street
shipping_city
shipping_zip_code
Prefix behavior
The prefix
attribute controls how column names are generated:
Column names are generated by combining the prefix with the embeddable field column name
The prefix is added as-is to the field column name
If no prefix is specified, the behavior remains the same as using the embeddable field column name directly
@Entity(naming = NamingType.SNAKE_LOWER_CASE)
public class Order {
@Id
Integer orderId;
// Without prefix - generates columns: street, city, zip_code
Address address;
// With prefix - generates columns: delivery_street, delivery_city, delivery_zip_code
@Embedded(prefix = "delivery_")
Address deliveryAddress;
}
Column overrides
You can use the columnOverrides
attribute along with @ColumnOverride
annotations to have fine-grained control over individual column mappings:
@Entity
public class Customer {
@Id
Integer id;
@Embedded(columnOverrides = {
@ColumnOverride(name = "street", column = @Column(name = "BILLING_STREET")),
@ColumnOverride(name = "city", column = @Column(name = "BILLING_CITY"))
})
Address billingAddress;
@Embedded(columnOverrides = {
@ColumnOverride(name = "street", column = @Column(name = "SHIP_STREET", insertable = false)),
@ColumnOverride(name = "city", column = @Column(name = "SHIP_CITY", updatable = false))
})
Address shippingAddress;
}
The @ColumnOverride
annotation allows you to:
Specify a custom column name for a specific embeddable field
Override column attributes such as
insertable
,updatable
, andquote
Take precedence over any
prefix
attribute when both are specified
Note
When both prefix
and columnOverrides
are used, the @ColumnOverride
settings take precedence for the specified fields.
Example
Employee employee = new Employee(); // Entity
Address address = new Address("Tokyo", "Yaesu", "103-0028"); // Embeddable
employee.setAddress(address);