杰克逊忽视了班级序列化的吸气

时间:2018-03-08 13:41:28

标签: spring serialization jackson dto ignore

我试图序列化一个我无法触及任何内容的课程。问题是我想忽略一些 getWhatever() getter方法,但我不能用 @JsonIgnore 标记getter方法,因为这意味着要触及DTO类。

该序列化是在Spring REST Web服务上通过 @RestController 方法进行的,所以如果它可以成为一个解决方案,那就太棒了。

我想到了一个我不喜欢的解决方案......它会为我要序列化的DTO类创建一个自定义序列化器,所以我可以控制什么序列化,什么不是,然后,来自 @RestController ,而不是返回DTO类(我认为这更优雅),在获取带有 ObjectMapper的JSON字符串后返回 String 并强制使用自定义序列化程序。

我不喜欢这个解决方案:

  • 我必须为每个需要序列化的DTO类创建一个自定义序列化器,它具有我不想序列化的getter方法
  • 我不喜欢返回表示代表DTO的JSON的字符串的解决方案...我更喜欢透明地执行此操作并从方法返回DTO类并让Spring的自动化生成该转换< / LI>

提前感谢您...非常感谢任何帮助

编辑(解决方案) 由于@Cassio Mazzochi Molin的想法,我终于采用了这个解决方案:

interface FooMixIn {
    @JsonIgnore
    Object getFoo();
    @JsonIgnore
    Object getBar();
}

@Service
public class ServiceFooSerializer extends SimpleModule{
    public ServiceFooSerializer(){
        this.setMixInAnnotation(Foo.class, FooMixIn.class);
    }
}

2 个答案:

答案 0 :(得分:1)

this answer的帮助下并基于Spring Boot Example

这是一个看起来相同的DTO1和DTO2类(getter和setter未显示):

public class DTO1 {

    private String property1;
    private String property2;
    private String property3;

这是一个用于测试的控制器:

@RestController
public class HelloController {

    @RequestMapping("/dto1")
    public ResponseEntity<DTO1> dto1() {
        return new ResponseEntity<DTO1>(new DTO1("prop1", "prop2", "prop3"), HttpStatus.OK);
    }

    @RequestMapping("/dto2")
    public ResponseEntity<DTO2> dto2() {
        return new ResponseEntity<DTO2>(new DTO2("prop1", "prop2", "prop3"), HttpStatus.OK);
    }

}

这是我的WebConfig

@Configuration
public class WebConfig extends WebMvcConfigurationSupport {

    @Bean
    public MappingJackson2HttpMessageConverter customJackson2HttpMessageConverter() {
        MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = new ObjectMapper();
        MyBeanSerializerFactory customSerializationFactory = new MyBeanSerializerFactory(new SerializerFactoryConfig());
        customSerializationFactory.getClasses().add(DTO1.class);
        customSerializationFactory.getFieldsToIgnore().add("property2");
        objectMapper.setSerializerFactory(customSerializationFactory);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        jsonConverter.setObjectMapper(objectMapper);
        return jsonConverter;
    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(customJackson2HttpMessageConverter());
    }
}

这是自定义BeanserializerFactory:

public class MyBeanSerializerFactory extends BeanSerializerFactory {

    private Set<Class> classes = new HashSet<>();
    private Set<String> fieldsToIgnore = new HashSet<>();

    protected MyBeanSerializerFactory(SerializerFactoryConfig config) {
        super(config);
        // TODO Auto-generated constructor stub
    }

    public Set<Class> getClasses() {
        return classes;
    }

    public Set<String> getFieldsToIgnore() {
        return fieldsToIgnore;
    }

    @Override
    protected void processViews(SerializationConfig config, BeanSerializerBuilder builder) {
        super.processViews(config, builder);

        // ignore fields only for concrete class
        // note, that you can avoid or change this check
        if (classes.contains(builder.getBeanDescription().getBeanClass())) {
            // get original writer
            List<BeanPropertyWriter> originalWriters = builder.getProperties();

            // create actual writers
            List<BeanPropertyWriter> writers = new ArrayList<BeanPropertyWriter>();

            for (BeanPropertyWriter writer : originalWriters) {
                String propName = writer.getName();
                // if it isn't ignored field, add to actual writers list
                if (!fieldsToIgnore.contains(propName)) {
                    writers.add(writer);
                }
            }

            builder.setProperties(writers);
        }

    }
}

这是一个测试,显示从DTO1中删除的属性2,但不是DTO2:

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class HelloControllerTest {

    @Autowired
    private MockMvc mvc;

    @Test
    public void test1() throws Exception {
        mvc.perform(MockMvcRequestBuilders.get("/dto1").accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
                .andExpect(content().string(equalTo("{\"property1\":\"prop1\",\"property3\":\"prop3\"}")));

        mvc.perform(MockMvcRequestBuilders.get("/dto2").accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
                .andExpect(content()
                        .string(equalTo("{\"property1\":\"prop1\",\"property2\":\"prop2\",\"property3\":\"prop3\"}")));
    }
}

有关上述代码,请参阅https://github.com/gregclinker/json-mapper-example

答案 1 :(得分:1)

如果无法修改类,则可以使用混合注释

您可以将其视为在运行时添加更多注释的面向方面的方式,以增加静态定义的注释。

首先定义一个混合注释界面(一个类也可以):

public interface FooMixIn {

    @JsonIgnore
    Object getWhatever();
}

然后配置ObjectMapper以将定义的界面用作POJO的混合:

ObjectMapper mapper = new ObjectMapper().addMixIn(Foo.class, FooMixIn.class); 

一些使用注意事项:

  • 杰克逊认可的所有annotation sets都可以混合进来。
  • 可以混合使用各种注释(成员方法,静态方法,字段,构造函数注释)。
  • 只有方法(和字段)名称和签名用于匹配注释:访问定义(privateprotected,...)和方法实现被忽略。

有关详细信息,请查看杰克逊documentation