Persistence top

Get started with Spring Data JPA through the reference Learn Spring Data JPA course:

>> CHECK OUT THE COURSE

1. Overview

In this tutorial, we'll show how to use @AttributeOverride to change a column mapping. We'll explain how to use it when extending or embedding an entity, and we'll cover single and collection embedding.

2. @AttributeOverride‘s Attributes

The annotation contains two mandatory attributes:

  • name – field name of an included entity
  • column – column definition which overrides the one defined in the original object

3. Use With @MappedSuperclass

Let's define a Vehicle class:

@MappedSuperclass
public class Vehicle {
    @Id
    @GeneratedValue
    private Integer id;
    private String identifier;
    private Integer numberOfWheels;
    
    // standard getters and setters
}

The @MappedSuperclass annotation indicates that it's a base class for other entities.

Let's next define class Car, which extends Vehicle. It demonstrates how to extend an entity and store a car's information in a single table. Note that the annotation goes on the class:

@Entity
@AttributeOverride(name = "identifier", column = @Column(name = "VIN"))
public class Car extends Vehicle {
    private String model;
    private String name;

    // standard getters and setters
}

As a result, we have one table with all car details together with vehicle details. The thing is that for a car, we want to store an identifier in column VIN. We achieve it with @AttributeOverride. The annotation defines that field identifier is stored in the VIN column. 

4. Use With an Embedded Class

Let's now add more details to our vehicle with two embeddable classes.

Let's first define basic address information:

@Embeddable
public class Address {
    private String name;
    private String city;

    // standard getters and setters
}

Let's also create a class with car manufacturer information:

@Embeddable
public class Brand {
    private String name;
    private LocalDate foundationDate;
    @Embedded
    private Address address;

    // standard getters and setters
}

The Brand class contains an embedded class with address details. We'll use it to demonstrate how to use @AttributeOverride with multiple levels of embedding.

Let's extend our Car with Brand details:

@Entity
@AttributeOverride(name = "identifier", column = @Column(name = "VIN"))
public class Car extends Vehicle {
    // existing fields

    @Embedded
    @AttributeOverrides({
      @AttributeOverride(name = "name", column = @Column(name = "BRAND_NAME", length = 5)),
      @AttributeOverride(name = "address.name", column = @Column(name = "ADDRESS_NAME"))
    })
    private Brand brand;

    // standard getters and setters
}

First of all, the @AttributeOverrides annotation allows us to modify more than one attribute. We've overridden the name column definition from the Brand class because the same column exists in the Car class. As a result, the brand name is stored in column BRAND_NAME.

Furthermore, we've defined column length to show that not only a column name can be overridden. Note that the column attribute overrides all values from the overridden class. To keep original values, all must be set in column attributes.

In addition to that, the name column from the Address class has been mapped to ADDRESS_NAME. To override mappings at multiple levels of embedding, we use a dot “.” to specify a path to the overridden field.

5. Embedded Collection

Let's play a little bit with this annotation and see how it works with a collection.

Let's add a car's owner details:

@Embeddable
public class Owner {
    private String name;
    private String surname;

    // standard getters and setters
}

We want to have an owner together with an address, so let's add a map of owners and their addresses:

@Entity
@AttributeOverride(name = "identifier", column = @Column(name = "VIN"))
public class Car extends Vehicle {
    // existing fields

    @ElementCollection
    @AttributeOverrides({
      @AttributeOverride(name = "key.name", column = @Column(name = "OWNER_NAME")),
      @AttributeOverride(name = "key.surname", column = @Column(name = "OWNER_SURNAME")),
      @AttributeOverride(name = "value.name", column = @Column(name = "ADDRESS_NAME")),
    })
    Map<Owner, Address> owners;

    // standard getters and setters
}

Thanks to the annotation, we can reuse the Address class. The key prefix indicates an override of a field from the Owner class. Furthermore, a value prefix points to the field from the Address class. For lists, no addition prefix is required.

6. Conclusion

That concludes this short article about the @AttibuteOverride annotation. We've seen how to use this annotation when extending or embedding an entity. After that, we've learned how to use it with a collection.

As always, the source code of the example is available over on GitHub.

Persistence bottom
Get started with Spring Data JPA through the reference Learn Spring Data JPA course: >> CHECK OUT THE COURSE
guest
0 Comments
Inline Feedbacks
View all comments