代码之家  ›  专栏  ›  技术社区  ›  Pep Gomez

Jackson忽略类序列化中的getter

  •  5
  • Pep Gomez  · 技术社区  · 7 年前

    我正在尝试序列化一个类,在这个类上我无法触及任何内容。问题是我想忽略一些 getWhatever() getter方法,但我无法将getter方法标记为 @杰索尼诺 ,因为这意味着要接触DTO类。

    正在从 @RestController 方法,所以如果考虑到这一点,这将是一个很好的解决方案。

    我想到了一个我不喜欢的解决方案。。。它将为我要序列化的DTO类创建一个自定义序列化程序,以便我可以控制哪些被序列化,哪些不被序列化,然后从 @RestController ,而不是返回DTO类(我认为这更优雅),而是返回 一串 获取JSON字符串后 ObjectMapper 以及强制自定义序列化程序。

    我不喜欢这种解决方案,因为:

    • 我必须为每个需要序列化的DTO类创建一个自定义序列化程序,该类具有我不想序列化的getter方法
    • 我不喜欢返回一个代表JSON的字符串来表示DTO的解决方案。。。我更喜欢透明地这样做,并从方法中返回DTO类,让Spring的自动化生成转换

    提前谢谢你。。。非常感谢您的帮助

    编辑(解决方案) 由于@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);
        }
    }
    
    3 回复  |  直到 3 年前
        1
  •  3
  •   cassiomolin    7 年前

    如果不能修改类,可以使用 混合注释 .

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

    首先在注释接口中定义一个混合(类也可以):

    public interface FooMixIn {
    
        @JsonIgnore
        Object getWhatever();
    }
    

    然后配置 ObjectMapper 要将定义的接口用作POJO的混合接口,请执行以下操作:

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

    一些使用注意事项:

    • 全部的 annotation sets 杰克逊认识到的可以混入其中。
    • 可以混合使用各种注释(成员方法、静态方法、字段、构造函数注释)。
    • 只有方法(和字段)名称和签名用于匹配注释:访问定义( private , protected , ...) 和方法实现被忽略。

    有关更多详细信息,请查看Jackson documentation .

        2
  •  1
  •   Essex Boy    7 年前

    在以下人员的帮助下 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);
        }
    
    }
    

    这是我的网络配置

    @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 对于上述代码。

        3
  •  0
  •   Sathish Kumar B    3 年前

    在这种情况下,如果有人需要单独忽略自定义getter(没有setter) 映射器。配置(MapperFeature.REQUIRE\u SETTERS\u FOR\u GETTERS,true)

    在序列化过程中,执行魔术。