From ca06582f2af2e31b23031d8650148d95129ce4a1 Mon Sep 17 00:00:00 2001 From: Sebastien Deleuze Date: Thu, 2 Apr 2015 10:53:35 +0200 Subject: [PATCH] Support Jackson @JsonFilter This commit adds a filters property to MappingJacksonValue and also manages a special FilterProvider class name model key in order to be able to specify a customized FilterProvider for each handler method execution, and thus provides a more dynamic alternative to our existing JsonView support. A filters property is also now available in Jackson2ObjectMapperBuilder and Jackson2ObjectMapperFactoryBean in order to set easily a global FilterProvider. More details about @JsonFilter at http://wiki.fasterxml.com/JacksonFeatureJsonFilter. Issue: SPR-12586 --- .../AbstractJackson2HttpMessageConverter.java | 8 ++- .../json/Jackson2ObjectMapperBuilder.java | 17 ++++++ .../json/Jackson2ObjectMapperFactoryBean.java | 13 ++++- .../converter/json/MappingJacksonValue.java | 27 +++++++++- .../Jackson2ObjectMapperBuilderTests.java | 52 ++++++++++++++++++ .../Jackson2ObjectMapperFactoryBeanTests.java | 47 ++++++++++++++++ ...pingJackson2HttpMessageConverterTests.java | 48 ++++++++++++++++- .../view/json/AbstractJackson2View.java | 10 +++- .../view/json/MappingJackson2JsonView.java | 6 ++- .../json/MappingJackson2JsonViewTests.java | 53 +++++++++++++++++++ 10 files changed, 274 insertions(+), 7 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java index 73f930a7a3..5bdb5bb880 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/json/AbstractJackson2HttpMessageConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,6 +28,7 @@ import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.ser.FilterProvider; import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpOutputMessage; @@ -218,15 +219,20 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractHttpM try { writePrefix(generator, object); Class serializationView = null; + FilterProvider filters = null; Object value = object; if (value instanceof MappingJacksonValue) { MappingJacksonValue container = (MappingJacksonValue) object; value = container.getValue(); serializationView = container.getSerializationView(); + filters = container.getFilters(); } if (serializationView != null) { this.objectMapper.writerWithView(serializationView).writeValue(generator, value); } + else if (filters != null) { + this.objectMapper.writer(filters).writeValue(generator, value); + } else { this.objectMapper.writeValue(generator, value); } diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java index d0871c8628..04acdc8631 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java +++ b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java @@ -27,6 +27,7 @@ import java.util.Locale; import java.util.Map; import java.util.TimeZone; +import com.fasterxml.jackson.annotation.JsonFilter; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; @@ -42,6 +43,7 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategy; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.cfg.HandlerInstantiator; import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.ser.FilterProvider; import com.fasterxml.jackson.dataformat.xml.XmlMapper; import org.springframework.beans.BeanUtils; @@ -109,6 +111,8 @@ public class Jackson2ObjectMapperBuilder { private HandlerInstantiator handlerInstantiator; + private FilterProvider filters; + private ApplicationContext applicationContext; @@ -486,6 +490,16 @@ public class Jackson2ObjectMapperBuilder { return this; } + /** + * Set the global filters to use in order to support {@link JsonFilter @JsonFilter} annotated POJO. + * @since 4.2 + * @see MappingJacksonValue#setFilters(FilterProvider) + */ + public Jackson2ObjectMapperBuilder filters(FilterProvider filters) { + this.filters = filters; + return this; + } + /** * Set the Spring {@link ApplicationContext} in order to autowire Jackson handlers ({@link JsonSerializer}, * {@link JsonDeserializer}, {@link KeyDeserializer}, {@code TypeResolverBuilder} and {@code TypeIdResolver}). @@ -593,6 +607,9 @@ public class Jackson2ObjectMapperBuilder { if (this.handlerInstantiator != null) { objectMapper.setHandlerInstantiator(this.handlerInstantiator); } + if (this.filters != null) { + objectMapper.setFilters(this.filters); + } else if (this.applicationContext != null) { objectMapper.setHandlerInstantiator( new SpringHandlerInstantiator(this.applicationContext.getAutowireCapableBeanFactory())); diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.java b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.java index 0058b0f74c..df61ee49be 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.java +++ b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ import java.util.Locale; import java.util.Map; import java.util.TimeZone; +import com.fasterxml.jackson.annotation.JsonFilter; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.AnnotationIntrospector; import com.fasterxml.jackson.databind.DeserializationFeature; @@ -35,6 +36,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.PropertyNamingStrategy; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.cfg.HandlerInstantiator; +import com.fasterxml.jackson.databind.ser.FilterProvider; import com.fasterxml.jackson.dataformat.xml.XmlMapper; import org.springframework.beans.factory.BeanClassLoaderAware; @@ -373,6 +375,15 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean serializationView; + private FilterProvider filters; + private String jsonpFunction; @@ -81,6 +85,27 @@ public class MappingJacksonValue { return this.serializationView; } + /** + * Set the Jackson filter provider to serialize the POJO with. + * @since 4.2 + * @see com.fasterxml.jackson.databind.ObjectMapper#writer(FilterProvider) + * @see com.fasterxml.jackson.annotation.JsonFilter + * @see Jackson2ObjectMapperBuilder#filters(FilterProvider) + */ + public void setFilters(FilterProvider filters) { + this.filters = filters; + } + + /** + * Return the Jackson filter provider to use. + * @since 4.2 + * @see com.fasterxml.jackson.databind.ObjectMapper#writer(FilterProvider) + * @see com.fasterxml.jackson.annotation.JsonFilter + */ + public FilterProvider getFilters() { + return this.filters; + } + /** * Set the name of the JSONP function name. */ diff --git a/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java b/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java index c083a0595e..e8b29ac285 100644 --- a/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java +++ b/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java @@ -27,6 +27,7 @@ import java.util.Locale; import java.util.Map; import java.util.TimeZone; +import com.fasterxml.jackson.annotation.JsonFilter; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; @@ -52,10 +53,13 @@ import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.module.SimpleSerializers; import com.fasterxml.jackson.databind.ser.BasicSerializerFactory; import com.fasterxml.jackson.databind.ser.Serializers; +import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; +import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; import com.fasterxml.jackson.databind.ser.std.ClassSerializer; import com.fasterxml.jackson.databind.ser.std.NumberSerializer; import com.fasterxml.jackson.databind.type.SimpleType; import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import static org.hamcrest.Matchers.containsString; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.junit.Test; @@ -329,6 +333,22 @@ public class Jackson2ObjectMapperBuilderTests { assertSame(mixInSource, objectMapper.findMixInClassFor(target)); } + @Test + public void filters() throws JsonProcessingException { + ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json() + .filters(new SimpleFilterProvider().setFailOnUnknownId(false)).build(); + JacksonFilteredBean bean = new JacksonFilteredBean("value1", "value2"); + String output = objectMapper.writeValueAsString(bean); + assertThat(output, containsString("value1")); + assertThat(output, containsString("value2")); + + objectMapper = Jackson2ObjectMapperBuilder.json().filters((new SimpleFilterProvider().setFailOnUnknownId(false) + .setDefaultFilter(SimpleBeanPropertyFilter.serializeAllExcept("property2")))).build(); + output = objectMapper.writeValueAsString(bean); + assertThat(output, containsString("value1")); + assertThat(output, not(containsString("value2"))); + } + @Test public void completeSetup() throws JsonMappingException { NopAnnotationIntrospector annotationIntrospector = NopAnnotationIntrospector.instance; @@ -436,4 +456,36 @@ public class Jackson2ObjectMapperBuilderTests { } } + + @JsonFilter("myJacksonFilter") + public static class JacksonFilteredBean { + + public JacksonFilteredBean() { + } + + public JacksonFilteredBean(String property1, String property2) { + this.property1 = property1; + this.property2 = property2; + } + + private String property1; + private String property2; + + public String getProperty1() { + return property1; + } + + public void setProperty1(String property1) { + this.property1 = property1; + } + + public String getProperty2() { + return property2; + } + + public void setProperty2(String property2) { + this.property2 = property2; + } + } + } diff --git a/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBeanTests.java b/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBeanTests.java index c4ccaea1c1..52b70bb3a9 100644 --- a/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBeanTests.java +++ b/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBeanTests.java @@ -28,6 +28,7 @@ import java.util.Locale; import java.util.Map; import java.util.TimeZone; +import com.fasterxml.jackson.annotation.JsonFilter; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; @@ -51,6 +52,8 @@ import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.module.SimpleSerializers; import com.fasterxml.jackson.databind.ser.BasicSerializerFactory; import com.fasterxml.jackson.databind.ser.Serializers; +import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; +import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; import com.fasterxml.jackson.databind.ser.std.ClassSerializer; import com.fasterxml.jackson.databind.ser.std.NumberSerializer; import com.fasterxml.jackson.databind.type.SimpleType; @@ -314,6 +317,18 @@ public class Jackson2ObjectMapperFactoryBeanTests { assertSame(mixinSource, objectMapper.findMixInClassFor(target)); } + @Test + public void filters() throws JsonProcessingException { + this.factory.setFilters(new SimpleFilterProvider().setFailOnUnknownId(false)); + this.factory.afterPropertiesSet(); + ObjectMapper objectMapper = this.factory.getObject(); + + JacksonFilteredBean bean = new JacksonFilteredBean("value1", "value2"); + String output = objectMapper.writeValueAsString(bean); + assertThat(output, containsString("value1")); + assertThat(output, containsString("value2")); + } + @Test public void completeSetup() { NopAnnotationIntrospector annotationIntrospector = NopAnnotationIntrospector.instance; @@ -429,4 +444,36 @@ public class Jackson2ObjectMapperFactoryBeanTests { } } + + @JsonFilter("myJacksonFilter") + public static class JacksonFilteredBean { + + public JacksonFilteredBean() { + } + + public JacksonFilteredBean(String property1, String property2) { + this.property1 = property1; + this.property2 = property2; + } + + private String property1; + private String property2; + + public String getProperty1() { + return property1; + } + + public void setProperty1(String property1) { + this.property1 = property1; + } + + public String getProperty2() { + return property2; + } + + public void setProperty2(String property2) { + this.property2 = property2; + } + } + } diff --git a/spring-web/src/test/java/org/springframework/http/converter/json/MappingJackson2HttpMessageConverterTests.java b/spring-web/src/test/java/org/springframework/http/converter/json/MappingJackson2HttpMessageConverterTests.java index fe54972a71..cfe9bca095 100644 --- a/spring-web/src/test/java/org/springframework/http/converter/json/MappingJackson2HttpMessageConverterTests.java +++ b/spring-web/src/test/java/org/springframework/http/converter/json/MappingJackson2HttpMessageConverterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,9 +24,13 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import com.fasterxml.jackson.annotation.JsonFilter; import com.fasterxml.jackson.annotation.JsonView; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ser.FilterProvider; +import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; +import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; import org.junit.Test; import org.springframework.core.ParameterizedTypeReference; @@ -42,6 +46,7 @@ import static org.junit.Assert.*; * Jackson 2.x converter tests. * * @author Rossen Stoyanchev + * @author Sebastien Deleuze */ public class MappingJackson2HttpMessageConverterTests { @@ -258,6 +263,24 @@ public class MappingJackson2HttpMessageConverterTests { assertThat(result, not(containsString("\"withoutView\":\"without\""))); } + @Test + public void filters() throws Exception { + MockHttpOutputMessage outputMessage = new MockHttpOutputMessage(); + JacksonFilteredBean bean = new JacksonFilteredBean(); + bean.setProperty1("value"); + bean.setProperty2("value"); + + MappingJacksonValue jacksonValue = new MappingJacksonValue(bean); + FilterProvider filters = new SimpleFilterProvider().addFilter("myJacksonFilter", + SimpleBeanPropertyFilter.serializeAllExcept("property2")); + jacksonValue.setFilters(filters); + this.converter.writeInternal(jacksonValue, outputMessage); + + String result = outputMessage.getBodyAsString(Charset.forName("UTF-8")); + assertThat(result, containsString("\"property1\":\"value\"")); + assertThat(result, not(containsString("\"property2\":\"value\""))); + } + @Test public void jsonp() throws Exception { MappingJacksonValue jacksonValue = new MappingJacksonValue("foo"); @@ -407,4 +430,27 @@ public class MappingJackson2HttpMessageConverterTests { } } + @JsonFilter("myJacksonFilter") + private static class JacksonFilteredBean { + + private String property1; + private String property2; + + public String getProperty1() { + return property1; + } + + public void setProperty1(String property1) { + this.property1 = property1; + } + + public String getProperty2() { + return property2; + } + + public void setProperty2(String property2) { + this.property2 = property2; + } + } + } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/json/AbstractJackson2View.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/json/AbstractJackson2View.java index f326c718c8..8d256a4333 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/json/AbstractJackson2View.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/json/AbstractJackson2View.java @@ -28,6 +28,7 @@ import com.fasterxml.jackson.core.JsonEncoding; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.ser.FilterProvider; import org.springframework.http.converter.json.MappingJacksonValue; import org.springframework.util.Assert; @@ -176,9 +177,11 @@ public abstract class AbstractJackson2View extends AbstractView { protected Object filterAndWrapModel(Map model, HttpServletRequest request) { Object value = filterModel(model); Class serializationView = (Class) model.get(JsonView.class.getName()); - if (serializationView != null) { + FilterProvider filters = (FilterProvider) model.get(FilterProvider.class.getName()); + if (serializationView != null || filters != null) { MappingJacksonValue container = new MappingJacksonValue(value); container.setSerializationView(serializationView); + container.setFilters(filters); value = container; } return value; @@ -205,16 +208,21 @@ public abstract class AbstractJackson2View extends AbstractView { writePrefix(generator, object); Class serializationView = null; + FilterProvider filters = null; Object value = object; if (value instanceof MappingJacksonValue) { MappingJacksonValue container = (MappingJacksonValue) value; value = container.getValue(); serializationView = container.getSerializationView(); + filters = container.getFilters(); } if (serializationView != null) { this.objectMapper.writerWithView(serializationView).writeValue(generator, value); } + else if (filters != null) { + this.objectMapper.writer(filters).writeValue(generator, value); + } else { this.objectMapper.writeValue(generator, value); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/json/MappingJackson2JsonView.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/json/MappingJackson2JsonView.java index 5209d3b704..347dba1882 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/json/MappingJackson2JsonView.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/json/MappingJackson2JsonView.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,6 +29,7 @@ import javax.servlet.http.HttpServletResponse; import com.fasterxml.jackson.annotation.JsonView; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ser.FilterProvider; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.http.converter.json.MappingJacksonValue; @@ -182,7 +183,8 @@ public class MappingJackson2JsonView extends AbstractJackson2View { Set modelKeys = (!CollectionUtils.isEmpty(this.modelKeys) ? this.modelKeys : model.keySet()); for (Map.Entry entry : model.entrySet()) { if (!(entry.getValue() instanceof BindingResult) && modelKeys.contains(entry.getKey()) && - !entry.getKey().equals(JsonView.class.getName())) { + !entry.getKey().equals(JsonView.class.getName()) && + !entry.getKey().equals(FilterProvider.class.getName())) { result.put(entry.getKey(), entry.getValue()); } } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/view/json/MappingJackson2JsonViewTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/view/json/MappingJackson2JsonViewTests.java index c57ed13f5b..f93331764a 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/view/json/MappingJackson2JsonViewTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/view/json/MappingJackson2JsonViewTests.java @@ -25,6 +25,7 @@ import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; +import com.fasterxml.jackson.annotation.JsonFilter; import com.fasterxml.jackson.annotation.JsonView; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JavaType; @@ -35,7 +36,12 @@ import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.cfg.SerializerFactoryConfig; import com.fasterxml.jackson.databind.ser.BeanSerializerFactory; +import com.fasterxml.jackson.databind.ser.FilterProvider; import com.fasterxml.jackson.databind.ser.SerializerFactory; +import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; +import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.not; import org.junit.Before; import org.junit.Test; import org.mozilla.javascript.Context; @@ -293,6 +299,29 @@ public class MappingJackson2JsonViewTests { assertFalse(content.contains(JsonView.class.getName())); } + @Test + public void renderSimpleBeanWithFilters() throws Exception { + TestSimpleBeanFiltered bean = new TestSimpleBeanFiltered(); + bean.setProperty1("value"); + bean.setProperty2("value"); + Map model = new HashMap(); + model.put("bindingResult", mock(BindingResult.class, "binding_result")); + model.put("foo", bean); + FilterProvider filters = new SimpleFilterProvider().addFilter("myJacksonFilter", + SimpleBeanPropertyFilter.serializeAllExcept("property2")); + model.put(FilterProvider.class.getName(), filters); + + view.setUpdateContentLength(true); + view.render(model, request, response); + + String content = response.getContentAsString(); + assertTrue(content.length() > 0); + assertEquals(content.length(), response.getContentLength()); + assertThat(content, containsString("\"property1\":\"value\"")); + assertThat(content, not(containsString("\"property2\":\"value\""))); + assertFalse(content.contains(FilterProvider.class.getName())); + } + @Test public void renderWithJsonpDefaultParameterName() throws Exception { Map model = new HashMap(); @@ -427,6 +456,30 @@ public class MappingJackson2JsonViewTests { } + @JsonFilter("myJacksonFilter") + private static class TestSimpleBeanFiltered { + + private String property1; + private String property2; + + public String getProperty1() { + return property1; + } + + public void setProperty1(String property1) { + this.property1 = property1; + } + + public String getProperty2() { + return property2; + } + + public void setProperty2(String property2) { + this.property2 = property2; + } + } + + @SuppressWarnings("serial") public static class DelegatingSerializerFactory extends BeanSerializerFactory { -- GitLab