¿Hay una manera genérica para deserializar objetos de valor de un solo valor (sin encargo deserializador) en Jackson

Marc von Renteln:

Utilizamos una gran cantidad de objetos de valor con un solo valor. Para la serialización (des) utilizamos Jackson con el Kotlin-módulo.

Un objeto de valor de ejemplo en Kotlin:

data class MyValueObject(val value: String)

o como Java

class MyValueObject {
 private String value;

 public MyValueObject(String value) { this.value = value; }

 public String getValue() { return value; }
}

Estos objetos de valor tienen que ser serializado y deserializado y deben ser serializado "valor único", por ejemplo. "theValue"en lugar de "{"value":"theValue"}".

Me gustaría evitar escribir serializadores personalizados / deserializadores para objetos de valor de decenas.

Sé que para la serialización @JsonValuepuede ser utilizado para darse cuenta de lo anterior.

data class MyValueObject(@JsonValue val value: String)

Pero el JSON "" theValue "" (lo anterior serializado literal-serie) no puede ser deserializado espalda MyValueObject. Se sesults en la siguiente excepción:

com.fasterxml.jackson.databind.exc.MismatchedInputException: 
Cannot construct instance of `[...].MyValueObject` (although at least one Creator exists): 
no String-argument constructor/factory method to deserialize from String value ('test')
 at [Source: (String)""test""; line: 1, column: 1]

Aquí está la unidad de prueba que utiliza:

@Test
fun testSerialize() {
    val objectMapper = ObjectMapper()
        .registerModule(Jdk8Module())
        .registerModule(KotlinModule())
    val test = MyValueObject("test")
    val json = objectMapper.writeValueAsString(test)
    println(json)
    objectMapper.readValue<MyValueObject>(json)
}

¿Hay una manera sencilla / genérico para deserializar estos como @JsonValuepara serializar?

PD: Una solución de trabajo (gracias a @LppEdd) es:

data class MyValueObject (@JsonValue val value: String) {

    companion object {
        @JvmStatic
        @JsonCreator
        fun create(value: String) = MyValueObject(value)
    }
}

Pero esto es muy detallado. @JsonCreator anotada sobre el constructor no funcionó para mí (ver mi comentario sobre la respuesta de @LppEdd)

LppEdd:

Claro, y es bastante simple.
Sólo tiene que añadir @JsonCreatoral constructor.

class MyValueObject {
  private String value;

  @JsonCreator
  public MyValueObject(String value) { this.value = value; }

  @JsonValue
  public String getValue() { return value; }
}

O para Kotlin que tendría, supongo

data class MyValueObject @JsonCreator constructor(@JsonValue val value: String)

Cuando se utiliza @JsonCreator sin prefijar el parámetro constructor

@JsonProperty("fieldName")

Jackson le dice a pasar toda la cadena JSON, que en su caso es sólo un valor de "primitivo".


Al parecer no le gusta Kotlin pares de captadores / definidores generados automáticamente.
Esto funciona, por ejemplo,

class MyValueObject @JsonCreator constructor(private val value: String) {
    @JsonValue
    fun getValue() = value
}

Además, después de un poco de depuración, descubrí el problema se plantea aquí

@Override
public Boolean hasAsValue(Annotated a) {
    JsonValue ann = _findAnnotation(a, JsonValue.class);
    if (ann == null) {
        return null;
    }
    return ann.value();
}

Al JacksonAnnotationIntrospector.

No sé por qué, pero Jackson todavía busco una @JsonValueanotación en un público campo o en un público comprador. Kotlin coloca la anotación en la privada de campo, por lo que Jackson no puede encontrarlo.

La solucion es

data class MyValueObject @JsonCreator constructor(@JvmField @JsonValue val value: String)

o mejor

data class MyValueObject @JsonCreator constructor(@get:JsonValue val value: String)

Como escribió Marc von Renteln en los comentarios, también se puede omitir @JsonCreator

data class MyValueObject(@get:JsonValue val value: String)

Lo que parece indocumentado, sin embargo. Si alguien puede señalar donde se describe este comportamiento, que sería increíble!

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=185024&siteId=1
Recomendado
Clasificación