简体   繁体   English

spring-data-rest集成测试因简单的json请求而失败

[英]spring-data-rest integration test fails with simple json request

My spring-data-rest integration test fails for a simple json request. 我的spring-data-rest集成测试因简单的json请求而失败。 Consider the below jpa models 考虑下面的jpa模型

Order.java Order.java

public class Order {

    @Id @GeneratedValue//
    private Long id;
    @ManyToOne(fetch = FetchType.LAZY)//
    private Person creator;
    private String type;

    public Order(Person creator) {
        this.creator = creator;
    }

    // getters and setters
}

Person.java Person.java

ic class Person {

    @Id @GeneratedValue private Long id;

    @Description("A person's first name") //
    private String firstName;

    @Description("A person's last name") //
    private String lastName;

    @Description("A person's siblings") //
    @ManyToMany //
    private List<Person> siblings = new ArrayList<Person>();

    @ManyToOne //
    private Person father;

    @Description("Timestamp this person object was created") //
    private Date created;

    @JsonIgnore //
    private int age;

    private int height, weight;
    private Gender gender;

    // ... getters and setters
}

In my test I created a person by using personRepository and inited order by passing person 在我的测试中,我通过传递人员使用personRepository和inited命令创建了一个人

Person creator = new Person();
creator.setFirstName("Joe");
creator.setLastName("Keith");
created.setCreated(new Date());
created.setAge("30");
creator = personRepository.save(creator);

Order order = new Order(creator);
String orderJson = new ObjectMapper().writeValueAsString(order);

mockMvc.perform(post("/orders").content(orderJson).andDoPrint());

Order is created but creator is not associated with the order. 订单已创建,但创建者未与订单关联。 Also I want to pass request body as a json object. 另外我想将请求体传递为json对象。 In this my json object should contain creator as follows 在这个我的json对象应该包含如下创建者

{
"type": "1",
"creator": {
    "id": 1,
    "firstName": "Joe",
    "lastName": "Keith",
    "age": 30
}
}

If I send request body with the following json, the call works fine 如果我使用以下json发送请求正文,则调用正常

{
"type": "1",
"creator": "http://localhost/people/1"
}

But I don't want to send the second json. 但我不想发送第二个json。 Any idea how to solve the issue. 任何想法如何解决问题。 Because already my client is consuming the server response by sending first json. 因为我的客户端已经通过发送第一个json来消耗服务器响应。 Now I migrated my server to use spring-data-rest. 现在我迁移了我的服务器以使用spring-data-rest。 After that all my client code is not working. 之后我的所有客户端代码都无法运行。

How to solve this? 怎么解决这个?

You are correctly associating order with the creator, however the Person is not associated with the orders. 您正确地将订单与创建者关联,但是Person与订单无关。 You are missing the List<Order> orders field in Person class. 您缺少Person类中的List<Order> orders字段。 Add this, add annotations, add methods for adding order to person and then before sending JSON you should call something like this: 添加此项,添加注释,添加向人员添加订单的方法,然后在发送JSON之前,您应该调用以下内容:

creator.addOrder(order);
order.setCreator(cretr);

Did you try using cascade = CascadeType.ALL in @ManyToOne annotation 您是否尝试在@ManyToOne注释中使用cascade = CascadeType.ALL

 public class Order { @Id @GeneratedValue// private Long id; @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)// private Person creator; private String type; public Order(Person creator) { this.creator = creator; } // getters and setters } 

OrderPerson类都应该实现Serializable以便将它们正确分解并从JSON重建它们。

There are some ways to solve your problem, but I want give you a hint. 有一些方法可以解决你的问题,但我想给你一个提示。 You just can save only "id" of your person and get the person by "id" from your database, when you need this. 你只可以只保存"id"的人,并得到由人"id"从你的数据库,当你需要这个。

It solves your problem and it also saves the memory. 它解决了您的问题,也节省了内存。

I believe you need to do two things to get this work. 我相信你需要做两件事来完成这项工作。

  1. Handle the deserialization properly. 正确处理反序列化。 As you expect Jackson to populate the nested Person object via the constructor you need to annotate this with @JsonCreator . 正如您所期望Jackson通过构造函数填充嵌套的Person对象,您需要使用@JsonCreator注释它。 See here: 看这里:

http://www.cowtowncoder.com/blog/archives/2011/07/entry_457.html http://www.cowtowncoder.com/blog/archives/2011/07/entry_457.html

One of more powerful features of Jackson is its ability to use arbitrary >constructors for creating POJO instances, by indicating constructor to use with @JsonCreator annotation ........................................... Property-based creators are typically used to pass one or more obligatory parameters into constructor (either directly or via factory method). Jackson的一个更强大的功能是它能够使用任意>构造函数来创建POJO实例,通过指示与@JsonCreator注释一起使用的构造函数..................... ......................基于属性的创建者通常用于将一个或多个必需参数传递给构造函数(直接或通过工厂方法)。 If a property is not found from JSON, null is passed instead (or, in case of primitives, so-called default value; 0 for ints and so on). 如果未从JSON中找到属性,则传递null (或者,如果是基元,则为所谓的默认值; 0表示int,依此类推)。

See also here on why Jackson may not be able to automatically work this out. 另请参见此处为何杰克逊可能无法自动解决此问题。

https://stackoverflow.com/a/22013603/1356423 https://stackoverflow.com/a/22013603/1356423

  1. Update your JPA mappings. 更新JPA映射。 If the associated Person is now populated correctly by the Jackson deserializer then by adding the necessary JPA cascade options to the relationship then both instances should be persisted. 如果关联的Person现在由Jackson反序列化器正确填充,那么通过向关系添加必要的JPA级联选项,则应该保持两个实例。

I think then the following should work as expected: 我认为以下应该按预期工作:

public class Order {

    @Id 
    @GeneratedValue(...)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY, cascade = cascadeType.ALL)
    private Person creator;

    private String type;

    @JsonCreator
    public Order(@JsonProperty("creator") Person creator) {
        this.creator = creator;
    }
}

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

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