Spring MVC:在@ResponseBody 中将对象转换为基元

Spring MVC: Convert Object to Primitive in @ResponseBody

我想要一个控制器 return 一个对象列表给客户端。一个对象也可以是 MyClass 的一个实例,它基本上是一个带有一堆方法的放大的 long-value。因此,将 MyClass 转换为它的 long 表示是有意义的。 Spring/Jackson 应该自己进行序列化。

我试图使用 Jackson 的 @Json*-注释,但找不到任何有用的东西。

这是简化的控制器:

  @RequestMapping("/execute")
  @ResponseBody
  public List<List<Object>> execute() {
    return generateResponseBody();
  }

内部对象列表由一个字符串、两个数字、一个 MyClass 实例和另外两个字符串组成。虽然原语转换得很好,但 MyClass 总是转换为 JSON-map:

["str1",1337,42,{"asDmy":"13.01.2015","asYmd":"2015.01.13"},"str2","str3"]

不过,我想要

["str1",1337,42,1421164289000,"str2","str3"]

注意:我也尝试使用 Converter 作为一些教程和答案建议:

  @Bean
  public ConversionServiceFactoryBean conversionService() {
    HashSet<Object> converters = new HashSet<>();
    converters.add(new Converter<MyClass, Long>() {

      @Override
      public Long convert(MyClass value) {
        return value.getAsMilliseconds();
      }

      @Override
      public JavaType getInputType(TypeFactory typeFactory) {
        return SimpleType.construct(MyClass.class);
      }

      @Override
      public JavaType getOutputType(TypeFactory typeFactory) {
        return SimpleType.construct(Long.class);
      }});
    ConversionServiceFactoryBean conversionService = new ConversionServiceFactoryBean();
    conversionService.setConverters(converters);
    return conversionService;
  }

但是,当我创建一个 ConversionServiceFactoryBean 的 bean 时,它会使我的 CXF 在 webapp 启动时崩溃。如果有人关心,这里是堆栈跟踪:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'appConfig': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.provider.schemas.cai3g1_2.SessionControl com.mc.config.AppConfig.sessionControl; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionControl': FactoryBean threw exception on object creation; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'conversionService': Requested bean is currently in creation: Is there an unresolvable circular reference?
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:292)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1185)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getObject(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:370)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1094)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:989)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getObject(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:915)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:403)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4971)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5467)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.provider.schemas.cai3g1_2.SessionControl com.mc.config.AppConfig.sessionControl; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionControl': FactoryBean threw exception on object creation; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'conversionService': Requested bean is currently in creation: Is there an unresolvable circular reference?
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:508)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:289)
    ... 30 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionControl': FactoryBean threw exception on object creation; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'conversionService': Requested bean is currently in creation: Is there an unresolvable circular reference?
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:175)
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:103)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1512)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:250)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1017)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:960)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:858)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:480)
    ... 32 more
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'conversionService': Requested bean is currently in creation: Is there an unresolvable circular reference?
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.beforeSingletonCreation(DefaultSingletonBeanRegistry.java:335)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
    at org.springframework.beans.factory.support.AbstractBeanFactory.isSingleton(AbstractBeanFactory.java:424)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:387)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:354)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:466)
    at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1188)
    at org.apache.cxf.bus.spring.SpringBeanLocator.getBeansOfType(SpringBeanLocator.java:59)
    at org.apache.cxf.bus.CXFBusImpl.getExtension(CXFBusImpl.java:99)
    at org.apache.cxf.service.factory.AbstractServiceFactoryBean.setBus(AbstractServiceFactoryBean.java:98)
    at org.apache.cxf.frontend.AbstractWSDLBasedEndpointFactory.initializeServiceFactory(AbstractWSDLBasedEndpointFactory.java:231)
    at org.apache.cxf.frontend.AbstractWSDLBasedEndpointFactory.createEndpoint(AbstractWSDLBasedEndpointFactory.java:100)
    at org.apache.cxf.frontend.ClientFactoryBean.create(ClientFactoryBean.java:90)
    at org.apache.cxf.frontend.ClientProxyFactoryBean.create(ClientProxyFactoryBean.java:144)
    at org.apache.cxf.jaxws.JaxWsProxyFactoryBean.create(JaxWsProxyFactoryBean.java:133)
    at org.apache.cxf.jaxws.spring.JaxWsProxyFactoryBeanDefinitionParser$JAXWSSpringClientProxyFactoryBean.create(JaxWsProxyFactoryBeanDefinitionParser.java:78)
    at org.apache.cxf.jaxws.spring.JaxWsProxyFactoryBeanDefinitionParser$JAXWSSpringClientProxyFactoryBean.getObject(JaxWsProxyFactoryBeanDefinitionParser.java:82)
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:168)
    ... 40 more

我怎样才能做到这一点?

@JsonUnwrapped@JsonAutoDetect 应该可以帮到你。查看文档:https://github.com/FasterXML/jackson-annotations/wiki/Jackson-Annotations

您可以编写自定义序列化程序并使用自定义序列化程序注释您的 MyClass,例如

public class CustomSerializer extends JsonSerializer<MyClass> {


    @Override
    public void serialize(MyClass myClass, JsonGenerator generator,
                          SerializerProvider provider) throws IOException {

        String dateString = String.valueOf(myClass.getDateTime().getMillis());
        generator.writeString(dateString);
    }
}

@JsonSerialize(using = CustomSerializer.class)
public class MyClass {

    private DateTime dateTime = new DateTime();
    ...

    public DateTime getDateTime() {
        return dateTime;
    }

    public void setDateTime(DateTime dateTime) {
        this.dateTime = dateTime;
    }
}

不确定 class 中字段的确切类型,但您明白了要点