Spring HATEOAS/Jackson 带资源和资源组装器
Spring HATEOAS/Jackson with resources and resource assembler
由于我的两个 JPA 实体(任务和作业)的双向关系中存在嵌套循环,我收到了 Jackson 错误。我开始研究并部分设法使用 @JsonManagedReference 和 @JsonBackReference 注释解决了这个问题,但这种方法只有在我使用我的实体中的注释时才有效,它以 JSON 序列化跳过我的 JobResource/JobResourceAssembler 结束和 TaskResource/TaskResourceAssembler,得到 HATEOASless 和 HALless json 响应。
有没有办法让这个 serialization/deserialization 由我的资源管理?
一些代码(通过这种方式我得到了 json 响应,但交换了 HATEOASless 和 HALLless):
@Entity
public class Task {
@Id
@GeneratedValue
private Long id;
@OneToMany(mappedBy="task")
@JsonManagedReference
private List<Job> job = new ArrayList<Job>();
//constructors, getter, setter...
@Entity
public class Job {
@Id
@GeneratedValue
private Long id;
@ManyToOne
@JsonBackReference
@JoinColumn(name = "task_id", updatable = true, insertable = true, nullable = true)
private Task task;
//constructor, setter, getter.
HATEOAS 无响应(职位应该有链接)
{
"_embedded": {
"tasks": [
{
"name": "Task",
"description": "Task Description",
"createdAt": 1467583658749,
"updatedAt": null,
"deletedAt": null,
"isActive": true,
"estimatedStartDate": null,
"startDate": null,
"estimatedDateEnd": null,
"dateEnd": null,
"ids": 1,
"risk": null,
"job": [
{
"id": 2,
"name": "Job",
"description": "Job Description",
"createdAt": 1467583673859,
"updatedAt": null,
"deletedAt": null,
"isActive": true
},
{
"id": 3,
"name": "Job2",
"description": "Job Description",
"createdAt": 1467583676138,
"updatedAt": null,
"deletedAt": null,
"isActive": true
},
{
"id": 4,
"name": "Job3",
"description": "Job Description",
"createdAt": 1467583679339,
"updatedAt": null,
"deletedAt": null,
"isActive": true
}
],
"_links": {
"self": {
"href": "http://127.0.0.3:7890/api/v1/tasks/1"
},
"task": {
"href": "http://127.0.0.3:7890/api/v1/tasks/1"
}
}
}
]
我和同事一起解决了这个问题。首先:问题在于杰克逊直接序列化我们的相关实体,忽略了 spring HATEOAS 的资源。这是因为我们的资源是由对象列表而不是资源列表提供的,所以我们改变了:
@Relation(collectionRelation = "tasks")
public class TaskResource extends ResourceSupport {
private List<JobResource> job = new ArrayList<JobResource>();
现在,由于我的资源列表是由资源而不是常规实体提供的,我们制作了一个可以用常规作业填充列表作业的服务。由于一个实体有自己的资源,基本相同,因此开发过程相当快:
public List<JobResource> findJobsFromTask(Long id) {
Task task = taskRepository.findOne(id);
List<Job> jobs = task.getJob();
List<JobResource> jobResourceList = new ArrayList<JobResource>();
for (Job job : jobs) {
jobResourceList.add(new JobResourceAssembler().toResource(job));
}
return jobResourceList;
}
有了这个,我们只需要修复汇编器就可以添加新的 JobResource:
@Override
public TaskResource toResource(Task task) {
taskResource.setJob(taskService.findJobsFromTask(task.getId()));
}
这就是我们的解决方案。如果有更好的,欢迎留言或其他答案一起讨论。
编辑:当嵌套资源超过 3 个时,可能需要手动将所有内容添加到资源中。让我们今天有 3 个资源:项目 -> 任务 -> 工作。如果我们采用之前的方法,那么它将以嵌套的 null 错误结束。服务:
@Override
public List<TaskResource> findTaskFromProject(Long id) {
Project project = projectRepository.findOne(id);
List<Task> tasks = project.getTask();
List<TaskResource> taskResourceList = new ArrayList<TaskResource>();
for (Task task : tasks) {
TaskResource taskResource = new TaskResource();
taskResource.setName(task.getName());
taskResource.setDescription(task.getDescription());
taskResource.setCreatedAt(task.getCreatedAt());
taskResource.setUpdatedAt(task.getUpdatedAt());
taskResource.setDeletedAt(task.getDeletedAt());
taskResource.setIsActive(task.getIsActive());
taskResource.setRisk(task.getRisk());
//taskResource.setDocumentState(task.getDocumentState());
taskResource.setEstimatedStartDate(task.getEstimatedStartDate());
taskResource.setStartDate(task.getStartDate());
taskResource.setEstimatedDateEnd(task.getEstimatedDateEnd());
taskResource.setDateEnd(task.getDateEnd());
taskResource.setIds(task.getId());
taskResource.setJob(taskService.findJobsFromTask(task.getId()));
taskResource.add(linkTo(TaskController.class).slash("").slash(task.getId()).withSelfRel());
taskResource.add(linkTo(TaskController.class).slash("").slash(task.getId()).withRel("task"));
taskResourceList.add(taskResource);
}
return taskResourceList;
}
有了这个,我们得到了一个项目 -> 任务 -> 工作 JSON 响应 full hateoas /hal.
由于我的两个 JPA 实体(任务和作业)的双向关系中存在嵌套循环,我收到了 Jackson 错误。我开始研究并部分设法使用 @JsonManagedReference 和 @JsonBackReference 注释解决了这个问题,但这种方法只有在我使用我的实体中的注释时才有效,它以 JSON 序列化跳过我的 JobResource/JobResourceAssembler 结束和 TaskResource/TaskResourceAssembler,得到 HATEOASless 和 HALless json 响应。
有没有办法让这个 serialization/deserialization 由我的资源管理?
一些代码(通过这种方式我得到了 json 响应,但交换了 HATEOASless 和 HALLless):
@Entity
public class Task {
@Id
@GeneratedValue
private Long id;
@OneToMany(mappedBy="task")
@JsonManagedReference
private List<Job> job = new ArrayList<Job>();
//constructors, getter, setter...
@Entity
public class Job {
@Id
@GeneratedValue
private Long id;
@ManyToOne
@JsonBackReference
@JoinColumn(name = "task_id", updatable = true, insertable = true, nullable = true)
private Task task;
//constructor, setter, getter.
HATEOAS 无响应(职位应该有链接)
{
"_embedded": {
"tasks": [
{
"name": "Task",
"description": "Task Description",
"createdAt": 1467583658749,
"updatedAt": null,
"deletedAt": null,
"isActive": true,
"estimatedStartDate": null,
"startDate": null,
"estimatedDateEnd": null,
"dateEnd": null,
"ids": 1,
"risk": null,
"job": [
{
"id": 2,
"name": "Job",
"description": "Job Description",
"createdAt": 1467583673859,
"updatedAt": null,
"deletedAt": null,
"isActive": true
},
{
"id": 3,
"name": "Job2",
"description": "Job Description",
"createdAt": 1467583676138,
"updatedAt": null,
"deletedAt": null,
"isActive": true
},
{
"id": 4,
"name": "Job3",
"description": "Job Description",
"createdAt": 1467583679339,
"updatedAt": null,
"deletedAt": null,
"isActive": true
}
],
"_links": {
"self": {
"href": "http://127.0.0.3:7890/api/v1/tasks/1"
},
"task": {
"href": "http://127.0.0.3:7890/api/v1/tasks/1"
}
}
}
]
我和同事一起解决了这个问题。首先:问题在于杰克逊直接序列化我们的相关实体,忽略了 spring HATEOAS 的资源。这是因为我们的资源是由对象列表而不是资源列表提供的,所以我们改变了:
@Relation(collectionRelation = "tasks")
public class TaskResource extends ResourceSupport {
private List<JobResource> job = new ArrayList<JobResource>();
现在,由于我的资源列表是由资源而不是常规实体提供的,我们制作了一个可以用常规作业填充列表作业的服务。由于一个实体有自己的资源,基本相同,因此开发过程相当快:
public List<JobResource> findJobsFromTask(Long id) {
Task task = taskRepository.findOne(id);
List<Job> jobs = task.getJob();
List<JobResource> jobResourceList = new ArrayList<JobResource>();
for (Job job : jobs) {
jobResourceList.add(new JobResourceAssembler().toResource(job));
}
return jobResourceList;
}
有了这个,我们只需要修复汇编器就可以添加新的 JobResource:
@Override
public TaskResource toResource(Task task) {
taskResource.setJob(taskService.findJobsFromTask(task.getId()));
}
这就是我们的解决方案。如果有更好的,欢迎留言或其他答案一起讨论。
编辑:当嵌套资源超过 3 个时,可能需要手动将所有内容添加到资源中。让我们今天有 3 个资源:项目 -> 任务 -> 工作。如果我们采用之前的方法,那么它将以嵌套的 null 错误结束。服务:
@Override
public List<TaskResource> findTaskFromProject(Long id) {
Project project = projectRepository.findOne(id);
List<Task> tasks = project.getTask();
List<TaskResource> taskResourceList = new ArrayList<TaskResource>();
for (Task task : tasks) {
TaskResource taskResource = new TaskResource();
taskResource.setName(task.getName());
taskResource.setDescription(task.getDescription());
taskResource.setCreatedAt(task.getCreatedAt());
taskResource.setUpdatedAt(task.getUpdatedAt());
taskResource.setDeletedAt(task.getDeletedAt());
taskResource.setIsActive(task.getIsActive());
taskResource.setRisk(task.getRisk());
//taskResource.setDocumentState(task.getDocumentState());
taskResource.setEstimatedStartDate(task.getEstimatedStartDate());
taskResource.setStartDate(task.getStartDate());
taskResource.setEstimatedDateEnd(task.getEstimatedDateEnd());
taskResource.setDateEnd(task.getDateEnd());
taskResource.setIds(task.getId());
taskResource.setJob(taskService.findJobsFromTask(task.getId()));
taskResource.add(linkTo(TaskController.class).slash("").slash(task.getId()).withSelfRel());
taskResource.add(linkTo(TaskController.class).slash("").slash(task.getId()).withRel("task"));
taskResourceList.add(taskResource);
}
return taskResourceList;
}
有了这个,我们得到了一个项目 -> 任务 -> 工作 JSON 响应 full hateoas /hal.