Каков наилучший способ последовательной сериализации данных JSON с использованием JACKSON? - PullRequest
4 голосов
/ 13 февраля 2012

У меня бин определен так:

public static class TestBean {
    private String a;
    private Long b;

    public TestBean(String a, Long b) {
        this.a = a;
        this.b = b;
    }

    public String getA() {
        return a;
    }

    public Long getB() {
        return b;
    }

}

Это моделирует некоторый бизнес, и я не могу его реализовать (используя JPA). Некоторые из моих API позволяют пользователю получать представление этого сериализованного компонента в виде JSON с использованием Jackson (через JAX-RS), и я хотел бы добавить список связанных ссылок на это представление.

Обычная сериализация JSON Джексона будет (для a = "aa" и b = 2L):

{"a":"aa","b":2}

И я бы хотел, чтобы ссылки отображались как

{"a":"aa","b":2,
 "links":[{"rel":"rel","href":"href://"},{"rel":"rel2","href":"href://2"}]}

Возможное решение

Я бы не стал добавлять метод getLinks () в мой bean-компонент, он специфичен для этого представления.

Простое использование составного объекта приведет к сериализации, например:

{"data":{"a":"aa","b":2},"links":[{"rel":"rel","href":"href://"}]}

С которым я мог бы жить, но это не то, что я искал в конечном итоге.

Текущее решение

Я бы хотел избежать манипулирования строкой JSON или необходимости перезагружать ее в Map для вставки моих дополнительных значений. На данный момент решение, которое я придумала, кажется ужасно запутанным:

Текущее страшное решение:

//a composite view object
public abstract class AddedLinksView<K> {

    private final K resource;

    private final Link[] links;

    public AddedLinksView(K resource) {
        this.resource = resource;
        links = buildLinks(resource);

    }

    public abstract Link[] buildLinks(K resource);

    public K getResource() {
        return resource;
    }

    public Link[] getLinks() {
        return links;
    }

}

//a specific bean serializer
private static class RawBeanSerializer extends BeanSerializer {

    public RawBeanSerializer(BeanSerializerBase ser) {
        super(ser);
    }

    //this is like the standard serialize but without the start and end tags
    public void rawSerialize(Object bean, JsonGenerator jgen, SerializerProvider provider) throws IOException,
            JsonGenerationException {
        if (_propertyFilterId != null) {
            serializeFieldsFiltered(bean, jgen, provider);
        } else {
            serializeFields(bean, jgen, provider);
        }
    }

}

@Test
public void usingModule() throws Exception {
    // basic module metadata just includes name and version (both for troubleshooting; but name needs to be unique)
    SimpleModule module = new SimpleModule("EnhancedDatesModule", new Version(0, 1, 0, "alpha"));
    //adding a serializer for the composite view
    module.addSerializer(new JsonSerializer<AddedLinksView>() {

        @Override
        public Class<AddedLinksView> handledType() {
            return AddedLinksView.class;
        }

        @Override
        public void serialize(AddedLinksView value, JsonGenerator jgen, SerializerProvider provider)
                throws IOException, JsonProcessingException {
            jgen.writeStartObject();
            //looking up the bean serializer that will be used for my resource
            JsonSerializer<Object> ser = provider.findTypedValueSerializer(value.getResource().getClass(), true,
                    null);

            if (ser instanceof BeanSerializerBase) {
                //cloning it in a sub class that makes it possible to 'inline' the serialization
                RawBeanSerializer openSer = new RawBeanSerializer((BeanSerializerBase) ser);
                openSer.rawSerialize(value.getResource(), jgen, provider);
            }
            //adding my links
            jgen.writeArrayFieldStart("links");
            for (Link link : value.getLinks()) {
                jgen.writeObject(link);
            }
            jgen.writeEndArray();
            jgen.writeEndObject();
        }

    });

    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(module);

    AddedLinksView<TestBean> view = new AddedLinksView<TestBean>(new TestBean("aa", 2L)) {
        @Override
        public Link[] buildLinks(TestBean resource) {
            return new Link[] { new Link("rel", "href://"), new Link("rel2", "href://2") };
        }

    };

    System.out.println("useModule json output: " + mapper.writeValueAsString(view));
}

Я упустил что-то очевидное в Джексоне, чтобы добиться этого? Или я уже полностью не отвечаю требованиям?

Ответы [ 2 ]

3 голосов
/ 14 февраля 2012

Нет реального способа извне добавить вещи в POJO для сериализации: но вас может заинтересовать проверка @JsonAnyGetter, которая, по крайней мере, позволяет просто добавить содержимое java.util.Map в качестве дополнительных свойств для POJO.

0 голосов
/ 13 февраля 2012

Будет ли это ответить на ваш вопрос: http://wiki.fasterxml.com/JacksonFeatureUpdateValue

Я не уверен, что вы можете избежать картирования. Вы можете использовать Dozer, чтобы помочь.

Это должно помочь вам: Инструменты для объединения Java-бинов

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...