序列化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”,但它没有任何区别。 我们应该如何序列化“代理”?
答案 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
}
为
公共抽象类为
超类型(已声明类型,它本身是运行时的超类型 类型)定位要使用的序列化程序时用作类型。
答案 2 :(得分:0)
我不确定这是否有效,但在另一种情况下它对我有用。 您可以尝试在Jobstatus类上使用@Configurable(配置了AspectJ编织)并在控制器中创建新的作业状态实例。每当调用JObStatus的新实例时,Spring都会注入bean。然后,您可以照常序列化jobstatus对象。
答案 3 :(得分:0)
如果您只接受通过公共getter方法获取序列化的字段,则可以将Jackson配置为忽略非公共字段。这导致代理字段未被序列化:
在那里设置了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;
}
}