Absolvoval jsem svůj doposud nejlepší technický pohovor (ne, v Google přijímací pohovor rozhodně lepší nebyl). Nikdo nedělal ramena s asymptotickou složitostí apod. Ba právě naopak to bylo velmi inspirující. Kromě toho, že jsem pochytil takové drobnosti jako unixový příkaz tree, jsem se hlavně přiučil, jak psát lépe abstract entity v JPA. SoftWare Samuraj měl pochopitelně k mému kódu zvídavé otázky a podnětné připomínky, které mě přiměly se na kód znovu podívat a zamyslet se.

Měl jsem abstraktní entitu s abstraktním getterem a setterem pro primární klíč, ale bez samotné deklarace fieldu, protože v každé tabulce se sloupec jmenoval jinak.

import javax.persistence.MappedSuperclass;
@MappedSuperclass
public abstract class AbstractEntity<PK> {
public abstract PK getId();
public abstract void setId(PK id);
@Override
public int hashCode() {
if (getId() != null) {
return getId().hashCode();
}
return super.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
AbstractEntity<?> other = (AbstractEntity<?>) obj;
if (getId() == null || other.getId() == null) {
return false;
}
if (!getId().equals(other.getId())) {
return false;
}
return true;
}
}
import javax.persistence.*;
@Entity
public class User extends AbstractEntity<Long> {
@Id
@SequenceGenerator(name = "userSequence", sequenceName="SQ_USERS")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "userSequence")
@Column(name = "USR_ID")
private Long id;
@Column(name = "USR_NAME", nullable = false)
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public Long getId() {
return id;
}
@Override
public void setId(Long id) {
this.id = id;
}
}
view raw User.java hosted with ❤ by GitHub

Samotné mapování lze překrýt pomocí anotace AttributeOverride. Zbývá ještě dořešit to, že každá entita má vlastní databázovou sekvenci. Ovšem i to lze nastavit.

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import java.io.Serializable;
@MappedSuperclass
public abstract class AbstractEntity<PK extends Serializable> {
public static final String GENERATOR = "customSequence";
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = GENERATOR)
private PK id;
public PK getId() {
return id;
}
public void setId(PK id) {
this.id = id;
}
@Override
public int hashCode() {
if (getId() != null) {
return getId().hashCode();
}
return super.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
AbstractEntity<?> other = (AbstractEntity<?>) obj;
if (getId() == null || other.getId() == null) {
return false;
}
if (!getId().equals(other.getId())) {
return false;
}
return true;
}
}
import javax.persistence.*;
@Entity
@SequenceGenerator(name = AbstractEntity.GENERATOR, sequenceName="SQ_USERS")
@AttributeOverride(name="id", column=@Column(name = "USER_ID"))
public class User extends AbstractEntity<Long> {
@Column(name = "USR_NAME", nullable = false)
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
view raw User.java hosted with ❤ by GitHub

Řekněte sami, není to takhle hezčí?

Ještě doplním, že více AttributOverride je možné sdružit do AttributeOverrides. K překrytí asociací analogicky použijete AssociationOverride a AttributeOverrides.