如何将@RestController中的请求体转换为抽象值列表?

duk*_*ash 6 java spring spring-mvc spring-restcontroller

假设我们有以下类:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

以下内容@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);
    }

}
Run Code Online (Sandbox Code Playgroud)

以及请求体中的以下json:

[
  {"investmentType":"Bond"},
  {"investmentType":"Equity"}
]
Run Code Online (Sandbox Code Playgroud)

如何在List<Investment> 不使用Jackson的@JsonSubTypes抽象类的情况下将json绑定或转换为请求主体Investment,而是使用InvestmentFactory

Joe*_*e A 4

@JsonDeserialize 效果很好,但如果您有更多字段而不仅仅是类型,那么您将必须手动设置它们。如果您要返回杰克逊,您可以使用:

投资级

    @JsonTypeInfo(
            use = JsonTypeInfo.Id.NAME,
            include = JsonTypeInfo.As.PROPERTY,
            property = "investmentType")
    @JsonTypeIdResolver(InvestmentResolver.class)
    public abstract class Investment {
    } 
Run Code Online (Sandbox Code Playgroud)

InvestmentResolver.类

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());
    }
Run Code Online (Sandbox Code Playgroud)

这样做的美妙之处在于,如果您开始向投资添加字段,则不必将它们添加到解串器中(至少,就我而言,这发生在我身上),而是 Jackson 会为您处理。所以明天你就可以得到测试用例:

'[{"investmentType":"Bond","investmentName":"ABC"},{"investmentType":"Equity","investmentName":"APPL"}]'
Run Code Online (Sandbox Code Playgroud)

你应该可以走了!