Java 在Spring中:使用接口作为RequestBody并返回正确的类

Java 在Spring中:使用接口作为RequestBody并返回正确的类,java,spring,interface,controller,Java,Spring,Interface,Controller,我试图在Spring控制器中使用接口,但在实例化正确的类时遇到了问题 我有以下方法: @RequestMapping(value="/settings/features/{feature}", method=RequestMethod.POST, produces = "application/json; charset=utf-8") @ResponseBody public ResponseEntityWrapper setFeatureSettings( HttpServl

我试图在Spring控制器中使用接口,但在实例化正确的类时遇到了问题

我有以下方法:

@RequestMapping(value="/settings/features/{feature}", method=RequestMethod.POST, produces = "application/json; charset=utf-8")
@ResponseBody
public ResponseEntityWrapper setFeatureSettings(
        HttpServletRequest request,
        @PathVariable Feature feature,
        @RequestBody IFeatureSettings featureSettings,
        HttpServletResponse response
        ) {
           ...
        }
我有几个实现IFeatureSettings的类,我需要为输入实例化正确的类。通过查看feature(它是一个枚举),我可以知道哪个类是正确的。因此,对于功能A,我将有一个功能设置简单,对于功能B,我将有一个功能设置简单

理想的是,中间会有一些方法,说:这次,用数据填充类,并将它作为接口实现。


我一直在研究HandlerMethodArgumentResolver,它听起来是正确的方法,但我不确定如何做到这一点。我需要访问feature参数,希望在获得解析代码之前解析它(或者我需要自己解析)。

编写另一个将
feature
bodyObject
作为参数的方法怎么样

差不多

private final IFeatureSettings getFeatureImpl(Feature feature, Object bodyObject) {
switch(feature) {
case a: return new AFeatureSettingsImpl;
...
   }
}

BTW,我真的不知道你想要的东西是否存在。 简单的解决方案是在方法签名中使用
Map
而不是
IFeatureSettings
。然后基于
特性
鉴别器,您可以手动实例化并填充bean。使用ApacheBeanutils它看起来像这样:

@RequestMapping(value="/settings/features/{feature}", method=RequestMethod.POST, produces = "application/json; charset=utf-8")
@ResponseBody
public ResponseEntityWrapper setFeatureSettings(
    HttpServletRequest request,
    @PathVariable Feature feature,
    @RequestBody Map featureSettings,
    HttpServletResponse response) {
        IFeatureSettings bean = createBean(feature); // instantiating the right bean based on the feature discriminator
        BeanUtils.populate(bean, featureSettings);
        ...
}
如果您想使其更通用,请查看HttpMessageConverters。Spring默认使用将json绑定到
@RequestBody
。您必须使用自定义逻辑扩展此转换器。请记住,在这种情况下,特征鉴别器不能是独立的参数,因为您需要在转换器中访问它。您可以输入HTTP头以使其工作。转换器的
readInternal
方法如下所示:

@Override
protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
    Class<?> actualClass = lookupByFeature(inputMessage.getHeaders().get("feature")); // returns the actual Class type based on the feature found in the header
    return super.readInternal(actualClass, inputMessage); // and now the original implementation can use the actual type instead of the interface
}
@覆盖
受保护的对象readInternal(类clazz,HttpInputMessage inputMessage)引发IOException,HttpMessageGenetradableException{
类actualClass=LookupyFeature(inputMessage.getHeaders().get(“feature”);//根据在标头中找到的功能返回实际的类类型
返回super.readInternal(actualClass,inputMessage);//现在原始实现可以使用实际类型而不是接口
}

谢谢您的回答,但问题不在于选择正确的实现类,而是让Spring根据输入自动创建正确的类。这是一个Spring问题。添加一个映射作为参数并不能解决我的问题,因为Spring本身不知道如何填充它,所以没有理由将该映射作为方法参数的一部分。正如您所建议的,我当然可以根据不同的特性手动实例化这些类,但我更愿意构建一个更通用的解决方案,它也适用于其他情况。使用消息转换器是另一种选择(虽然不是很好),这意味着我必须再次手动绑定自己,并且以某种方式必须再次手动访问特性参数。这是不对的。Spring能够使用json中的键值对填充映射。如果您想要一个更通用的解决方案,您需要使用如上所述的转换器。您无法避免自己编写绑定逻辑。Spring怎么可能知道您的enum->bean实现映射呢?问题是Spring的输入(实际上是jackson)是一个没有对象类型提示的对象,服务器端的接口没有说明可以使用哪个实现类(它只是一个接口,Imp部分未知). 那么jackson如何知道选择哪个实现类来将它得到的值映射到一个真实的对象呢?这不是jackson,而是Spring的MappingJacksonHttpMessageConverter!这就是扩展和重写readInternal方法所需的,以便能够基于特性鉴别器选择正确的bean实现。这就是鉴别器必须转到HTTP头的原因。我会用更多的细节更新我的答案,让它更清晰。这个答案看起来是一个很好的方向,我会尝试一下,谢谢!我会更新成功/失败的信息。