Estoy experimentando combinando Jackson y Lombok. Esas son mis clases:
package testelombok;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Value;
import lombok.experimental.Wither;
@Value
@Wither
@AllArgsConstructor(onConstructor=@__(@JsonCreator))
public class TestFoo {
@JsonProperty("xoom")
private String x;
private int z;
}
package testelombok;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xebia.jacksonlombok.JacksonLombokAnnotationIntrospector;
import java.io.IOException;
public class TestLombok {
public static void main(String[] args) throws IOException {
TestFoo tf = new TestFoo("a", 5);
System.out.println(tf.withX("b"));
ObjectMapper om = new ObjectMapper().setAnnotationIntrospector(new JacksonLombokAnnotationIntrospector());
System.out.println(om.writeValueAsString(tf));
TestFoo tf2 = om.readValue(om.writeValueAsString(tf), TestFoo.class);
System.out.println(tf2);
}
}
Esos son los archivos JAR que estoy agregando a la clase:
Lombok: https://projectlombok.org/downloads/lombok.jar (versión 1.16.10)
Anotaciones de Jackson: http://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-annotations/2.8.2/jackson-annotations-2.8.2.jar
Núcleo de Jackson: http://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-core/2.8.2/jackson-core-2.8.2.jar
Enlace de datos de Jackson: http://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-databind/2.8.2/jackson-databind-2.8.2.jar
Jackson-lombok: http://repo1.maven.org/maven2/io/paradoxical/jackson-lombok/1.1/jackson-lombok-1.1.jar
Lo estoy compilando con Netbeans (no creo que esto sea realmente relevante, pero lo estoy informando de todos modos para que sea perfecta y fielmente reproducible). Los cinco JAR anteriores se guardan en una carpeta llamada " lib
" dentro de la carpeta del proyecto (junto con " src
", " nbproject
", " test
" y " build
"). Los agregué a Netbeans a través del botón " Agregar JAR / Carpeta " en las propiedades del proyecto y se enumeran en el orden exacto en la lista anterior. El proyecto es un proyecto de tipo "aplicación Java" estándar.
Además, el proyecto Netbeans está configurado para " NO compilar al guardar ", " generar información de depuración ", " informar API obsoletas ", " rastrear dependencias java ", " procesar anotaciones activacte " y " procesar anotaciones activacte en el editor ". No se configura explícitamente ningún procesador de anotaciones ni opción de procesamiento de anotaciones en Netbeans. Además, la -Xlint:all
opción de línea de " " comandos se pasa en la línea de comandos del compilador y el compilador se ejecuta en una máquina virtual externa.
La versión de mi javac es 1.8.0_72 y la versión de mi java es 1.8.0_72-b15. Mi Netbeans es 8.1.
Mi proyecto se compila bien. Sin embargo, arroja una excepción en su ejecución. La excepción no parece ser nada que parezca fácil o obviamente reparable. Aquí está la salida, incluido el stacktrace:
TestFoo(x=b, z=5)
{"z":5,"xoom":"a"}
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Argument #0 of constructor [constructor for testelombok.TestFoo, annotations: {interface java.beans.ConstructorProperties=@java.beans.ConstructorProperties(value=[x, z]), interface com.fasterxml.jackson.annotation.JsonCreator=@com.fasterxml.jackson.annotation.JsonCreator(mode=DEFAULT)}] has no property name annotation; must have name when multiple-parameter constructor annotated as Creator
at [Source: {"z":5,"xoom":"a"}; line: 1, column: 1]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:296)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:269)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:475)
at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:3890)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3785)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2833)
at testelombok.TestLombok.main(TestLombok.java:14)
Caused by: java.lang.IllegalArgumentException: Argument #0 of constructor [constructor for testelombok.TestFoo, annotations: {interface java.beans.ConstructorProperties=@java.beans.ConstructorProperties(value=[x, z]), interface com.fasterxml.jackson.annotation.JsonCreator=@com.fasterxml.jackson.annotation.JsonCreator(mode=DEFAULT)}] has no property name annotation; must have name when multiple-parameter constructor annotated as Creator
at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._addDeserializerConstructors(BasicDeserializerFactory.java:511)
at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._constructDefaultValueInstantiator(BasicDeserializerFactory.java:323)
at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.findValueInstantiator(BasicDeserializerFactory.java:253)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:219)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:141)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:406)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:352)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:264)
... 7 more
Ya intenté pinchar aleatoriamente con las anotaciones @Value
y @AllArgsConstructor
, pero no pude hacerlo mejor.
Busqué en Google la excepción y encontré un informe de error antiguo en Jackson , y otro que está abierto, pero parece estar relacionado con otra cosa . Sin embargo, esto todavía no dice nada sobre qué es este error o cómo solucionarlo. Además, no pude encontrar nada útil buscando eso en otro lado.
Dado que lo que estoy tratando de hacer es un uso muy básico tanto de lombok como de jackson, parece extraño que no haya podido encontrar más información útil sobre cómo solucionar este problema. ¿Quizás me perdí algo?
Aparte de simplemente decir " no use lombok " o " no use jackson ", ¿alguien tiene alguna idea sobre cómo resolver esto?
Immutable + Lombok + Jackson se puede lograr de la siguiente manera:
import com.fasterxml.jackson.databind.ObjectMapper; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import lombok.Value; @Value @NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) @AllArgsConstructor public class LocationDto { double longitude; double latitude; } class ImmutableWithLombok { public static void main(String[] args) throws Exception { ObjectMapper objectMapper = new ObjectMapper(); String stringJsonRepresentation = objectMapper.writeValueAsString(new LocationDto(22.11, 33.33)); System.out.println(stringJsonRepresentation); LocationDto locationDto = objectMapper.readValue(stringJsonRepresentation, LocationDto.class); System.out.println(locationDto); } }
fuente
AllArgsConstructor
ya parte de la@Value
anotación?@NoArgsConstructor
anula el constructor que es generado por la@Value
anotación, por lo que debe agregar el extra@AllArgsConstructor
Probé varios de los anteriores y todos fueron temperamentales. Lo que realmente funcionó para mí es la respuesta que encontré aquí .
en el directorio raíz de su proyecto agregue un archivo lombok.config (si aún no lo ha hecho)
y dentro pega esto
lombok.anyConstructor.addConstructorProperties=true
Entonces puedes definir tus pojos de la siguiente manera:
@Data @AllArgsConstructor public class MyPojo { @JsonProperty("Description") private String description; @JsonProperty("ErrorCode") private String errorCode; }
fuente
Tuve exactamente el mismo problema, lo "resolví" agregando el
suppressConstructorProperties = true
parámetro (usando su ejemplo):@Value @Wither @AllArgsConstructor(suppressConstructorProperties = true) public class TestFoo { @JsonProperty("xoom") private String x; private int z; }
A Jackson aparentemente no le gusta la
java.beans.ConstructorProperties
anotación agregada a los constructores. ElsuppressConstructorProperties = true
parámetro le dice a Lombok que no lo agregue (lo hace por defecto).fuente
suppressConstructorProperties
ahora está en desuso :-(false
.@AllArgsConstructor(suppressConstructorProperties = true)
es obsoleto. Definirlombok.anyConstructor.suppressConstructorProperties=true
( https://projectlombok.org/features/configuration ) y cambiar la anotación lombok de POJO de@Value
a@Data
+@NoArgsConstructor
+@AllArgsConstructor
funciona para mí.fuente
Para mí funcionó cuando actualicé la versión de lombok a: 'org.projectlombok: lombok: 1.18.0'
fuente
De la respuesta de Jan Rieke
Necesitará una @JsonProperty en cada campo, incluso si el nombre coincide, pero es una buena práctica seguir de todos modos. También puede configurar sus campos a final público usando esto, que prefiero a los getters.
@ToString @EqualsAndHashCode @Wither @AllArgsConstructor(onConstructor=@__(@JsonCreator)) public class TestFoo { @JsonProperty("xoom") public final String x; @JsonProperty("z") public final int z; }
Sin embargo, también debería funcionar con getters (+ setters).
fuente
Can not deserialize instance of java.lang.String out of START_OBJECT token
... ¡Y esto lo solucionó! Necesito tener esa@JsonProperty
anotación para cada parámetro de constructor y esa adición al@AllArgsConstructor
permite a lombok instrumentar eso.Puedes hacer que Jackson juegue con casi cualquier cosa si usas su patrón de "mezcla" . Básicamente, le brinda una forma de agregar anotaciones de Jackson a una clase existente sin modificar esa clase. Me inclino a recomendarlo aquí en lugar de una solución de Lombok porque esto resuelve un problema que Jackson tiene con una función de Jackson, por lo que es más probable que funcione a largo plazo.
fuente
Tengo todas mis clases anotadas así:
@JsonAutoDetect(fieldVisibility = Visibility.ANY) @JsonInclude(JsonInclude.Include.NON_DEFAULT) @Data @Accessors(fluent = true) @NoArgsConstructor @AllArgsConstructor
Funcionó con todas las versiones de Lombok y Jackson durante, al menos, un par de años.
Ejemplo:
@JsonAutoDetect(fieldVisibility = Visibility.ANY) @JsonInclude(JsonInclude.Include.NON_DEFAULT) @Data @Accessors(fluent = true) @NoArgsConstructor @AllArgsConstructor public class Person { String id; String first; String last; }
Y eso es. Lombok y Jackson juegan juntos como un encanto.
fuente
@JsonInclude(JsonInclude.Include.NON_NULL) @Data public class Person { String id; String first; String last; }
Adicional a la Clase de Datos, se debe configurar correctamente el ObjectMapper. En este caso, está funcionando bien con una configuración de ParameterNamesModule y configurando la visibilidad de los campos y métodos de creador.
om.registerModule(new ParameterNamesModule()); om.setVisibility(FIELD, JsonAutoDetect.Visibility.ANY); om.setVisibility(CREATOR, JsonAutoDetect.Visibility.ANY);
Entonces debería funcionar como se esperaba.
fuente
Tenía problemas para lograr que Lombok no agregara la
ConstructorProperies
anotación, así que fui por el otro lado y deshabilité a Jackson para que no mirara esa anotación.El culpable es JacksonAnnotationIntrospector.findCreatorAnnotation . Darse cuenta:
if (_cfgConstructorPropertiesImpliesCreator && config.isEnabled(MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES)
También observe JacksonAnnotationIntrospector.setConstructorPropertiesImpliesCreator :
public JacksonAnnotationIntrospector setConstructorPropertiesImpliesCreator(boolean b) { _cfgConstructorPropertiesImpliesCreator = b; return this; }
Así que dos opciones, o bien establecen el
MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES
que falsa o crean unJacksonAnnotationIntrospector
conjuntosetConstructorPropertiesImpliesCreator
defalse
y establecer estaAnnotationIntrospector
en elObjectMapper
medio de ObjectMapper.setAnnotationIntrospector .Observe un par de cosas, estoy usando Jackson 2.8.10 y en esa versión
MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES
no existe. No estoy seguro en qué versión de Jackson se agregó. Entonces, si no está allí, use elJacksonAnnotationIntrospector.setConstructorPropertiesImpliesCreator
mecanismo.fuente
También debe tener este módulo. https://github.com/FasterXML/jackson-modules-java8
luego active el indicador -parameters para su compilador.
<build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.7.0</version> <configuration> <compilerArgs> <arg>-parameters</arg> </compilerArgs> </configuration> </plugin>
fuente
También luché con esto por un momento. Pero mirando la documentación aquí , puedo ver que el parámetro de anotación onConstructor se considera experimental y no es compatible con mi IDE (STS 4). Según la documentación de Jackson, los miembros privados no se (des) serializan de forma predeterminada. Hay formas rápidas de resolver esto.
Agregue la anotación JsonAutoDetect y configúrela adecuadamente para detectar miembros protegidos / privados. Esto es conveniente para los DTO
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) public class SomeClass
Agregue una función de fábrica con la anotación @JsonCreator, esto funciona mejor si necesita alguna validación de objeto o transformaciones adicionales.
public class SomeClass { // some code here @JsonCreator public static SomeClass factory(/* params here dressing them in @JsonProperty annotations*/) { return new SomeClass(); } }
Por supuesto, también puede agregar manualmente el constructor en usted mismo.
fuente
Tuve un problema diferente y fue con los tipos primitivos booleanos.
private boolean isAggregate;
Estaba arrojando el siguiente error como resultado
Exception: Unrecognized field "isAggregate" (class
Lambok se convierte
isAggregate
enisAggregate()
un captador que convierte la propiedad internamente en lombok como en suaggregate
lugarisAggregate
. A la biblioteca de Jackson no le gusta y necesitaisAggregate
propiedades.Actualicé el booleano primitivo a Wrapper Boolean para solucionar este problema. Hay otras opciones para usted si se trata de
boolean
tipos, consulte la referencia a continuación.Sol:
private Boolean isAggregate;
ref: https://www.baeldung.com/lombok-getter-boolean
fuente