如何使用数据类解决 Kotlin 中的"Could not write JSON: Infinite recursion (StackOverflowError)"?



我知道这个主题中有几篇文章,但我就是找不到一篇使用Kotlin数据类的文章。因此,我正在尝试使用SpringBoot在Kotlin中使用H2数据库创建一个REST API,我也在使用Postman。我的类的某些属性具有List类型。每次我试图在Postman中为这些列表添加一些值,然后尝试获得结果时,我都会得到以下错误:

在此处输入图像描述

我有三个班:

配方.kt:

@Entity
data class Recipe(
@Id
@SequenceGenerator(name = RECIPE_SEQUENCE, sequenceName = RECIPE_SEQUENCE, initialValue = 1, allocationSize = 1)
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long = 0,
val name: String,
var cookTime: String?,
var servings: String?,
var directions: String?,
@OneToMany(cascade = [CascadeType.ALL], mappedBy = "recipe")
@JsonManagedReference
var ingredient: List<Ingredient>?,
@ManyToMany
@JsonManagedReference
@JoinTable(
name = "recipe_category",
joinColumns = [JoinColumn(name = "recipe_id")],
inverseJoinColumns = [JoinColumn(name = "category_id")]
)
var category: List<Category>?,
@Enumerated(value = EnumType.STRING)
var difficulty: Difficulty?
) { companion object { const val RECIPE_SEQUENCE: String = "RECIPE_SEQUENCE" } }

分类.kt

@Entity
data class Category(
@Id
@SequenceGenerator(name = CATEGORY_SEQUENCE, sequenceName = CATEGORY_SEQUENCE, initialValue = 1, allocationSize = 1)
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0,
var name: String,
@ManyToMany(mappedBy = "category")
@JsonBackReference
var recipe: List<Recipe>?
) { companion object { const val CATEGORY_SEQUENCE: String = "CATEGORY_SEQUENCE" } }

入口.kt

@Entity
data class Ingredient(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0,
var description: String?,
var amount: BigDecimal?,
@ManyToOne
@JsonBackReference
var recipe: Recipe?,
var unitOfMeasure: String?
)

RecipeResponse.kt

data class RecipeResponse (var id:Long,
var name:String,
var cookTime:String?,
var servings:String?,
var directions:String?,
var ingredient:List<Ingredient>?,
var category: List<Category>?,
var difficulty: Difficulty?)

RecipeResource.kt

@RestController
@RequestMapping(value = [BASE_RECIPE_URL])
class RecipeResource(private val recipeManagementService: RecipeManagementService)
{
@GetMapping
fun findAll(): ResponseEntity<List<RecipeResponse>> = ResponseEntity.ok(this.recipeManagementService.findAll())

配方管理服务.kt

@Service
class RecipeManagementService (@Autowired private val recipeRepository: RecipeRepository,
private val addRecipeRequestTransformer: AddRecipeRequestTransformer) {
fun findAll(): List<RecipeResponse> = this.recipeRepository.findAll().map(Recipe::toRecipeResponse)

您可以按照@Akash的建议使用@JsonIgnore,但结果不会在响应json中包含类别字段。对于单个recipe对象,响应将类似于:

{"id":1,"name":"recipe"}

您可以使用@JsonManagedReference@JsonBackReference。通过这种方式,您将打破无限循环,但仍会生成category列表。

你的模型看起来像:

data class Recipe(
var id: Long = 0,
val name: String,
@JsonManagedReference
var category: List<Category>,
)
data class Category(
val id: Long = 0,
var name: String,
@JsonBackReference
var recipe: List<Recipe>
)

这将生成一个json:

{"id":1,"name":"recipe","category":[{"id":1,"name":"cat"}]}

您必须在@ManyToOne和@OneToMany字段的顶部添加@JsonIgnore。Spring将忽略那些返回该对象的字段。外汇。

@Entity
data class Ingredient(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0,
var description: String?,
var amount: BigDecimal?,
@ManyToOne
@JsonIgnore
var recipe: Recipe?, // This field will not be returned in JSON response.
var unitOfMeasure: String?
)

在这里,如果你想在你的回复中包括这个ManyToOne或OneToMany关系的一些字段,也要注意。您必须使用ObjectNode制定响应,然后返回它。

编辑:


ObjectMapper objectMapper = new ObjectMapper();
@RestController
public ResponseEntity<String> someFunction() throws Exception {
ObjectNode msg = objectMapper.createObjectNode();
msg.put("success", true);
msg.put("field1", object.getValue1());
msg.put("field2", object.getValue2());
return ResponseEntity.ok()
.header("Content-Type", "application/json")
.body(objectMapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(res));
}

这里的代码是用java编写的,你可以把它转换成Kotlin,我想它会是一样的。在这里,您可以编写自己的对象名称,例如component.getDescription((,而不是对象,并可以生成响应。

最新更新