@AttributeOverride and @AttributeOverrides example - Walking Techie

Blog about Java programming, Design Pattern, and Data Structure.

Wednesday, June 3, 2020

@AttributeOverride and @AttributeOverrides example

@AttributeOverride annotation

Used to override the mapping of a Basic (whether explicit or default) property or field or Id property or field.

May be applied to an entity that extends a mapped superclass or to an embedded field or property to override a basic mapping or id mapping defined by the mapped superclass or embeddable class (or embeddable class of one of its attributes).

May be applied to an element collection containing instances of an embeddable class or to a map collection whose key and/or value is an embeddable class. When AttributeOverride is applied to a map, "key." or "value." must be used to prefix the name of the attribute that is being overridden in order to specify it as part of the map key or map value.

To override mappings at multiple levels of embedding, a dot (".") notation form must be used in the name element to indicate an attribute within an embedded attribute. The value of each identifier used with the dot notation is the name of the respective embedded field or property. If AttributeOverride is not specified, the column is mapped the same as in the original mapping.

@AttributeOverrides annotation

Used to override mappings of multiple properties or fields.

Understand using example

We strongly recommend to read these article before moving ahead, component mapping in hibernate using JPA annotation, this post, and how mapping of column happens when mapping file and @Column annotation is not used..

If we want to change the column names of component address to something like "address_street", "address_city", and "address_zipcode" as table below.

Custom column names of address component

We can do the same by using the name attribute of @Column annotation.

package com.walking.techie.entity;

import javax.persistence.Column;
import javax.persistence.Embeddable;

@Embeddable
public class Address {

  @Column(name = "address_street")
  private String street;
  @Column(name = "address_city")
  private String city;
  @Column(name = "address_zipcode")
  private String zipcode;

  public Address() {
  }

  public Address(String street, String city, String zipcode) {
    this.street = street;
    this.city = city;
    this.zipcode = zipcode;
  }
}

But sometimes, We need to override the settings of component class into the particular entity class. For example, Here by default attributes of address component class will be mapped to street, city, and zipcode columns. But, if you wanted to map these columns with some other name for this "Person" entity. You can do it using @AttributeOverride annotation.

package com.walking.techie.entity;

import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Getter;
import lombok.Setter;

@Entity
@Table(name = "Person")
@Getter
@Setter
public class Person {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "id")
  private Long id;

  @Column(name = "name", nullable = false)
  private String name;

  @Embedded
  @AttributeOverrides({
      @AttributeOverride(name = "street", column = @Column(name = "address_street")),
      @AttributeOverride(name = "city", column = @Column(name = "address_city")),
      @AttributeOverride(name = "zipcode", column = @Column(name = "address_zipcode"))
  })
  private Address address;

  public Person() {
  }

  public Person(String name, Address address) {
    this.name = name;
    this.address = address;
  }
}

In "Person" entity, street attribute mapped to "address_street" column, city attribute mapped to "address_city" column, and zipcode attribute mapped to "address_zipcode" column.

package com.walking.techie.entity;

import javax.persistence.Embeddable;

@Embeddable
public class Address {

  private String street;
  private String city;
  private String zipcode;

  public Address() {
  }

  public Address(String street, String city, String zipcode) {
    this.street = street;
    this.city = city;
    this.zipcode = zipcode;
  }
}

When requirement comes like "Person" entity should have two address say "homeAddress" and "billingAddress". We can achieve the same using the @AttributeOverride annotation. The "Address" class is embeddable as above. So it is a value type.

The "Person" entity will be like below.

package com.walking.techie.entity;

import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Getter;
import lombok.Setter;

@Entity
@Table(name = "Person")
@Getter
@Setter
public class Person {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "id")
  private Long id;

  @Column(name = "name", nullable = false)
  private String name;

  @Embedded
  @AttributeOverrides({
      @AttributeOverride(name = "street", column = @Column(name = "home_street")),
      @AttributeOverride(name = "city", column = @Column(name = "home_city")),
      @AttributeOverride(name = "zipcode", column = @Column(name = "home_zipcode"))
  })
  private Address homeAddress;

  @Embedded
  @AttributeOverrides({
      @AttributeOverride(name = "street", column = @Column(name = "billing_street")),
      @AttributeOverride(name = "city", column = @Column(name = "billing_city")),
      @AttributeOverride(name = "zipcode", column = @Column(name = "billing_zipcode"))
  })
  private Address billingAddress;

  public Person() {
  }

  public Person(String name, Address homeAddress, Address billingAddress) {
    this.name = name;
    this.homeAddress = homeAddress;
    this.billingAddress = billingAddress;
  }
}

AttributeOverrideClient

package com.walking.techie;

import com.walking.techie.entity.Address;
import com.walking.techie.entity.Person;
import com.walking.techie.utils.HibernateUtil;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

public class AttributeOverrideClient {

  public static void main(String[] args) {
    // get session factory of an application
    SessionFactory sessionFactory = HibernateUtil.getSessionFactory();

    // Open a session
    Session session = sessionFactory.openSession();
    Transaction transaction = null;

    try {
      // Begin a unit of work and return the associated Transaction object.
      transaction = session.beginTransaction();

      Address homeAddress = new Address("6th cross, 6th main", "Bangalore", "560078");
      Address billingAddress = new Address("11th cross, 7th main", "New Delhi", "110005");
      Person person = new Person("Santosh", homeAddress, billingAddress);

      session.persist(person);

      // commit the transaction
      transaction.commit();
    } catch (Exception e) {
      if (transaction != null) {
        transaction.rollback();
        e.printStackTrace();
      }
    } finally {
      if (session != null) {
        // End the session by releasing the JDBC connection and cleaning up.
        session.close();
      }
    }
  }
}

After running the code. The data in "Person" table will be like below.

@AttributeOverride example table record

Please find the working code from git.

1 comment :