skip to content

An entity needs two attributes of the same @Embeddable type — for example a billing address and a shipping address — and both would map to identical column names. How do you make that work in JPA/Hibernate, including when the embeddable itself contains a nested embeddable or an association?

level: middleimportance: should knowfreq 52%

answer

  1. Repeated column in mapping → needs overrides
  2. name = path inside embeddable, not column
  3. Dots for nested: geo.latitude
  4. @AssociationOverride for @ManyToOne inside
  5. Override replaces the whole @Column, defaults return

basics

~10 s

Use @AttributeOverride on each embedded attribute to rename the columns, one per property. Nested embeddable properties are addressed with dotted paths like "geo.latitude". Associations inside the embeddable are renamed with @AssociationOverride instead.

solid answer

~50 s

Two embedded values of the same type would collide on column names, so the *owner* renames them with `@AttributeOverride`: ```java @Embedded @AttributeOverride(name = "street", column = @Column(name = "bill_street")) @AttributeOverride(name = "city", column = @Column(name = "bill_city")) private Address billingAddress; ``` `@AttributeOverride` is repeatable since Java 8, so the `@AttributeOverrides` wrapper is optional. Rules worth stating: - `name` is the **path inside the embeddable**, not the column name; nested embeddables use dots (`name = "geo.latitude"`). - Associations declared inside the embeddable are not covered — use `@AssociationOverride(name = "country", joinColumns = @JoinColumn(name = "bill_country_id"))`. - The same annotations work on `@EmbeddedId`, on `@ElementCollection` element attributes, and on fields inherited from a `@MappedSuperclass`. - Overrides are *mapping-level*, so you must list every colliding property; anything you omit keeps the embeddable's own column name and still collides. Hibernate 6.6+ adds `@EmbeddedColumnNaming("bill_%s")` as a pattern-based shorthand for the repetitive case.

code

java · 16 lines
java
@Entity
public class Order {
    @Id @GeneratedValue private Long id;

    @Embedded
    @AttributeOverride(name = "street",        column = @Column(name = "bill_street", nullable = false))
    @AttributeOverride(name = "geo.latitude",  column = @Column(name = "bill_lat"))
    @AssociationOverride(name = "country",     joinColumns = @JoinColumn(name = "bill_country_id"))
    private Address billing;

    @Embedded
    @AttributeOverride(name = "street",        column = @Column(name = "ship_street"))
    @AttributeOverride(name = "geo.latitude",  column = @Column(name = "ship_lat"))
    @AssociationOverride(name = "country",     joinColumns = @JoinColumn(name = "ship_country_id"))
    private Address shipping;
}

go deeper

for a junior

Know that duplicate embeddables collide on column names and that @AttributeOverride on the owning field fixes it; be able to write one override correctly.

for a middle

Explain dotted paths for nested embeddables, @AssociationOverride for associations, repeatability, and that the override replaces the whole @Column.

for a senior

Point out the constraint-loss trap under schema generation, where else overrides apply (@EmbeddedId, @ElementCollection, @MappedSuperclass), and when the override count signals the value type should be a real table.

for a principal

Treat it as a reuse-versus-clarity call: shared value types plus overrides keep invariants centralised, but heavy override blocks are a sign the model needs normalising or a Hibernate naming strategy applied consistently across the codebase.

## The problem An `@Embeddable` declares column names once, but a single entity may embed it more than once. Two `Address` fields both wanting `street`, `city`, `zip` cannot coexist in one table, and Hibernate fails at bootstrap with a repeated-column error ("Repeated column in mapping for entity"). The fix belongs to the **owner**, because only the owner knows the context of each copy. ## @AttributeOverride ```java @Entity public class Order { @Id @GeneratedValue private Long id; @Embedded @AttributeOverride(name = "street", column = @Column(name = "bill_street")) @AttributeOverride(name = "city", column = @Column(name = "bill_city")) private Address billing; @Embedded @AttributeOverride(name = "street", column = @Column(name = "ship_street")) @AttributeOverride(name = "city", column = @Column(name = "ship_city")) private Address shipping; } ``` Key details candidates get wrong: - **`name` is the attribute path inside the embeddable**, not a column name. `name = "street"` refers to the Java property; `column = @Column(name = "bill_street")` supplies the new column. - The `@Column` you supply **replaces** the embeddable's own `@Column` for that property. If the original declared `nullable = false, length = 120`, and your override omits them, you get the defaults back. Restate everything you care about. - `@AttributeOverride` is `@Repeatable` (Java 8 / JPA 2.2 onward), so the `@AttributeOverrides({...})` container is optional but still valid. - You must override **every** colliding property. Forgetting `zip` leaves both copies pointing at `zip` and bootstrap fails — which is at least a loud failure, not silent corruption. ## Nested embeddables Embeddables nest freely, and overrides address nested properties by dotted path: ```java @Embeddable class GeoPoint { double latitude; double longitude; } @Embeddable class Address { String street; @Embedded GeoPoint geo; } @Embedded @AttributeOverride(name = "street", column = @Column(name = "ship_street")) @AttributeOverride(name = "geo.latitude", column = @Column(name = "ship_lat")) @AttributeOverride(name = "geo.longitude",column = @Column(name = "ship_lon")) private Address shipping; ``` The path is always rooted at the embeddable being overridden, and only the outermost `@Embedded` carries the overrides — you do not repeat them on the nested field. ## Associations inside embeddables `@AttributeOverride` handles basic and embedded attributes only. If `Address` declares `@ManyToOne Country country`, the join column is renamed with a different annotation: ```java @AssociationOverride(name = "country", joinColumns = @JoinColumn(name = "ship_country_id")) ``` `@AssociationOverride` also carries `joinTable` for collection-valued associations inside the embeddable. ## Where else overrides apply - On `@EmbeddedId`, to rename composite-key columns per entity. - On `@ElementCollection`, where the overrides apply to the *element* attributes stored in the collection table. - On an entity that inherits attributes from a `@MappedSuperclass`, to retarget inherited columns. ## Hibernate-specific shorthand Repeating five overrides twice is noisy. Hibernate 6.6 introduced `@EmbeddedColumnNaming("bill_%s")`, which applies a printf-style pattern to every column of that embedded attribute, including nested ones. It is a Hibernate extension, not portable JPA — mention it as a convenience, and know the standard `@AttributeOverride` route because that is what an interviewer is testing. ## Design note If you find yourself writing a dozen overrides, ask whether the two copies really are the same value type or whether the schema should have been normalised (an `address` table with a foreign key). Overrides are cheap for two or three columns and a smell at ten.

  • If the embeddable declares @Column(nullable = false, length = 60) on a property and your @AttributeOverride only sets the name, what happens to the constraints?
    They are lost. The `@Column` inside `@AttributeOverride` replaces the original wholesale rather than merging with it, so any `nullable`, `length`, `unique` or `columnDefinition` you do not restate reverts to the JPA defaults. With `hbm2ddl` generating the schema, that silently produces a nullable VARCHAR(255).
  • Can you avoid overrides entirely by giving the two embedded fields different names and relying on a naming strategy?
    Not with the standard implicit naming strategies — they derive column names from the embeddable's own property names, so both copies still collide. You can write a custom Hibernate `ImplicitNamingStrategy` that prefixes with the embedded attribute name, or use Hibernate 6.6's `@EmbeddedColumnNaming` pattern; plain JPA offers only `@AttributeOverride`.

saying these in an interview costs you the question

  • Thinking @AttributeOverride's name attribute is the target column name
  • Putting the overrides on the nested @Embedded field instead of the outermost one
  • Using @AttributeOverride to rename a @ManyToOne join column inside an embeddable
  • Assuming the overridden @Column merges with the original and keeps nullable/length
  • Believing two identical embeddables in one entity 'just work' and last-one-wins

context