我有一个JSON文档,它是对一堆文件进行解析的结果:
{
"offer": {
"clientName": "Tom",
"insuranceCompany": "INSURANCE",
"address": "GAMLE BONDALSVEGEN 53",
"renewalDate": "22.12.2018",
"startDate": "22.12.2017",
"too_old": false,
"products": [
{
"productType": "TRAVEL",
"objectName": "Reiseforsikring - Holen, Tom Andre",
"name": null,
"value": null,
"isExclude": false,
"monthPrice": null,
"yearPrice": 1637,
"properties": {}
}
]
},
"documents": [
{
"clientName": "Tom",
"insuranceCompany": "INSURANCE",
"fileName": "insurance_tom.pdf",
"address": "GAMLE BONDALSVEGEN 53",
"renewalDate": "22.12.2019",
"startDate": "22.12.2018",
"issuedDate": "20.11.2018",
"policyNumber": "6497777",
"products": [
{
"productType": "TRAVEL",
"objectName": "Reiseforsikring - Holen, Tom Andre",
"name": null,
"value": null,
"isExclude": false,
"monthPrice": null,
"yearPrice": 1921,
"properties": {
"TRAVEL_PRODUCT_NAME": "Reise Ekstra",
"TRAVEL_DURATION_TYPE": "DAYS",
"TRAVEL_TYPE": "FAMILY",
"TRAVEL_DURATION": "70",
"TRAVEL_INSURED_CLIENT_NAME": "Holen, Tom Andre, Familie"
}
},
我想要遍历所有来自“documents”部分的“products”,并将缺失的“properties”设置为来自“offer”部分的“products”。
“Offer”和“documents”在JSON中处于相同的深度级别。
使用Stream API实现如下:
private void mergePropertiesToOffer(InsuranceDocumentsSession insuranceSession) {
Validate.notNull(insuranceSession, "insurance session can't be null");
if (insuranceSession.getOffer() == null) return;
log.info("BEFORE_MERGE");
// merge all properties by `objectName`
Stream.of(insuranceSession).forEach(session -> session.getDocuments().stream()
.filter(Objects::nonNull)
.flatMap(doc -> doc.getProducts().stream())
.filter(Objects::nonNull)
.filter(docProduct -> StringUtils.isNotEmpty(docProduct.getObjectName()))
.filter(docProduct -> MapUtils.isNotEmpty(docProduct.getProperties()))
.forEach(docProduct -> Stream.of(session.getOffer())
.flatMap(offer -> offer.getProducts().stream())
.filter(Objects::nonNull)
.filter(offerProduct -> MapUtils.isEmpty(offerProduct.getProperties()))
.filter(offerProduct -> StringUtils.isNotEmpty(offerProduct.getObjectName()))
.filter(offerProduct -> offerProduct.getObjectName().equals(docProduct.getObjectName()))
.forEach(offerProduct -> {
try {
ObjectMapper mapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
log.info("BEFORE_PRODUCT: {}", mapper.writeValueAsString(offerProduct));
offerProduct.setProperties(docProduct.getProperties());
log.info("UPDATED_PRODUCT: {}", mapper.writeValueAsString(offerProduct));
} catch (JsonProcessingException e) {
log.error("Error converting product to offer: {}", e.getCause());
}
})));
log.info("AFTER_MERGE");
}
它工作得很好。然而,未来实施比维护要快得多。
我两次使用Stream.of()
工厂方法获取不同级别的2个实体的流。此外,尽可能使用flatMap()
,以及所有的空值检查。
问题不是这个实现太难了吗?
应该将其重构并分成较小的部分吗?如果是,如何使用良好的编程原则?
解决方案:
非常感谢 nullpointer
的答案。
最终解决方案如下:
Map<Integer, InsuranceProductDto> offerProductMap = session.getOffer().getProducts()
.stream()
.filter(this::validateOfferProduct)
.collect(Collectors.toMap(InsuranceProductDto::getYearPrice, Function.identity(), (first, second) -> first));
Map<Integer, InsuranceProductDto> documentsProductMap = session.getDocuments()
.stream()
.flatMap(d -> d.getProducts().stream())
.filter(this::validateDocumentProduct)
.collect(Collectors.toMap(InsuranceProductDto::getYearPrice, Function.identity(), (first, second) -> first));
documentsProductMap.forEach((docPrice, docProduct) -> {
if (offerProductMap.containsKey(docPrice)) {
offerProductMap.compute(docPrice, (s, offerProduct) -> {
setProductProperties(offerProduct, docProduct);
return offerProduct;
});
}
});
// after finishing execution `offerProductMap` contains updated products