Reputation: 167
To explain the problem I'm dealing with I will first provide the code.
@RequestMapping(path = "/addrecipe")
public void addNewRecipe(@RequestBody AddRecipeDto addRecipeDto){
Recipe newRecipe = new Recipe();
EvaUser user = evaUserRepository.findOne(addRecipeDto.getUserId());
for(Ingredient ingredient: addRecipeDto.getIngredients()){
ingredientRepository.save(ingredient);
}
newRecipe.setTitle(addRecipeDto.getTitle());
newRecipe.setAuthor(user);
newRecipe.setDescription(addRecipeDto.getDescription());
newRecipe.setIngredients(addRecipeDto.getIngredients());
recipeRepository.save(newRecipe);
user.getMyRecipes().add(newRecipe);
evaUserRepository.save(user);
}
@RequestMapping("/getusers")
public Iterable<EvaUser> getAllUsers() {
return evaUserRepository.findAll();
}
@OneToMany
private List<Recipe> myRecipes;
@ManyToMany
private List<Recipe> favoriteRecipes;
@ManyToOne
private EvaUser author;
Failed to write HTTP message:
org.springframework.http.converter.HttpMessageNotWritableException: Could
not write content: Infinite recursion
So when I call the method to add a recipe, I want the database to know that there is a new recipe and that the new recipe is linked to the user who added it. When I drop the part where I save the user-entity, the mapping isn't made at all. But when I use the userRepository to tell the database that there has been made a change (adding the recipe to their list) it seems like there is an infinite loop of adding new users.
Upvotes: 1
Views: 1306
Reputation: 7117
Answering to your question and including the last requirements from your comments.
If you want to break the loop, but some somehow want to keep also nested objects, I would recommend to write a custom serializer and replace the the object which causes the endless recursion with some other field (I used author username which is String
instead of Author
object in the example below).
To reproduce the case I created a mock model which is similar to yours.
Recipe:
public class Recipe {
private EvaUser author;
private String name = "test";
private String ingridients = "carrots, tomatos";
public EvaUser getAuthor() {
return author;
}
public void setAuthor(EvaUser author) {
this.author = author;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getIngridients() {
return ingridients;
}
public void setIngridients(String ingridients) {
this.ingridients = ingridients;
}
}
EvaUser:
public class EvaUser {
private List<Recipe> myRecipes = new ArrayList<>();
private List<Recipe> favoriteRecipes = new ArrayList<>();
private String username;
public List<Recipe> getMyRecipes() {
return myRecipes;
}
public void setMyRecipes(List<Recipe> myRecipes) {
this.myRecipes = myRecipes;
}
public List<Recipe> getFavoriteRecipes() {
return favoriteRecipes;
}
public void setFavoriteRecipes(List<Recipe> favoriteRecipes) {
this.favoriteRecipes = favoriteRecipes;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
Creating a custom serializer:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import java.io.IOException;
import java.util.Optional;
public class RecipeSerializer extends StdSerializer<Recipe> {
protected RecipeSerializer() {
this(null);
}
protected RecipeSerializer(Class<Recipe> t) {
super(t);
}
@Override
public void serialize(Recipe recipe, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeStartObject();
gen.writeStringField("name", recipe.getName());
gen.writeStringField("author", Optional.ofNullable(recipe.getAuthor().getUsername()).orElse("null"));
gen.writeStringField("ingridients", recipe.getIngridients());
gen.writeEndObject();
}
}
Applying serializer:
@JsonSerialize(using = RecipeSerializer.class)
public class Recipe {
// model entity
}
JSON response body of EvaUser
from controller (previous one was StackOverflowError
):
{
"myRecipes": [
{
"name": "soup",
"author": "user1",
"ingridients": "carrots, tomatos"
},
{
"name": "steak",
"author": "user1",
"ingridients": "meat, salt"
}
],
"favoriteRecipes": [
{
"name": "soup",
"author": "user1",
"ingridients": "carrots, tomatos"
},
{
"name": "steak",
"author": "user1",
"ingridients": "meat, salt"
}
],
"username": "user1"
}
Upvotes: 1