[Risolto] org.hibernate.AnnotationException: Nessun identificatore specificato per la classe entità

Recentemente stavo lavorando su un progetto di hibernate e ho aggiunto alcuni entity bean, quando eseguito ho ottenuto la seguente traccia dell’eccezione.

Initial SessionFactory creation failed.org.hibernate.AnnotationException: No identifier specified for entity: com.journaldev.hibernate.model.Address
org.hibernate.AnnotationException: No identifier specified for entity: com.journaldev.hibernate.model.Address
	at org.hibernate.cfg.InheritanceState.determineDefaultAccessType(InheritanceState.java:277)
	at org.hibernate.cfg.InheritanceState.getElementsToProcess(InheritanceState.java:224)
	at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:775)
	at org.hibernate.cfg.Configuration$MetadataSourceQueue.processAnnotatedClassesQueue(Configuration.java:3788)
	at org.hibernate.cfg.Configuration$MetadataSourceQueue.processMetadata(Configuration.java:3742)
	at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1410)
	at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1844)
	at com.journaldev.hibernate.util.HibernateUtil.buildSessionFactory(HibernateUtil.java:22)
	at com.journaldev.hibernate.util.HibernateUtil.getSessionFactory(HibernateUtil.java:34)
	at com.journaldev.hibernate.main.HibernateExample.main(HibernateExample.java:15)
Exception in thread "main" java.lang.ExceptionInInitializerError
	at com.journaldev.hibernate.util.HibernateUtil.buildSessionFactory(HibernateUtil.java:29)
	at com.journaldev.hibernate.util.HibernateUtil.getSessionFactory(HibernateUtil.java:34)
	at com.journaldev.hibernate.main.HibernateExample.main(HibernateExample.java:15)

Il problema stava arrivando perché ho dimenticato di specificare la chiave primaria nel mio bean Entity, il mio bean era definito come; Address.java

package com.journaldev.hibernate.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;

@Entity
@Table(name = "ADDRESS")
@Access(value=AccessType.FIELD)
public class Address {

	@Column(name = "emp_id", unique = true, nullable = false)
	@GeneratedValue(generator = "gen")
	@GenericGenerator(name = "gen", strategy = "foreign", parameters = { @Parameter(name = "property", value = "employee") })
	private long id;

	@Column(name = "address_line1")
	private String addressLine1;

	@Column(name = "zipcode")
	private String zipcode;

	@Column(name = "city")
	private String city;

	@OneToOne
	@PrimaryKeyJoinColumn
	private Employee employee;

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getAddressLine1() {
		return addressLine1;
	}

	public void setAddressLine1(String addressLine1) {
		this.addressLine1 = addressLine1;
	}

	public String getZipcode() {
		return zipcode;
	}

	public void setZipcode(String zipcode) {
		this.zipcode = zipcode;
	}

	public String getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}

	public Employee getEmployee() {
		return employee;
	}

	public void setEmployee(Employee employee) {
		this.employee = employee;
	}

	@Override
	public String toString() {
		return "AddressLine1= " + addressLine1 + ", City=" + city
				+ ", Zipcode=" + zipcode;
	}
}

Tutto ciò di cui avevo bisogno per risolvere il problema era annotare il campo chiave primaria con l’annotazione @Id. Ho modificato la dichiarazione del mio campo id come segue e il problema è stato risolto.

@Id
@Column(name = "emp_id", unique = true, nullable = false)
@GeneratedValue(generator = "gen")
@GenericGenerator(name = "gen", strategy = "foreign", parameters = { @Parameter(name = "property", value = "employee") })
private long id;

Si tratta di una soluzione semplice ma c’è uno scenario in cui diventa più confuso. Di solito hibernate determina automaticamente il modo di accedere alle proprietà del bean in base alle annotazioni utilizzate sulla variabile o sul getter-setter. Tuttavia, possiamo definire esplicitamente il tipo di accesso per i nostri entity bean. Ci sono due tipi di accesso:

  1. Field: Hibernate cercherà le annotazioni sulle variabili in questo caso, come abbiamo definito per la classe Address sopra come @Access(value=AccessType.FIELD).
  2. Property: Hibernate cercherà le annotazioni sui metodi getter-setter in questo caso, la sintassi per questo è @Access(value=AccessType.PROPERTY)

Se le annotazioni non sono definite secondo il tipo di accesso, otterremo comunque questa eccezione. Ad esempio, se il tipo di accesso è property e abbiamo aggiunto tutte le annotazioni sulle variabili del bean, otterremo questa eccezione. Una classe di esempio che genererà questa eccezione è data di seguito. Employee.java

package com.journaldev.hibernate.model;

import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;

import org.hibernate.annotations.Cascade;

@Entity
@Table(name = "EMPLOYEE")
@Access(value=AccessType.FIELD)
public class Employee {

	private long id;

	private String name;

	private double salary;

	private Address address;

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "emp_id")
	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	@OneToOne(mappedBy = "employee")
	@Cascade(value = org.hibernate.annotations.CascadeType.ALL)
	public Address getAddress() {
		return address;
	}

	public void setAddress(Address address) {
		this.address = address;
	}

	@Column(name = "emp_name")
	public String getName() {
		System.out.println("Employee getName called");
		return name;
	}

	public void setName(String name) {
		System.out.println("Employee setName called");
		this.name = name;
	}

	@Column(name = "emp_salary")
	public double getSalary() {
		return salary;
	}

	public void setSalary(double salary) {
		this.salary = salary;
	}

	@Override
	public String toString() {
		return "Id= " + id + ", Name= " + name + ", Salary= " + salary
				+ ", {Address= " + address + "}";
	}

}

Nota che tutte le annotazioni JPA sono utilizzate con i metodi getter mentre il tipo di accesso è definito come Field, basta cambiare il tipo di accesso a property per risolvere questo problema.

Source:
https://www.digitalocean.com/community/tutorials/solved-org-hibernate-annotationexception-no-identifier-specified-for-entity-class