具有资源和资源汇编器的Spring HATEOAS/Jackson [英] Spring HATEOAS/Jackson with resources and resource assembler

查看:69
本文介绍了具有资源和资源汇编器的Spring HATEOAS/Jackson的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于两个JPA实体(任务和作业)的双向关系中存在嵌套循环,因此出现了杰克逊错误.我开始研究并使用@JsonManagedReference和@JsonBackReference批注来部分解决此问题,但是该方法仅在我在实体中使用批注时有效,最后以JSON序列化跳过JobResource/JobResourceAssembler和TaskResource/TaskResourceAssembler, HATEOASless和HALless json响应.

I got a Jackson error because of a nested loop in a bidirectional relationship of two of my JPA entities (Task and Job). 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.

是否可以通过我的资源来管理此序列化/反序列化?

Is there a way to get this serialization/deserialization being managed by my resources?

一些代码(通过这种方式,我得到了一个json响应,但是交换了HATEOASless和HALless):

Some code (this way I got a json response but at exchange of being HATEOASless and 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.

没有HATEOAS响应(职位应该有链接)

HATEOASless response (jobs should have links)

{
"_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的资源而直接序列化我们的相关实体.这是由于我们的资源是由对象列表而不是资源列表提供的,因此我们将其更改为:

I solved this with my coworker. First: the problem was that jackson was serializing our related entities directly, ignoring spring HATEOAS' resources. 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>();

现在,由于我的资源列表是由资源而不是常规实体提供的,因此我们提供了一项服务,可以用常规作业填充List作业.如果一个实体拥有自己的资源,而这些资源基本上是相同的,则开发过程相当快:

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

有了这个,我们只需要修复汇编器,以便它将添加新的JobResource:

Having this, we just needed to fix the assembler so it will add the new 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.

当有3个以上的嵌套资源时,可能有必要将所有内容手动添加到资源中.我们拥有3种资源:项目->任务->工作.如果我们采用了前面的方法,那么它将以嵌套的null错误结束.服务:

it may be necessary to manually add everything to the resource when there're 3+ nested resources. Let's day we have 3 resources: project -> task -> job. If we did the previous approach, then it will end with a nested null error. 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;
}

由此,我们获得了一个项目->任务->作业JSON响应完整阴影/hal.

With this, we obtained a project -> task -> job JSON response full hateoas /hal.

这篇关于具有资源和资源汇编器的Spring HATEOAS/Jackson的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆