Java Spring Jackson通过Id引用现有对象来反序列化对象
我有以下三个实体类: 装运实体:Java Spring Jackson通过Id引用现有对象来反序列化对象,java,json,spring,jackson,deserialization,Java,Json,Spring,Jackson,Deserialization,我有以下三个实体类: 装运实体: @Entity @Table(name = "SHIPMENT") public class Shipment implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "SHIPMENT_ID", nullable = false) private in
@Entity
@Table(name = "SHIPMENT")
public class Shipment implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "SHIPMENT_ID", nullable = false)
private int shipmentId;
@Column(name = "DESTINATION", nullable = false)
private String destination;
@OneToMany(mappedBy = "shipment")
private List<ShipmentDetail> shipmentDetailList;
//bunch of other variables omitted
public Shipment(String destination) {
this.destination = destination;
shipmentDetailList = new ArrayList<>();
}
产品实体:
@Entity
@Table(name = "Product")
public class Product implements Serializable {
@Id
@Column(name = "PRODUCT_ID", nullable = false)
private String productId;
@Column(name = "PRODUCT_NAME", nullable = false)
private String productName;
//bunch of other variables omitted
public Product() {
}
public Product(String productId, String productName) {
this.productId = productId;
this.productName = productName;
}
我通过RESTAPI接收JSON。问题是我不知道如何使用shipmentDetails反序列化一个新的装运,shipmentDetails仅通过ID与现有对象建立关系。我知道您可以简单地使用objectmapper反序列化,但这要求每个shipmentDetail中都包含product的所有字段。如何仅使用productID进行实例化
已收到JSON示例
{
"destination": "sample Dest",
"shipmentDetails": [
{
"productId": "F111111111111111"
},
{
"productId": "F222222222222222"
}
]
}
当前,我的rest端点将接收JSON,并执行以下操作:
public ResponseEntity<String> test(@RequestBody String jsonString) throws JsonProcessingException {
JsonNode node = objectMapper.readTree(jsonString);
String destination = node.get("destination").asText();
Shipment newShipment = new Shipment(destination);
shipmentRepository.save(newShipment);
JsonNode shipmentDetailsArray = node.get("shipmentDetails");
int shipmentDetailsArrayLength = shipmentDetailsArray.size();
for (int c = 0; c < shipmentDetailsArrayLength; c++) {
String productId = node.get("productId").asText();
Product product = productRepository.findById(productId).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No product with ID of: " + productId + " exists!"));
ShipmentDetail shipmentDetail = new ShipmentDetail(newShipment, product, quantity);
shipmentDetailRepository.save(shipmentDetail);
}
}
public ResponseEntity测试(@RequestBody String jsonString)抛出JsonProcessingException{
JsonNode节点=objectMapper.readTree(jsonString);
字符串destination=node.get(“destination”).asText();
装运新闻装运=新装运(目的地);
shipmentRepository.save(newShipment);
JsonNode shipmentDetailsArray=node.get(“shipmentDetails”);
int shipmentDetailsArrayLength=shipmentDetailsArray.size();
对于(int c=0;cnew ResponseStatusException(HttpStatus.NOT_FOUND,“没有ID为“+productId+”的产品存在!”);
ShipmentDetail ShipmentDetail=新的ShipmentDetail(新装运、产品、数量);
shipmentDetailRepository.save(shipmentDetail);
}
}
我想做的是:
public ResponseEntity<String> test2(@RequestBody String jsonString) throws JsonProcessingException {
JsonNode wholeJson = objectMapper.readTree(jsonString);
Shipment newShipment = objectMapper.treeToValue(wholeJson, Shipment.class);
return new ResponseEntity<>("Transfer Shipment successfully created", HttpStatus.OK);
}
public ResponseEntity test2(@RequestBody String jsonString)抛出JsonProcessingException{
JsonNode wholeJson=objectMapper.readTree(jsonString);
Shipping newShipment=objectMapper.treeToValue(wholeJson,shipping.class);
返回新的响应属性(“已成功创建转运”,HttpStatus.OK);
}
我尝试了这个解决方案,但没有成功:
如何使产品实体搜索现有产品,而不是尝试创建新产品。我一直在使用的一种非常低效的方法是遍历json数组,对于每个productId,使用productRepository查找产品,然后逐个设置产品的shipmentDetail。我不确定这是否是最佳实践,因为我是自学成才
因此,在伪代码中,我试图做的是:
代码已经大大简化,以便更好地展示问题,我认为您当前的方法不是一个糟糕的解决方案,您正在正确地处理问题,并且只需几步 无论如何,有一件事你可以尝试一下 我们的想法是在支持与
产品
实体关系的同一数据库列上定义一个新字段productId
,类似于:
@实体
@表(name=“装运详情”)
公共类ShipmentDetail实现可序列化{
@身份证
@GeneratedValue(策略=GenerationType.IDENTITY)
@列(name=“Shipping\u DETAIL\u ID”,null=false)
私有int-shipmentDetailId;
@列(name=“PRODUCT\u ID”,null=false)
私有字符串productId;
@许多酮
@JoinColumn(name=“PRODUCT_ID”,insertable=false,updateable=false)
私人产品;
@杰索尼奥雷
@许多酮
@JoinColumn(name=“shipping\u ID”,null=false)
私人运输;
//忽略了一堆其他变量
公共船舶详情(){
}
公共装运详细信息(装运、产品){
本产品=产品;
本次装运=装运;
}
}
product
字段必须注释为notinsertable
和notupdateable
:相反,Hibernate会抱怨应该使用哪个字段来维护与product
实体的关系,换句话说,就是维护实际列值
修改与ShipmentDetail
的ShipmentDetail
关系,并传播持久性操作(根据需要调整代码):
@OneToMany(mappedBy=“shipping”,cascade=CascadeType.ALL,orphan=true)
私有列表shipmentDetailList;
然后,您可以安全地依赖Spring+Jackson反序列化,并获得对接收的装运
对象的引用:
public ResponseEntity processShipping(@RequestBody-shipping){
//此时,装运应包含不同的细节,
//每个都具有相应的productId信息
//执行所需的验证,如有必要,记录信息
//保存对象:它应该在数据库中保存整个对象树
shipmentRepository.save(发货);
}
这种方法有一个明显的缺点,产品的存在事先没有检查
虽然可以使用外键确保数据库级别的数据完整性,但在执行实际插入之前,验证信息是否正确可能会比较方便:
public ResponseEntity processShipping(@RequestBody-shipping){
//此时,装运应包含不同的细节,
//每个都具有相应的productId信息
//执行所需的验证,如有必要,记录信息
List shipmentDetails=shipping.getShipmentDetails();
if(shipmentDetails==null | | shipmentDetails.isEmpty()){
//适当地处理错误
抛出新的ResponseStatusException(HttpStatus.BAD_请求,“未提供装运详细信息”);
}
shipmentDetails.forEach(shipmentDetail->{
斯特里
public ResponseEntity<String> test2(@RequestBody String jsonString) throws JsonProcessingException {
JsonNode wholeJson = objectMapper.readTree(jsonString);
Shipment newShipment = objectMapper.treeToValue(wholeJson, Shipment.class);
return new ResponseEntity<>("Transfer Shipment successfully created", HttpStatus.OK);
}
Product product = productRepository.findById(productId)
public class ShipmentDeserializer extends JsonDeserializer {
@Override
public Shipment deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
JsonNode node = jp.getCodec().readTree(jp);
String destination = node.get("destination").asText();
Shipment shipment = new Shipment(destination);
JsonNode shipmentDetailsNode = node.get("shipmentDetails");
List shipmentDetailList = new ArrayList();
for (int c = 0; c < shipmentDetailsNode.size(); c++) {
JsonNode productNode = shipmentDetailsNode.get(c);
String productId = productNode.get("productId").asText();
Product product = new Product(productId);
ShipmentDetail shipmentDetail = new ShipmentDetail(product);
shipmentDetailList.add(shipmentDetail);
}
shipment.setShipmentDetailList(shipmentDetailList);
return shipment;
}
}
@JsonDeserialize(using = ShipmentDeserializer .class)
public class Shipment {
// Class code
}
public ResponseEntity test2(@RequestBody String jsonString) throws JsonProcessingException {
Shipment newShipment = objectMapper.readValue(jsonString, Shipment.class);
/* More code */
return new ResponseEntity("Transfer Shipment successfully created", HttpStatus.OK);
}
public ResponseEntity test2(@RequestBody String jsonString) throws JsonProcessingException {
Shipment newShipment = objectMapper.readValue(jsonString, Shipment.class);
shipmentRepository.save(newShipment);
List<ShipmentDetail> shipmentDetails = newShipment.getShipmentDetailList();
for (int i = 0; i < shipmentDetails.size(); c++) {
ShipmentDetail shipmentDetail = shipmentDetails.get(i);
shipmentDetail.setShipment(newShipment);
Product product = productRepository.findById(productId).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No product with ID of: " + productId + " exists!"));
shipmentDetail.setProduct(product);
shipmentDetailRepository.save(shipmentDetail);
}
return new ResponseEntity("Transfer Shipment successfully created", HttpStatus.OK);
}
public class ShipmentDeserializer extends JsonDeserializer {
@Override
public Shipment deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
JsonNode node = jp.getCodec().readTree(jp);
String destination = node.get("destination").asText();
Shipment shipment = new Shipment(destination);
JsonNode shipmentDetailsNode = node.get("shipmentDetails");
List shipmentDetailList = new ArrayList();
for (int c = 0; c < shipmentDetailsNode.size(); c++) {
JsonNode productNode = shipmentDetailsNode.get(c);
String productId = productNode.get("productId").asText();
Product product = productRepository.findById(productId).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No product with ID of: " + productId + " exists!"));
ShipmentDetail shipmentDetail = new ShipmentDetail(product);
shipmentDetailList.add(shipmentDetail);
}
shipment.setShipmentDetailList(shipmentDetailList);
return shipment;
}
}