0

What I would like to do is serialize the People object having a list of only summary persons and a single person detail record. Person includes nested objects like Name (included in summary) and Address (which is detail only). And I need the internal Spring ObjectMapper configured to do this serialization. I've tried to do some things with @JsonView and @JsonFilter, but not finding the right path forward. I've also tried to provide my own custom ObjectMapper, and I can through its construction when my container is started, but at runtime I get errors that no filter with id "summary" has been configured.

I'm asking why the setFilter(...) did not seem to take effect during runtime, it's as if my customer ObjectMapper was constructed but not being used? The rest of my implementation can be ignored, as I am not at all sure I am on the right path. But, in case it helps...

  • I put @JsonFilter("summary") on Person
  • I put @JsonView(Views.Summary.class) on select properties within Person
  • I did not make use of Json Views, only used the annotation as a marker that my filter, which I can't get to execute, attempted to look for and then serialize the attribute if found.
  • I discovered filters are not applied to List's, so...

How can I do this?

public class People
{
    @JsonProperty("persons")
    // A list of persons, summary info only
    private List<Person> persons;

    @JsonProperty("person")
    // A single, full detail person
    private Person person;
}


<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
        <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
        <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
            <property name="objectMapper" ref="myObjectMapper" />
        </bean>        
    </mvc:message-converters>
</mvc:annotation-driven>
<bean id="myObjectMapper" class="this.that.MyObjectMapper" />

public class MyObjectMapper extends ObjectMapper {
    public MyObjectMapper() {
        super();

        Set<Class<?>> views = new HashSet<Class<?>>();
        views.add(Views.Summary.class);

        FilterProvider filters = new SimpleFilterProvider()
                .addFilter("summary", new FilterExceptViewFilter(views));

        setFilters(filters);
    }
}
kenshinji
  • 2,021
  • 4
  • 25
  • 39
03T
  • 49
  • 1
  • 10

1 Answers1

0

I was perhaps making it too hard, or at least had to think about my problem differently. This question was my primary inspiration. What I needed was:

  • Different serialization for my object's properties
  • Different serialization implies creating a custom JsonSerializer / @JsonSerialize
  • A custom serializer that chooses the correct JsonView to serialize with.

What I ended up with was fairly simple:

public class Views
{
    public static class Summary {}
    public static class Detail extends Summary {}
}

public class Model
{
    // Not marked with @JsonView - always serialized
    @JsonProperty("id")
    private String id;
}

public class Person extends Model
{
    @JsonView(Views.Detail.class)
    @JsonProperty("internalId")
    private String internalId;

    @JsonView(Views.Detail.class)
    @JsonProperty("tin")
    private Tin tin;

    @JsonView(Views.Summary.class)
    @JsonProperty("name")
    private Name name;
}

public class People
{
    @JsonSerialize(using = SummaryViewListSerializer.class)
    @JsonProperty("persons")
    private List<Person> persons;

    @JsonProperty("person")
    private Person person;
}

public class SummaryViewListSerializer extends JsonSerializer<List<Object>>
{
    @Override
    public void serialize(final List<Object> list, final JsonGenerator gen, final SerializerProvider serializers) throws IOException {
        ObjectMapper mapper = new MyObjectMapper();
        // By design, explicitly set mapper to serialize all parameters not explicitly set with @JsonView
        mapper.enable(SerializationConfig.Feature.DEFAULT_VIEW_INCLUSION);
        mapper.setSerializationConfig(mapper.getSerializationConfig().withView(Views.Summary.class));

        gen.writeStartArray();
        for (Object item : list) {
            mapper.writeValue(gen, item);
        }
        gen.writeEndArray();
    }
}

If I also needed to serialize person in summary form, I could implement a SummaryViewSerializer and mark the property to use that.

Community
  • 1
  • 1
03T
  • 49
  • 1
  • 10