简体   繁体   English

具有资源和资源汇编器的Spring HATEOAS / Jackson

[英]Spring HATEOAS/Jackson with resources and resource assembler

I got a Jackson error because of a nested loop in a bidirectional relationship of two of my JPA entities (Task and Job). 由于两个JPA实体(任务和作业)的双向关系中存在嵌套循环,因此出现了杰克逊错误。 I started researching and partially managed to solve this using the @JsonManagedReference and @JsonBackReference annotations, but this method only works when I use the annotations within my entities, which ends with the JSON serialization jumping over my JobResource/JobResourceAssembler and TaskResource/TaskResourceAssembler, getting a HATEOASless and HALless json response. 我开始研究并使用@JsonManagedReference和@JsonBackReference批注来部分解决此问题,但是该方法仅在我在实体中使用批注时才有效,最后以JSON序列化跳过了JobResource / JobResourceAssembler和TaskResource / TaskResourceAssembler, HATEOASless和HALless json响应。

Is there a way to get this serialization/deserialization being managed by my resources? 有没有办法让我的资源管理此序列化/反序列化?

Some code (this way I got a json response but at exchange of being HATEOASless and HALless): 一些代码(通过这种方式,我得到了json响应,但是交换了HATEOASless和HALless):

@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.

HATEOASless response (jobs should have links) HATEOASless响应(工作应具有链接)

{
"_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"
      }
    }
  }
]

I solved this with my coworker. 我和我的同事解决了这个问题。 First: the problem was that jackson was serializing our related entities directly, ignoring spring HATEOAS' resources. 首先:问题是杰克逊忽略了弹簧HATEOAS的资源而直接序列化我们的相关实体。 This was caused because our resources were being feeded by object list, no resources list, so we changed that: 这是由于我们的资源是由对象列表而不是资源列表提供的,因此我们将其更改为:

@Relation(collectionRelation = "tasks")
public class TaskResource extends ResourceSupport {

    private List<JobResource> job = new ArrayList<JobResource>();

Now, with my resource list being feeded by a resource and not a regular entity, we made a service which could fill the List job with regular jobs. 现在,在我的资源列表由资源而非常规实体提供的情况下,我们提供了一项服务,可以用常规作业填充List作业。 Being the case that a entity has its own resource which is basically the same, the process was fairly fast to develop: 假设一个实体拥有自己的资源,而这些资源基本上是相同的,则开发过程相当快:

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;
}

Having this, we just needed to fix the assembler so it will add the new JobResource: 有了这个,我们只需要修复汇编器,以便它将添加新的JobResource:

@Override
public TaskResource toResource(Task task) {
    taskResource.setJob(taskService.findJobsFromTask(task.getId()));
}

And this was our solution. 这就是我们的解决方案。 If there's a better one, please leave comment or another answer to discuss it. 如果有更好的选择,请发表评论或其他答案进行讨论。

Edit: it may be necessary to manually add everything to the resource when there're 3+ nested resources. 编辑:当有3个以上的嵌套资源时,可能有必要手动将所有内容添加到资源中。 Let's day we have 3 resources: project -> task -> job. 我们拥有3种资源:项目->任务->工作。 If we did the previous approach, then it will end with a nested null error. 如果我们采用了前面的方法,那么它将以嵌套的null错误结束。 The service: 服务:

@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;
}

With this, we obtained a project -> task -> job JSON response full hateoas /hal. 这样,我们获得了一个项目->任务->作业JSON响应full hateoas / hal。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM