[해결됨] org.hibernate.AnnotationException: 엔티티 클래스에 지정된 식별자가 없습니다.
최근에 나는 최대 절전 모드 프로젝트에서 작업 중이었고 엔터티 bean을 거의 추가하지 않았습니다. 실행될 때 예외 스택 추적 아래에 도달했습니다.
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)
내 Entity bean에서 기본 키를 지정하는 것을 잊었기 때문에 문제가 발생했습니다. 내 bean은 다음과 같이 정의되었습니다. 주소.자바
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;
}
}
이 문제를 해결하는 데 필요한 것은 기본 키 필드에 @Id
주석을 추가하는 것뿐이었습니다. 내 ID 필드 선언을 아래로 변경하고 문제가 해결되었습니다.
@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;
이것은 쉬운 수정이지만 더 혼란스러워지는 한 가지 시나리오가 있습니다. 일반적으로 최대 절전 모드는 변수 또는 getter-setter에 사용된 주석을 기반으로 빈 속성에 액세스하는 방법을 자동으로 파악합니다. 그러나 엔티티 bean에 대한 액세스 유형을 명시적으로 정의할 수 있습니다. 액세스 유형에는 두 가지 유형이 있습니다.
- Field: Hibernate는 위의 Address 클래스에 대해
@Access(value=AccessType.FIELD)
로 정의한 것처럼 이 경우 변수에 대한 주석을 찾습니다. - 속성: Hibernate는 이 경우 getter-setter 메서드에 대한 주석을 찾을 것입니다. 이에 대한 구문은
@Access(value=AccessType.PROPERTY)
입니다.\n
주석이 액세스 유형별로 정의되지 않은 경우에도 이 예외가 발생합니다. 예를 들어 액세스 유형이 속성이고 빈 변수에 모든 주석을 추가한 경우 이 예외가 발생합니다. 이 예외를 발생시키는 샘플 클래스는 다음과 같습니다. 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 + "}";
}
}
모든 JPA 주석은 getter 메서드와 함께 사용되는 반면 액세스 유형은 필드로 정의됩니다. 이 문제를 해결하려면 액세스 유형을 속성으로 변경하기만 하면 됩니다.