146 votes

Impossible que Jackson et Lombok travaillent ensemble

Je suis expérimenter dans la combinaison de Jackson et de Lombok. Ce sont mes classes:

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);
    }

}

Ce sont les Pots que je vais ajouter dans le classpth:

Je suis pour le compiler avec Netbeans (je ne pense pas que ce est vraiment pertinente, mais je suis déclaration ce de toute façon, pour le rendre parfaitement et fidèlement reproductible). Les cinq Jarres ci-dessus sont conservés dans un dossier appelé "lib" à l'intérieur du dossier du projet (avec "src", "nbproject", "test" et "build"). J'ai ajouté à Netbeans via "Add JAR/Folder" dans les propriétés du projet et ils sont répertoriés dans l'ordre exact de la liste ci-dessus. Le projet est un projet de norme "Java application" type de projet.

En outre, le projet Netbeans est configuré à "ne PAS compiler sur " enregistrer", "générer les informations de débogage", "rapport Api obsolète", "piste java dépendances", "activacte annotation proccessing" et "activacte annotation proccessing dans l'éditeur". Pas de processeur d'annotation ou de l'annotation option de traitement est configuré de manière explicite dans Netbeans. Aussi, le "-Xlint:all" option de ligne de commande est passé dans la ligne de commande du compilateur, et le compilateur s'exécute sur une machine virtuelle.

Mon javac version 1.8.0_72 et mon java version 1.8.0_72-b15. Mon Netbeans est de 8.1.

Mon projet se compile très bien. Cependant, il déclenche une exception dans son exécution. L'exception ne semble pas être quelque chose qui semble facile ou évident réparable. Voici la sortie, y compris la 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

J'ai déjà essayé de manière aléatoire piquer avec l' @Value et @AllArgsConstructor les annotations, mais je ne pouvais pas faire mieux.

Je google avais l'exception et trouvé un vieux rapport de bug sur jackson, et un autre qui est ouvert, mais semble être lié à quelque chose d'autre. Toutefois, cela ne dit rien à propos de quoi est-ce un bug ou comment résoudre le problème. Aussi, je ne pouvais pas trouver quelque chose d'utile à la recherche que quelque part d'autre.

Depuis que je suis en train de faire est très simple d'utilisation à la fois de lombok et de jackson, il semble étrange que je ne pouvais pas trouver toutes les informations les plus utiles sur la façon de contourner ce problème. Peut-être que j'ai raté quelque chose?

Autres que de simplement dire "ne pas utiliser de lombok" ou "ne pas utiliser jackson", faire quelqu'un a une idée sur comment résoudre ce problème?

80voto

Si vous voulez immuable, mais un json serializable POJO à l'aide de lombok et de jackson. Utilisation jacksons nouvelle annotation sur votre lomboks constructeur @JsonPOJOBuilder(withPrefix = "") J'ai essayé cette solution et ça fonctionne très bien. Exemple d'utilisation

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import lombok.Builder;
import lombok.Value;

@JsonDeserialize(builder = Detail.DetailBuilder.class)
@Value
@Builder
public class Detail {

    private String url;
    private String userName;
    private String password;
    private String scope;

    @JsonPOJOBuilder(withPrefix = "")
    public static class DetailBuilder {

    }
}

Si vous avez un trop grand nombre de classes avec @Builder et vous voulez ne voulez pas que le code réutilisable vide d'annotation, vous pouvez remplacer l'annotation de l'intercepteur d'avoir vide withPrefix

mapper.setAnnotationIntrospector(new JacksonAnnotationIntrospector() {
        @Override
        public JsonPOJOBuilder.Value findPOJOBuilderConfig(AnnotatedClass ac) {
            if (ac.hasAnnotation(JsonPOJOBuilder.class)) {//If no annotation present use default as empty prefix
                return super.findPOJOBuilderConfig(ac);
            }
            return new JsonPOJOBuilder.Value("build", "");
        }
    });

Et vous pouvez supprimer le vide d'un générateur de classe avec @JsonPOJOBuilder d'annotation.

8voto

Donovan Muller Points 2670

J'ai eu exactement le même problème, résolu par l'ajout de l' suppressConstructorProperties = true paramètre (à l'aide de votre exemple):

@Value
@Wither
@AllArgsConstructor(suppressConstructorProperties = true)
public class TestFoo {
    @JsonProperty("xoom")
    private String x;
    private int z;
}

Jackson apparemment n'aime pas l' java.beans.ConstructorProperties d'annotation ajoutée pour les constructeurs. L' suppressConstructorProperties = true paramètre indique à Lombok pas à l'ajouter (il le fait par défaut).

4voto

yyy Points 75

@AllArgsConstructor(suppressConstructorProperties = true) est obsolète. Définir lombok.anyConstructor.suppressConstructorProperties=true ( https://projectlombok.org/features/configuration ) et changer l'annotation Lombok de POJO de @Value à @Data - @NoArgsConstructor + @AllArgsConstructor travaille pour moi.

1voto

David Ehrmann Points 2406

Vous pouvez obtenir que Jackson joue avec à peu près n'importe quoi si vous utilisez son motif "mixin" . En gros, cela vous permet d'ajouter des annotations de Jackson à une classe existante sans modifier réellement cette classe. Je suis plutôt enclin à le recommander ici plutôt qu’à une solution de Lombok, car cela résout un problème rencontré par Jackson avec une fonctionnalité de Jackson. Il est donc plus probable qu’il fonctionne à long terme.

0voto

Matt Broekhuis Points 368

Vous devez aussi avoir ce module. https://github.com/FasterXML/jackson-modules-java8

puis activez le paramètre -parameters pour votre compilateur.

 <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>
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X