spring序列化autowired字段

时间:2016-01-14 10:06:56

标签: json spring serialization jackson autowired

序列化spring托管bean时遇到问题。

我想返回一个autowired bean作为restcontroller的响应。我已经阅读了几个回复,其中一个建议使用simpleFilter。(Use SimpleFilter to exclude non required fields.)。但是我不认为这个建议很实用,而且我相信有一个更简单,更具体的方法来解决这个问题。

我有一个名为JobStatus的Spring托管bean。

@Component
@Scope(value="Prototype")
public class JobStatus{

    private Integer job_type;

    public Integer getJob_type() {
        return job_type;
    }

    public void setJob_type(Integer job_type) {
        this.job_type = job_type;
    }


    public JobStatus(){

    }
}

我有一个控制器如下:

@RestController
public class JobController  {

@Autowired 
JobStatus js;

@RequestMapping(value = "/get_job_status", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody
JobStatus get_job_status(@RequestBody JobStatusRequest  req) {


    js.setJobType(req.getJobType);


    ObjectMapper mapper = new ObjectMapper();

    try {
        System.out.println(mapper.writeValueAsString(js));
    } catch (JsonProcessingException e) {

        e.printStackTrace();
    }



    return js;

}

}

抛出以下异常:

com.fasterxml.jackson.databind.JsonMappingException:找不到类org.springframework.cglib.proxy.NoOp $ 1的序列化程序,并且没有发现创建BeanSerializer的属性(为了避免异常,禁用SerializationFeature.FAIL_ON_EMPTY_BEANS))(通过参考链) :ATM.Job.JobStatus $$ EnhancerBySpringCGLIB $$ be675215 [“callbacks”])

我已经尝试将JobStatus的范围更改为“singleton”和“session”以及“request”,但它没有任何区别。 我们应该如何序列化“代理”?

4 个答案:

答案 0 :(得分:1)

创建一个视图类

public class JobStatusView {

    public JobStatusView(JobStatus js) {
        job_type = js.getJob_type();
    }

    private Integer job_type;

    public Integer getJob_type() {
        return job_type;
    }

    public void setJob_type(Integer job_type) {
        this.job_type = job_type;
    }
}

让您的控制器方法返回new JobStatusView(js)或创建Factory类或创建实例的首选方法。

这样可以将数据与视图分开。如果需要,您可以稍后在视图类中添加任何Jackson注释,而不必将它们堆积到原始bean中。

答案 1 :(得分:1)

您可以告诉Jackson:“使用与超类型相同的类型来序列化我的课程”。由于Spring代理继承了您的原始类,因此这似乎至少在Spring Boot 2.0.4.RELEASE上有效:

@JsonSerialize(as=MyCompontClass.class)
@Component
public class MyCompontClass{
    // fields, getters, setters
}

Jackson API docs说:

  

     

公共抽象类为

     

超类型(已声明类型,它本身是运行时的超类型   类型)定位要使用的序列化程序时用作类型。

答案 2 :(得分:0)

我不确定这是否有效,但在另一种情况下它对我有用。 您可以尝试在Jobstatus类上使用@Configurable(配置了AspectJ编织)并在控制器中创建新的作业状态实例。每当调用JObStatus的新实例时,Spring都会注入bean。然后,您可以照常序列化jobstatus对象。

答案 3 :(得分:0)

如果您只接受通过公共getter方法获取序列化的字段,则可以将Jackson配置为忽略非公共字段。这导致代理字段未被序列化:

  • 在类路径的某处将@Configuration bean添加到Spring的Application.java类所在的包中:
  • 在那里设置了ObjectMapper属性

    objectMapper.setVisibility(PropertyAccessor.ALL,                               JsonAutoDetect.Visibility.NONE);    objectMapper.setVisibility(PropertyAccessor.GETTER,                               JsonAutoDetect.Visibility.PUBLIC_ONLY);

这是一个完整的课程:

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import 
 org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import
 org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

@Configuration
public class JacksonConfig extends WebMvcConfigurerAdapter {

    @Bean
    @Primary
    public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
        setup(objectMapper);
        return objectMapper;
    }

    public void setup(ObjectMapper objectMapper) {

        objectMapper.setVisibility(PropertyAccessor.ALL,                    
                            JsonAutoDetect.Visibility.NONE);
        objectMapper.setVisibility(PropertyAccessor.GETTER, 
                            JsonAutoDetect.Visibility.PUBLIC_ONLY);

    }

    @Override
    public void configureMessageConverters(
                  List<HttpMessageConverter<?>> converters) {
        final MappingJackson2HttpMessageConverter converter = 
              getMappingJackson2HttpMessageConverter();

        converters.add(converter);
        super.configureMessageConverters(converters);
    }

    @Bean
    @Primary
    public MappingJackson2HttpMessageConverter
 getMappingJackson2HttpMessageConverter() {
        final MappingJackson2HttpMessageConverter converter = new 
                  MappingJackson2HttpMessageConverter();
        final ObjectMapper objectMapper = new ObjectMapper();

        setup(objectMapper);

        converter.setObjectMapper(objectMapper);
        converter.setPrettyPrint(true);
        return converter;
    }
}