Reputation: 253
I have a parent class called FoodInfo
, and 3 more child classes called Ingredient
, Tag
and MiscellaneousData
. The relation between FoodInfo
and each of those classes is OneToOne
.
Currently, this is how I defined the classes:
FoodInfo:
@Entity
@Table(name="food")
public class FoodInfo {
@Id
@Column(name="code")
private Long code;
@OneToOne(mappedBy = "foodInfo", cascade = CascadeType.ALL)
private Tag tag;
@OneToOne(mappedBy = "foodInfo", cascade = CascadeType.ALL)
private Ingredient ingredient;
@OneToOne(mappedBy = "foodInfo", cascade = CascadeType.ALL)
private MiscellaneousData misc;
//And the getters and setters for all attributes including:
public Ingredient getIngredient() {
return ingredient;
}
public MiscellaneousData getMisc() {
return misc;
}
public String getProduct_name() {
return product_name;
}
public void setTag(Tag tag) {
this.tag = tag;
}
public void setIngredient(Ingredient ingredient) {
this.ingredient = ingredient;
}
public void setMisc(MiscellaneousData misc) {
this.misc = misc;
}
}
In Ingredient's class:
@Entity
@Table(name="ingredient")
public class Ingredient {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@JoinColumn(name = "code")
private FoodInfo foodInfo;
public FoodInfo getFoodInfo() {
return foodInfo;
}
public void setFoodInfo(FoodInfo foodInfo) {
this.foodInfo = foodInfo;
}
}
The other two child classes are the same as Ingredient
.
And finally, to Insert all the data I did like so:
FoodInfo food = new FoodInfo();
Ingredient ing = new Ingredient();
MiscellaneousData misc = new MiscellaneousData();
Tag tag = new Tag();
//And after setting all their attributes...
food.setTag(tag);
food.setMisc(misc);
food.setIngredient(ing);
tag.setFoodInfo(food);
misc.setFoodInfo(food);
ing.setFoodInfo(food);
foodRepository.save(food);
Now, when I try to run the program, an error says:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource
[org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]:
Invocation of init method failed; nested exception is org.hibernate.AnnotationException: Referenced property not a (One|Many)ToOne: com.guillermo.off.model.Ingredient.foodInfo in mappedBy of com.guillermo.off.model.FoodInfo.ingredient
............
Caused by: org.hibernate.AnnotationException: Referenced property not a (One|Many)ToOne: com.guillermo.off.model.Ingredient.foodInfo in mappedBy of com.guillermo.off.model.FoodInfo.ingredient
In previous attempts, using annotations in a different way I managed to insert the data in the database, but when I tried to fetch all this data, the program got into an endless loop.
Any help will be very appreciated! Thanks in advance!!
EDIT:
After doing what @Hülya suggested, the information in the database seems to be right:
But when requesting the info, I ran into what looks an inifinite loop.
My code for requesting the data is:
@GetMapping("/food")
public List<FoodInfo> findFood(HttpServletResponse response) {
List<FoodInfo> food = foodService.findAll();
return food;
}
...and in the console, I can only see the folloging a thousand times:
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.11.4.jar:2.11.4] at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:755) ~[jackson-databind-2.11.4.jar:2.11.4]
Upvotes: 1
Views: 1031
Reputation: 3433
@OneToOne
annotation should be used on both parent and child side to create a bidirectional one-to-one mapping.
As the error says: Referenced property not a (One|Many)ToOne
There is no mapping on the Ingredient
side.
You should specify the entity association for foodInfo
field with @OneToOne
:
@Entity
@Table(name="ingredient")
public class Ingredient {
// ...
@OneToOne
@JoinColumn(name = "code")
private FoodInfo foodInfo;
}
Update for com.fasterxml.jackson.databind
exception:
When serializing bidirectional relationships with jackson, cyclic dependency leads to an endless loop. To break the cycle you should add @JsonManagedReference
and @JsonBackReference
annotations:
FoodInfo class:
@Entity
@Table(name="food")
public class FoodInfo {
// ...
@OneToOne(mappedBy = "foodInfo", cascade = CascadeType.ALL)
@JsonManagedReference
private Ingredient ingredient;
}
Ingredient class:
@Entity
@Table(name="ingredient")
public class Ingredient {
//...
@OneToOne
@JoinColumn(name = "code")
@JsonBackReference
private FoodInfo foodInfo;
}
Upvotes: 2