| I think it was a false alarm – I had annotated the fields incorrectly. Changing the annotation as follows will make it work as expected:
package org.hibernate.bugreport.jointable.constraintviolation.entity;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
import java.util.Objects;
@Entity
public class Component {
@Id
@GeneratedValue(generator = "UUID")
@GenericGenerator(
name = "UUID",
strategy = "org.hibernate.id.UUIDGenerator"
)
private String id;
private String name;
@ManyToOne(cascade = CascadeType.ALL)
@JoinTable(
name = "laptop_components",
joinColumns = @JoinColumn(
name = "component_id",
referencedColumnName = "id"
),
inverseJoinColumns = @JoinColumn(
name = "laptop_id",
referencedColumnName = "id"
)
)
private Laptop laptop;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Laptop getLaptop() {
return laptop;
}
public void setLaptop(Laptop laptop) {
this.laptop = laptop;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Component component = (Component) o;
return Objects.equals(id, component.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
package org.hibernate.bugreport.jointable.constraintviolation.entity;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
@Entity
public class Laptop {
@Id
@GeneratedValue(generator = "UUID")
@GenericGenerator(
name = "UUID",
strategy = "org.hibernate.id.UUIDGenerator"
)
private String id;
private String brand;
private String series;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "laptop")
private Set<Component> components = new HashSet<>();
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getSeries() {
return series;
}
public void setSeries(String series) {
this.series = series;
}
public Set<Component> getComponents() {
return components;
}
public void setComponents(Set<Component> components) {
this.components = components;
}
public void addComponent(Component component) {
getComponents().add(component);
component.setLaptop(this);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Laptop laptop = (Laptop) o;
return Objects.equals(id, laptop.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
However, Hibernate detects some classes of invalid annotations on startup. For example, if I have a field definition like this:
@OneToMany(cascade = CascadeType.ALL, mappedBy = "laptop")
@JoinTable(
name = "laptop_components",
joinColumns = @JoinColumn(
name = "laptop_id",
referencedColumnName = "id"
),
inverseJoinColumns = @JoinColumn(
name = "component_id",
referencedColumnName = "id"
)
)
private Set<Component> components = new HashSet<>();
Hibernate throws an exception on startup letting the user know that there’s something wrong with his entity definitions:
org.hibernate.AnnotationException: Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn: org.hibernate.bugreport.jointable.constraintviolation.entity.Laptop.components
It would be nice if Hibernate could warn users when they accidentally place the JoinTable annotation on fields of the joined classes, instead of behaving unexpectedly at runtime. Maybe we can turn this ticket into a feature request to do just that? |