Estou experimentando combinar Jackson e Lombok. Essas são minhas aulas:
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);
}
}
Esses são os JARs que estou adicionando ao classpth:
Lombok: https://projectlombok.org/downloads/lombok.jar (versão 1.16.10)
Anotações de Jackson: http://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-annotations/2.8.2/jackson-annotations-2.8.2.jar
Jackson core: http://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-core/2.8.2/jackson-core-2.8.2.jar
Jackson databind: 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
Estou compilando com o Netbeans (não acho que isso seja realmente relevante, mas estou relatando isso de qualquer maneira para torná-lo reproduzível perfeita e fielmente). Os cinco JARs acima são mantidos em uma pasta chamada " lib
" dentro da pasta do projeto (junto com " src
", " nbproject
", " test
" e " build
"). Eu os adicionei ao Netbeans através do botão " Adicionar JAR / Pasta " nas propriedades do projeto e eles estão listados na ordem exata da lista acima. O projeto é um projeto do tipo "aplicativo Java" padrão.
Além disso, o projeto Netbeans está configurado para " NÃO compilar ao salvar ", " gerar informações de depuração ", " relatar APIs obsoletas ", " rastrear dependências de java ", " processamento de anotação de ativação " e " processamento de anotação de ativação no editor ". Nenhum processador de anotação ou opção de processamento de anotação é explicitamente configurado no Netbeans. Além disso, a -Xlint:all
opção de linha de comando " " é passada na linha de comando do compilador e o compilador é executado em uma VM externa.
A versão do meu javac é 1.8.0_72 e a versão do meu java é 1.8.0_72-b15. Meu Netbeans é 8.1.
Meu projeto compila bem. No entanto, ele lança uma exceção em sua execução. A exceção não parece ser nada que pareça fácil ou óbvio consertável. Aqui está a saída, incluindo o rastreamento de pilha:
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
Eu já tentei cutucar aleatoriamente com as anotações @Value
e @AllArgsConstructor
, mas não consegui fazer melhor.
Eu pesquisei a exceção e encontrei um relatório de bug antigo no jackson , e outro que está aberto, mas parece estar relacionado a outra coisa . No entanto, isso ainda não diz nada sobre o que é esse bug ou como corrigi-lo. Além disso, não consegui encontrar nada útil procurando em outro lugar.
Visto que o que estou tentando fazer é o uso muito básico de lombok e jackson, parece estranho que eu não tenha conseguido encontrar mais informações úteis sobre como solucionar esse problema. Talvez eu tenha perdido alguma coisa?
Além de dizer " não use lombok " ou " não use jackson ", alguém tem alguma idéia de como resolver isso?
Immutable + Lombok + Jackson pode ser alcançado da próxima maneira:
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); } }
fonte
AllArgsConstructor
Já não faz parte da@Value
anotação?@NoArgsConstructor
substitui o construtor que é gerado pela@Value
anotação, então você tem que adicionar o extra@AllArgsConstructor
Tentei várias das opções acima e todas foram temperamentais. O que realmente funcionou para mim foi a resposta que encontrei aqui .
no diretório raiz do seu projeto, adicione um arquivo lombok.config (se ainda não o fez)
e dentro cole isso
lombok.anyConstructor.addConstructorProperties=true
Em seguida, você pode definir seus pojos da seguinte forma:
@Data @AllArgsConstructor public class MyPojo { @JsonProperty("Description") private String description; @JsonProperty("ErrorCode") private String errorCode; }
fonte
Eu tive exatamente o mesmo problema, "resolvi" adicionando o
suppressConstructorProperties = true
parâmetro (usando seu exemplo):@Value @Wither @AllArgsConstructor(suppressConstructorProperties = true) public class TestFoo { @JsonProperty("xoom") private String x; private int z; }
Jackson aparentemente não gosta da
java.beans.ConstructorProperties
anotação adicionada aos construtores. OsuppressConstructorProperties = true
parâmetro diz ao Lombok para não adicioná-lo (ele o faz por padrão).fonte
suppressConstructorProperties
agora está obsoleto :-(false
.@AllArgsConstructor(suppressConstructorProperties = true)
está obsoleto. Definirlombok.anyConstructor.suppressConstructorProperties=true
( https://projectlombok.org/features/configuration ) e alterar a anotação lombok do POJO de@Value
para@Data
+@NoArgsConstructor
+@AllArgsConstructor
funciona para mim.fonte
Da resposta de Jan Rieke
Você precisará de @JsonProperty em cada campo, mesmo se o nome corresponder, mas essa é uma boa prática a ser seguida de qualquer maneira. Você também pode definir seus campos para público final usando isso, que eu prefiro a getters.
@ToString @EqualsAndHashCode @Wither @AllArgsConstructor(onConstructor=@__(@JsonCreator)) public class TestFoo { @JsonProperty("xoom") public final String x; @JsonProperty("z") public final int z; }
Ele também deve funcionar com getters (+ setters).
fonte
Can not deserialize instance of java.lang.String out of START_OBJECT token
... E isso corrigiu! Preciso ter essa@JsonProperty
anotação para cada parâmetro do construtor e essa adição ao@AllArgsConstructor
lombok permite que o instrumentem.Para mim, funcionou quando atualizei a versão do lombok para: 'org.projectlombok: lombok: 1.18.0'
fonte
Você pode fazer Jackson tocar com quase qualquer coisa se usar seu padrão de "mixagem" . Basicamente, oferece uma maneira de adicionar anotações de Jackson a uma classe existente sem realmente modificar essa classe. Estou inclinado a recomendá-lo aqui, em vez de uma solução Lombok, porque isso resolve um problema que Jackson está tendo com um recurso de Jackson, então é mais provável que funcione a longo prazo.
fonte
Todas as minhas aulas foram anotadas assim:
@JsonAutoDetect(fieldVisibility = Visibility.ANY) @JsonInclude(JsonInclude.Include.NON_DEFAULT) @Data @Accessors(fluent = true) @NoArgsConstructor @AllArgsConstructor
Funcionou com todas as versões de Lombok e Jackson por, pelo menos, alguns anos.
Exemplo:
@JsonAutoDetect(fieldVisibility = Visibility.ANY) @JsonInclude(JsonInclude.Include.NON_DEFAULT) @Data @Accessors(fluent = true) @NoArgsConstructor @AllArgsConstructor public class Person { String id; String first; String last; }
E é isso. Lombok e Jackson brincam juntos como um encanto.
fonte
@JsonInclude(JsonInclude.Include.NON_NULL) @Data public class Person { String id; String first; String last; }
Adicional à Classe de Dados, deve ser configurado corretamente o ObjectMapper. Neste caso, está funcionando bem com a configuração ParameterNamesModule, e definindo a visibilidade dos Campos e Métodos do Criador
om.registerModule(new ParameterNamesModule()); om.setVisibility(FIELD, JsonAutoDetect.Visibility.ANY); om.setVisibility(CREATOR, JsonAutoDetect.Visibility.ANY);
Então, ele deve funcionar conforme o esperado.
fonte
Eu estava tendo problemas para fazer o Lombok não adicionar a
ConstructorProperies
anotação, então fui para o outro lado e desabilitei Jackson de olhar para aquela anotação.O culpado é JacksonAnnotationIntrospector.findCreatorAnnotation . Aviso prévio:
if (_cfgConstructorPropertiesImpliesCreator && config.isEnabled(MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES)
Observe também JacksonAnnotationIntrospector.setConstructorPropertiesImpliesCreator :
public JacksonAnnotationIntrospector setConstructorPropertiesImpliesCreator(boolean b) { _cfgConstructorPropertiesImpliesCreator = b; return this; }
Então duas opções, ou definir a
MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES
como falsa ou criar umJacksonAnnotationIntrospector
conjuntosetConstructorPropertiesImpliesCreator
defalse
e definir estaAnnotationIntrospector
naObjectMapper
via ObjectMapper.setAnnotationIntrospector .Observe algumas coisas, estou usando o Jackson 2.8.10 e essa versão
MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES
não existe. Não tenho certeza em qual versão de Jackson foi adicionado. Portanto, se não estiver lá, use oJacksonAnnotationIntrospector.setConstructorPropertiesImpliesCreator
mecanismo.fonte
Você precisa ter este módulo também. https://github.com/FasterXML/jackson-modules-java8
em seguida, ative a sinalização -parameters para seu 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>
fonte
Eu lutei com isso por um momento também. Mas olhando a documentação aqui , posso ver que o parâmetro de anotação onConstructor é considerado experimental e não é bem suportado em meu IDE (STS 4). De acordo com a documentação de Jackson, os membros privados não são (des) serializados por padrão. Existem maneiras rápidas de resolver isso.
Adicione a anotação JsonAutoDetect e defina-a apropriadamente para detectar membros protegidos / privados. Isso é conveniente para DTOs
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) public class SomeClass
Adicione uma função de fábrica com a anotação @JsonCreator, isso funciona melhor se você precisar de alguma validação de objeto ou transformações adicionais.
public class SomeClass { // some code here @JsonCreator public static SomeClass factory(/* params here dressing them in @JsonProperty annotations*/) { return new SomeClass(); } }
Claro que você também pode adicionar manualmente o construtor em você mesmo.
fonte
Eu tive um problema diferente e foi com os tipos primitivos booleanos.
private boolean isAggregate;
Ele estava gerando o seguinte erro como resultado
Exception: Unrecognized field "isAggregate" (class
Convertidos Lambok
isAggregate
aisAggregate()
como um getter tornando a propriedade internamente para Lombok comoaggregate
vezisAggregate
. A biblioteca Jackson não gosta e,isAggregate
em vez disso , precisa de propriedade.Atualizei o booleano primitivo para Wrapper Boolean para contornar esse problema. Existem outras opções para você se estiver lidando com
boolean
tipos, consulte a referência abaixo.Sol:
private Boolean isAggregate;
ref: https://www.baeldung.com/lombok-getter-boolean
fonte