Пользовательский Сериализатор Джексона для Wrapper Object - PullRequest
2 голосов
/ 27 февраля 2012

У меня есть интерфейс провайдера

interface IProvider<T> {
    T locate();
}

и класс, содержащий поле типа IProvider (может быть другим типом для других полей).

class MyObject {
    MyLocator<String> field;
}

Мне нужно сериализовать экземплярыMyObject для JSON с использованием Jackson 1.7.Вывод должен быть таким же, как если бы MyObject.field был String (т.е. не ссылался на ILocator).

Я не могу понять, как создать собственный сериализатор, необходимый для этого.Вот структура, которую я пытаюсь использовать для этой задачи:

class MyLocatorSerializer extends SerializerBase<MyLocator<?>> {
    public MyLocatorSerializer() {
        super(MyLocator.class, false);
    }

    @Override
    public void serialize(MyLocator<?> a_value, JsonGenerator a_jgen,
            SerializerProvider a_provider) throws IOException, JsonGenerationException {
        // Insert code here to serialize a_value.locate(), whatever its type
    }

    @Override
    public JsonNode getSchema(SerializerProvider a_provider, Type a_typeHint)
            throws JsonMappingException {
        // What should I return here? I can't find documentation regarding the different schema types...
    }
}

Пользовательский сериализатор будет зарегистрирован с использованием

SimpleModule module = new SimpleModule("MyModule", new Version(1, 0, 0, null));
module.addSerializer(new MyLocatorSerializer());
objectMapper.registerModule(module);

Ответы [ 3 ]

3 голосов
/ 01 марта 2012

Еще один ответ с использованием дополнительных комментариев после комментария от Staxman.

static class JacksonCustomModule extends SimpleModule {
    public JacksonCustomModule() {
        super("JacksonCustomModule", new Version(1, 0, 0, null));
    }

    @Override
    public void setupModule(SetupContext context) {
        context.setMixInAnnotations(IProvider.class, IProviderMixIn.class);
        super.setupModule(context);
    }

    interface IProviderMixIn<T> {
        @JsonValue
        T locate();
    }
}

Активируйте модуль с помощью:

objectMapper.registerModule(new JacksonCustomModule());
2 голосов
/ 27 февраля 2012

Извиняюсь, если я неправильно понял вопрос, но будет ли это так же просто, как просто использовать @JsonValue в методе 'Locate' вместо написания собственного сериализатора? @JsonValue принимает значение свойства как есть и использует его вместо создания объекта JSON: часто это используется для сериализации POJO в виде простой строки или числа, например:

public class StringWrapper {
   @JsonValue public String value;
}

так что для класса вроде:

public class POJO {
   public StringWrapper wrapped;
}

мы получим сериализацию как:

{
  "wrapper" : "string value of 'value'"
}

вместо того, что было бы иначе:

{
   "wrapper" : {
      "value" : "... string value ... "
   }
}

Аннотация может использоваться для любых типов значений, очевидно.

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

После ответа StaxMan я проверил работу @JsonValue и получил следующий сериализатор:

// Based on JsonValueSerializer
private static class ProviderSerializer extends SerializerBase<IProvider<?>> {

    public ProviderSerializer() {
        super(IProvider.class, false);
    }

    @Override
    public void serialize(IProvider<?> value, JsonGenerator jgen, SerializerProvider provider)
            throws IOException, JsonGenerationException {
        Object object = value.locate();

        // and if we got null, can also just write it directly
        if (object == null) {
            provider.defaultSerializeNull(jgen);
            return;
        }

        Class<?> c = object.getClass();
        JsonSerializer<Object> ser = provider.findTypedValueSerializer(c, true, null);
        // note: now we have bundled type serializer, so should NOT call with typed version
        ser.serialize(object, jgen, provider);
    }

    @Override
    public JsonNode getSchema(SerializerProvider provider, Type typeHint)
            throws JsonMappingException {
        // is this right??
        return JsonSchema.getDefaultSchemaNode();
    }
}

После некоторых тестов это делает то, что мне нужно.Тем не менее, я не совсем понимаю цель метода getSchema, поэтому, возможно, я делаю что-то не так ...

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