Пользовательские json сериализация java примитивов от kotlin от Джексона - PullRequest
1 голос
/ 03 июня 2019

В моем проекте есть модули java и kotlin. В каком-то модуле kotlin мне нужна пользовательская сериализация. Все длинные значения должны быть сериализованы в виде строки. Я использую Джексона.

Пример:

Котлин

data class KotlinRecord(val id: Long)

Java

public class JavaRecord {
    private Long id;

    public Long getId() {
        return id;
    }

    public JavaRecord setId(Long id) {
        this.id = id;
        return this;
    }
}

Когда ObjectMapper настроен в java модуле, и я сериализирую значение следующим образом:

 ObjectMapper mapper = new ObjectMapper()
            .registerModule(new KotlinModule())
            .registerModule(new JavaTimeModule())
            .registerModule(
                    new SimpleModule()
                            .addSerializer(Long.class, LongToStringJSONSerializer.ofObject())
                            .addSerializer(long.class, LongToStringJSONSerializer.ofPrimitive())
            );

JavaRecord javaRecord = new JavaRecord().setId(Long.MAX_VALUE);
KotlinRecord kotlinRecord = new KotlinRecord(Long.MAX_VALUE);

System.out.println("Java record:   " + mapper.writeValueAsString(javaRecord));
System.out.println("Kotlin record: " + mapper.writeValueAsString(kotlinRecord));

Я получаю следующий результат:

Java record:   {"id":"9223372036854775807"}
Kotlin record: {"id":"9223372036854775807"}

Всё хорошо. Это то что мне нужно.

Но если я сделаю то же самое в kotlin модуле, как это:

val mapper = ObjectMapper()
        .registerModule(KotlinModule())
        .registerModule(JavaTimeModule())
        .registerModule(
                SimpleModule()
                        .addSerializer(Long::class.java, LongToStringJSONSerializer.ofObject())
                        .addSerializer(Long::class.javaPrimitiveType, LongToStringJSONSerializer.ofPrimitive())
        )

val javaRecord = JavaRecord().setId(Long.MAX_VALUE)
val kotlinRecord = KotlinRecord(Long.MAX_VALUE)

println("Java record:   ${mapper.writeValueAsString(javaRecord)}")
println("Kotlin record: ${mapper.writeValueAsString(kotlinRecord)}")

Я получаю:

Java record:   {"id":9223372036854775807}
Kotlin record: {"id":"9223372036854775807"}

Для записи, определенной как класс java, длинное значение не было передано в строку.

Мой пользовательский сериализатор:

public class LongToStringJSONSerializer extends JsonSerializer<Long> {
    private boolean forPrimitive;

    private LongToStringJSONSerializer(boolean forPrimitive) {
        this.forPrimitive = forPrimitive;
    }

    @Override
    public void serialize(Long longVal, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws
            IOException {
        jsonGenerator.writeObject(longVal == null ? "" : String.valueOf(longVal));
    }

    @Override
    public Class<Long> handledType() {
        return forPrimitive ? long.class : Long.class;
    }

    public static LongToStringJSONSerializer ofPrimitive() {
        return new LongToStringJSONSerializer(true);
    }

    public static LongToStringJSONSerializer ofObject() {
        return new LongToStringJSONSerializer(false);
    }
} 

Может кто-нибудь объяснить это поведение и что нужно сделать, чтобы исправить это? Спасибо!

1 Ответ

1 голос
/ 03 июня 2019

Проблема была в неправильном типе сериализации.

Object mapper должен быть определен так:

val mapper = ObjectMapper()
        .registerModule(KotlinModule())
        .registerModule(JavaTimeModule())
        .registerModule(
                SimpleModule()
                        .addSerializer(Long::class.javaPrimitiveType, LongToStringJSONSerializer.ofObject())
                        .addSerializer(Long::class.javaObjectType, LongToStringJSONSerializer.ofPrimitive())
        )

Я пропустил Long::class.javaObjectType

...