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

时间:2016-12-06 07:56:57

标签: java spring-boot integration-testing spring-data-jpa spring-data-rest

我的spring-data-rest集成测试因简单的json请求而失败。考虑以下jpa模型

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

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
}

在我的测试中,我通过传递人

使用personRepository和inited order创建了一个人
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());

订单已创建,但创建者未与订单关联。另外我想将请求体传递为json对象。在这个我的json对象应该包含如下的创建者

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

如果我使用以下json发送请求正文,则调用正常

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

但我不想发送第二个json。任何想法如何解决问题。因为我的客户端已经通过发送第一个json来消耗服务器响应。现在我迁移了我的服务器以使用spring-data-rest。之后我的所有客户端代码都无法运行。

如何解决这个问题?

5 个答案:

答案 0 :(得分:7)

您正确地将订单与创建者关联,但是Person与订单无关。您缺少Person类中的List<Order> orders字段。添加此项,添加注释,添加向人员添加订单的方法,然后在发送JSON之前,您应该调用以下内容:

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

答案 1 :(得分:7)

您是否尝试在@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
}

答案 2 :(得分:1)

您的CREATE TABLE IF NOT EXISTS `ps_cms_block` ( `id_cms_block` int(10) unsigned NOT NULL, `id_cms_category` int(10) unsigned NOT NULL, `location` tinyint(1) unsigned NOT NULL, `position` int(10) unsigned NOT NULL DEFAULT '0', `display_store` tinyint(1) unsigned NOT NULL DEFAULT '1' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ; INSERT INTO `ps_cms_block` (`id_cms_block`, `id_cms_category`, `location`, `position`, `display_store`) VALUES (1, 1, 0, 0, 1); ALTER TABLE `ps_cms_block` ADD PRIMARY KEY (`id_cms_block`); ALTER TABLE `ps_cms_block` MODIFY `id_cms_block` int(10) unsigned NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=2; Order类都应实施Person,以便正确地将它们分解为Serializable并重建它们。

答案 3 :(得分:1)

有一些方法可以解决你的问题,但我想给你一个提示。您只需保存"id"个人,并在需要时从您的数据库中通过"id"获取此人。

它解决了您的问题,也节省了内存。

答案 4 :(得分:1)

我相信你需要做两件事来完成这项工作。

  1. 正确处理反序列化。正如您所期望Jackson通过构造函数填充嵌套的Person对象,您需要使用@JsonCreator对其进行注释。见:
  2. http://www.cowtowncoder.com/blog/archives/2011/07/entry_457.html

      

    Jackson的一个更强大的功能是它能够使用任意的&gt;构造函数来创建POJO实例,通过指示要使用的构造函数   @JsonCreator注释   ...........................................   基于属性的创建者通常用于传递一个或多个   强制性参数到构造函数(直接或通过工厂   方法)。 如果找不到JSON的属性,则传递null   (或者,如果是基元,则是所谓的默认值; 0表示整数,等等   上)。

    此处还可以看到杰克逊为何无法自动解决这个问题。

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

    1. 更新JPA映射。如果关联的Person现在由Jackson反序列化器正确填充,那么通过向关系添加必要的JPA级联选项,则应该保持两个实例。
    2. 我认为以下内容应该按预期工作:

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