[英]How do I convert request body in a @RestController to a List of abstract values?
假設我們有以下類:
public abstract class Investment {
private String investmentType;
// getters & setters
}
public class Equity extends Investment {
}
public class Bond extends Investment {
}
public class InvestmentFactory {
public static Investment getTypeFromString(String investmentType) {
Investment investment = null;
if ("Bond".equals(investmentType)) {
investment = new Bond();
} else if ("Equity".equals(investmentType)) {
investment = new Equity();
} else {
// throw exception
}
return investment;
}
}
以下@RestController
:
@RestController
public class InvestmentsRestController {
private InvestmentRepository investmentRepository;
@Autowired
public InvestmentsRestController(InvestmentRepository investmentRepository) {
this.investmentRepository = investmentRepository;
}
@RequestMapping(RequestMethod.POST)
public List<Investment> update(@RequestBody List<Investment> investments) {
return investmentRepository.update(investments);
}
}
以及請求體中的以下json:
[
{"investmentType":"Bond"},
{"investmentType":"Equity"}
]
如何在不使用Jackson的抽象類Investment
的@JsonSubTypes
情況下將json綁定或轉換為List<Investment>
的請求主體,而是使用InvestmentFactory
?
@JsonDeserialize效果很好,但是如果你有更多的字段而不僅僅是類型,那么你必須手動設置它們。 如果你要回到傑克遜,你可以使用:
Investment.class
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "investmentType")
@JsonTypeIdResolver(InvestmentResolver.class)
public abstract class Investment {
}
InvestmentResolver.class
public class InvestmentResolver extends TypeIdResolverBase {
@Override
public JavaType typeFromId(DatabindContext context, String id) throws IOException {
Investment investment = InvestmentFactory.getTypeFromString(type);
return context.constructType(investment.getClass());
}
這樣做的好處是,如果你開始向投資添加字段,你就不必在Desrializer中添加它們(至少,在我的情況下這發生在我身上),但傑克遜會為你照顧它。 所以明天你可以得到測試用例:
'[{"investmentType":"Bond","investmentName":"ABC"},{"investmentType":"Equity","investmentName":"APPL"}]'
你應該好好去!
如果你可以使用@JsonDeserialize :
@JsonDeserialize(using = InvestmentDeserializer.class)
public abstract class Investment {
}
public class InvestmentDeserializer extends JsonDeserializer<Investment> {
@Override
public Investment deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
ObjectMapper objectMapper = (ObjectMapper) p.getCodec();
TreeNode node = objectMapper.readTree(p);
TreeNode investmentNode = node.get("investmentType");
String type = objectMapper.readValue(investmentNode.traverse(objectMapper), String.class);
return InvestmentFactory.getTypeFromString(type);
}
}
示例控制器:
@RestController
public class MyController {
@RequestMapping("/")
public List<Class<?>> update(@RequestBody List<Investment> investments) {
return investments.stream().map(Object::getClass).collect(Collectors.toList());
}
}
測試:
$ curl localhost:8080 -H "Content-Type: application/json" -d '[{"investmentType":"Bond"},{"investmentType":"Equity"}]'
輸出:
["com.example.demo.Bond","com.example.demo.Equity"]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.