【问题标题】:JSON parse error: Cannot construct instance of 'Custom object' while dealing with one to one relationJSON解析错误:处理一对一关系时无法构造“自定义对象”的实例
【发布时间】:2019-06-28 15:06:20
【问题描述】:

我正在使用 java 和 spring boot 开发一个 REST API。

有两个实体具有一对一关系:

用户:

@Entity
@Table(name = "users")
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    @Column(name = "first_name", nullable = false)
    private String firstName;

    @Column(name = "last_name", nullable = false)
    private String lastName;

    @Column(name = "email", nullable = false, unique = true)
    private String email;

    @OneToOne(fetch = FetchType.LAZY,
            cascade =  CascadeType.ALL,
            mappedBy = "employee")
    @JsonBackReference
    private Company company;

    // constructors, getters & setters...

和公司:

@Entity
@Table(name = "companies")
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Company {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    @Column(name = "company_name", nullable = false)
    private String companyName;

    @Column(name = "company_info", nullable = false)
    private String companyInfo;

    @CreationTimestamp
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "created_at", nullable = false)
    private Date createdAt;

    @OneToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "employee_id", nullable = false)
    @JsonManagedReference
    private User employee;

   // constructors, getters & setters...

我希望能够通过 POST 方法创建公司,因此我在 CompanyController 中创建了一个(我省略了控制器中的 GET 方法,因为它们按预期工作):

@RestController
@RequestMapping(value = "/api/v1")
public class CompanyController {

    private static final Logger logger = LoggerFactory.getLogger(CompanyController.class);

    @Autowired
    private CompanyRepository companyRepository;

    @PostMapping(path = "company", produces = "application/JSON")
    public ResponseEntity<?> createCompany(@RequestBody Company company){
        logger.info("Request to save new Company: {}", company);

        Company result = companyRepository.save(company);
        return ResponseEntity.ok().body(result);
    }

当我使用 JSON 发送请求时,createCompany 方法工作正常,如下所示:

{
"companyName" : "Big Client Company 2",
"companyInfo" : "unspecified",
"employee" : {
    "id": 17,
    "firstName": "someName",
    "lastName": "someLastName",
    "email": "someEmail@a.ru"
  }
}

但是,我希望能够发送 JSON, 没有整个员工字段,但只有一个 id:

{
"companyName" : "Big Client Company 2",
"companyInfo" : "unspecified",
"employee" : 17
}

当我这样做时,我得到一个错误:

JSON 解析错误:无法构造 model.User 的实例(尽管至少存在一个 Creator):没有 int/Int-argument 构造函数/工厂方法可从数值 (17) 反序列化

那么问题有没有办法做到这一点不改变公司类“员工”为字符串(并摆脱一对一的关系)?

我试图找到编写自定义 JSON 反序列化器的示例,但没有找到适合我的示例。

【问题讨论】:

  • @alan-hay 我试过了,公司成功创建并保存到数据库。尽管作为响应发送的 JSON 包含一个空的员工正文,但 GET 请求返回了具有正确员工正文的公司。更新:还没有看到您使用链接更新了您的评论。我的回复是尝试发送"employee" : { "id" : 17 }至于链接我在发布之前已经检查过它对我不起作用。

标签: java json hibernate spring-boot jpa


【解决方案1】:

您可以使用自定义反序列化:

public class CompanyDeserializer extends StdDeserializer<Company> { 

@Autowired
private UserRepository userRepository;

public CompanyDeserializer() { 
    this(null); 
} 

public CompanyDeserializer(Class<?> vc) { 
    super(vc); 
}

@Override
public Company deserialize(JsonParser jp, DeserializationContext ctxt) 
  throws IOException, JsonProcessingException {
    JsonNode node = jp.getCodec().readTree(jp);
    Company c = new Company();
    //Set the rest of the attributes.
    Long empId = (Long) ((IntNode) node.get("employee")).numberValue();
    c.setEmployee(userRepository.findById(empId).orElse(null)));
    return c;
}

}

【讨论】:

  • 我放了@JsonComponent 注释,它起作用了!谢谢!
【解决方案2】:

问题是您的用户在创建它们时需要提供必填字段(firstNamelastNameemail)。

如果没有用户,您将无法使用您现在拥有的定义创建用户。

您可以在这些字段上使用nullable = true,但最终可能会导致您想要保留在数据库中的数据不一致。如果让这些字段为空,那么我会建议这种方法。

另外,作为旁注,请注意混合 REST 控制器层和存储库层通常是一种不好的做法。您应该通过服务层将这些层分开。

【讨论】:

  • 不幸的是,这些字段不能为空。谢谢你的注意!我对 Spring Boot 还很陌生,所以会尝试找到有关正确结构和组织层方式的更多信息
  • 没问题 :) 检查 Spring Data REST。我认为它将涵盖您需要的所有功能。您无需手动定义所有 API 行为
猜你喜欢
  • 2018-01-17
  • 2019-04-01
  • 2018-07-05
  • 1970-01-01
  • 1970-01-01
  • 2020-06-13
  • 2020-06-14
  • 1970-01-01
  • 2014-02-13
相关资源
最近更新 更多