我可以控制如何实例化spring控制器方法参数吗?

时间:2013-05-17 11:45:23

标签: java spring spring-mvc jackson

考虑spring项目中的以下接口/对象层次结构:

public interface MyInterface {
    //method defenitions
}

@Component
@Scope(SCOPE_PROTOTYPE)
public class MyClass implements MyInterface {
   //method implementations
}

我在控制器方法中使用MyClass,从请求体中读取它:

@RequestMapping(method = POST, value = "/posturi", consumes = "application/json")
public void createEntity(@RequestBody MyClass myClass) {
    //handle request
}

jackson库用于读取json数据并将其转换为java对象。

我想将控制器方法中的参数类型从MyClass更改为MyInterface。这似乎不起作用,因为无法使用new运算符实例化接口。但可以这样创建:

MyInterface instance = applicationContext.getBean(MyInterface.class);

是否有可能让spring / jackson以这种方式实例化对象?我想这样做,以便我的控制器不需要知道使用什么实现。

2 个答案:

答案 0 :(得分:0)

应该可以使用转换器。请参阅文档http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/validation.html。问题是,您如何知道您通过转换器返回哪个班级?而是重新考虑您的设计以在输入中使用POJO。

答案 1 :(得分:0)

我现在已经解决了这个问题,这个概念非常简单,但实现起来可能有点棘手。据我了解,只要提供可以从http请求转换为所需类型的@RequestBody,就可以使用HttpMessageConverter注释任何类型。 所以解决方案是:

  1. 实施HttpMessageConverter
  2. 配置弹簧以便使用HttpMessageConverter
  3. 第二部分可能有点棘手。这是因为spring添加了一堆默认的HttpMessageConverter,可以处理常见的类型,如字符串,整数,日期,我希望它们能像往常一样继续运行。另一个问题是,如果jackson在路径上,spring还会为通用json处理添加MappingJackson2HttpMessageConverter,例如转换为具体对象,地图等。 Spring将使用它发现声称能够转换为您的类型的第一个HttpMessageConverterMappingJackson2HttpMessageConverter声称能够为我的对象执行此操作,但它无法执行此操作,因此失败并且请求失败。这可能被视为一个错误......

    我想要的链是:

    1. 弹簧默认HttpMessageConverter s。
    2. 我自己的HttpMessageConverter
    3. MappingJackson2HttpMessageConverter
    4. 我找到了两种方法来实现这一目标。首先,您可以通过xml明确声明这一点。

      <mvc:annotation-driven>
          <mvc:message-converters>
              <!-- All converters in specific order here -->
          </mvc:message-converters>
      </mvc:annotation-driven>
      

      这样做的缺点是,如果默认HttpMessageConverter链在以后的版本中发生更改,则不会更改您的配置。

      另一种方法是在HttpMessageConverter之前以编程方式插入自己的MappingJackson2HttpMessageConverter

      @Configuration
      public class MyConfiguration {
      
          @Autowired
          private RequestMappingHandlerAdapter adapter;
      
          @Autowired
          private MyHttpMessageConverter myHttpMessageConverter;
      
          @PostConstruct
          private void modify() {
              List<HttpMessageConverter<?>> messageConverters = adapter.getMessageConverters();
              int insertLocation = messageConverters.size() - 1;
              for (int i = 0; i < messageConverters.size(); i++) {
                  Object messageConverter = messageConverters.get(i);
                  if (messageConverter instanceof MappingJackson2HttpMessageConverter) {
                      insertLocation = i;
                  }
              }
              messageConverters.add(insertLocation, myHttpMessageConverter);
          }
      }
      

      第二种方法将继续使用“默认配置”,即使它在以后的版本中发生了变化。我认为它有点hacky而且根本不优雅,但我认为它是一个有效的解决方案的原因是MappingJackson2HttpMessageConverter声称能够转换为无法转换为的类型似乎存在缺陷。此外,您无法明确地将HttpMessageConverter添加到链中的特定位置。

      目前我正在使用第二种选择,但你的做法取决于你......