[英]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.