web-dev-qa-db-ja.com

ジャクソンとロンボクが一緒に働くことはできません

ジャクソンとロンボクを組み合わせて実験しています。これらは私のクラスです:

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

}

これらは、classpthに追加するJARです。

Netbeansでコンパイルしています(これは本当に関連があるとは思いませんが、とにかくこれを報告して、完全かつ忠実に再現できるようにします)。上記の5つのJARは、プロジェクトフォルダー内の「lib」というフォルダーに保存されます(「src」、「nbproject」、「test」、「build」とともに)。プロジェクトのプロパティの「Add JAR/Folder」ボタンを使用してそれらをNetbeansに追加しましたが、上記のリストと同じ順序でリストされています。プロジェクトは、標準の「Javaアプリケーション」タイプのプロジェクトです。

さらに、Netbeansプロジェクトは、「保存時にコンパイルしない」、「デバッグ情報を生成する」、「レポート非推奨API」、「 track Java依存関係 "、" activacteアノテーションの処理 "および" エディターでのアノテーションの処理の処理 "。 Netbeansでは、注釈プロセッサまたは注釈処理オプションは明示的に構成されていません。また、「-Xlint:all」コマンドラインオプションはコンパイラコマンドラインで渡され、コンパイラは外部VMで実行されます。

私のjavacのバージョンは1.8.0_72で、Javaのバージョンは1.8.0_72-b15です。私のNetbeansは8.1です。

私のプロジェクトは問題なくコンパイルされます。ただし、実行中に例外をスローします。例外は、簡単にまたは明白に修正できるように見えるものではないようです。スタックトレースを含む出力はここにあります:

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

既に@Valueおよび@AllArgsConstructorアノテーションをランダムに突っ込んでみましたが、これ以上改善することはできませんでした。

私は例外をグーグルでやりました jacksonの古いバグレポートを見つけました 、および 開いているが、何か他のものに関連しているように見える 。ただし、これでもこのバグの内容や修正方法については何もわかりません。また、私はそれをどこか他の場所で見るのに役立つものを見つけることができませんでした。

私がやろうとしているのはロンボクとジャクソンの両方の非常に基本的な使用方法であるため、この問題を回避する方法に関する有用な情報を見つけることができなかったようです。たぶん私は何かを見逃しましたか?

lombokを使用しない」または「jacksonを使用しない」と言う以外に、これを解決する方法について誰もが考えていますか?

53
Victor Stafusa

不変であるが、lombokとjacksonを使用したjsonシリアライズ可能なPOJOが必要な場合。 lomboksビルダーでjacksonsの新しいアノテーションを使用する@JsonPOJOBuilder(withPrefix = "")このソリューションを試しましたが、非常にうまく機能します。サンプル使用法

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 {

    }
}

@Builderを持つクラスが多すぎて、ボイラープレートコードの空の注釈を望まない場合は、注釈インターセプターをオーバーライドして空の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", "");
        }
    });

また、@JsonPOJOBuilderアノテーションを使用して空のビルダークラスを削除できます。

33

私はまったく同じ問題を抱えていました。suppressConstructorProperties = trueパラメーターを追加して「解決」しました(例を使用)。

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

ジャクソンは、コンストラクタに追加された Java.beans.ConstructorProperties 注釈が嫌いなようです。 suppressConstructorProperties = trueパラメーターは、 Lombok を追加しないように指示します(デフォルトで追加します)。

6
Donovan Muller

不変+ロンボク+ジャクソンは、次の方法で実現できます。

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);
    }
}
5
Alex Efimov

@AllArgsConstructor(suppressConstructorProperties = true)は非推奨です。 lombok.anyConstructor.suppressConstructorProperties=truehttps://projectlombok.org/features/configuration )を定義し、POJOのlombokアノテーションを@Valueから@Data + @NoArgsConstructor +に変更します@AllArgsConstructorは私のために働きます。

4
yyy

上記のいくつかを試しましたが、それらはすべて気まぐれでした。私にとって本当に役立ったのは、私が見つけた答えです ここ

プロジェクトのルートディレクトリにファイルを追加します(まだ行っていない場合)

lombok.config

内側に貼り付けます

lombok.anyConstructor.addConstructorProperties=true

次に、次のようにpojoを定義できます。

@Data
@AllArgsConstructor
public class MyPojo {

    @JsonProperty("Description")
    private String description;
    @JsonProperty("ErrorCode")
    private String errorCode;
}
3

私にとっては、ロンボクのバージョンを「org.projectlombok:lombok:1.18.0」に更新したときに機能しました

2
fascynacja

このモジュールも必要です。 https://github.com/FasterXML/jackson-modules-Java8

次に、コンパイラの-parametersフラグをオンにします。

<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>
1
Matt Broekhuis

"mixin" pattern を使用すれば、ジャクソンにほぼ何でも遊ばせることができます。基本的に、既存のクラスを実際に変更することなく、そのクラスにジャクソン注釈を追加する方法を提供します。ジャクソンがジャクソンの機能で抱えている問題を解決するため、ロンボクのソリューションではなくここでそれを推奨することに傾いています。

1
David Ehrmann

ヤン・リーケの回答より

Lombok 1.18.4以降、コンストラクターパラメーターにコピーされる注釈を構成できます。これをlombok.configに挿入します:

lombok.copyableAnnotations += com.fasterxml.jackson.annotation.JsonProperty

次に、@JsonPropertyをフィールドに追加します。

...

名前が一致する場合でも、すべてのフィールドに@JsonPropertyが必要になりますが、とにかく従うことをお勧めします。また、これを使用してフィールドをパブリックファイナルに設定することもできます。

@ToString
@EqualsAndHashCode
@Wither
@AllArgsConstructor(onConstructor=@__(@JsonCreator))
public class TestFoo {
    @JsonProperty("xoom")
    private final String x;
    @JsonProperty("z")
    private final int z;
}
0
Mingwei Samuel
@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
public class Person {
   String id;
   String first;
   String last;
}

データクラスに加えて、ObjectMapperを正しく構成する必要があります。この場合、ParameterNamesModule構成で正常に動作し、FieldsおよびCreatorメソッドの可視性を設定しています

    om.registerModule(new ParameterNamesModule());
    om.setVisibility(FIELD, JsonAutoDetect.Visibility.ANY);
    om.setVisibility(CREATOR, JsonAutoDetect.Visibility.ANY);

その後、期待どおりに動作するはずです。

0
Hector Delgado

私もこれに少し苦労しました。しかし、ドキュメントを見ると here onConstructorアノテーションパラメータは実験的であると見なされ、IDE(STS 4)では十分にサポートされていないことがわかります。 Jacksonのドキュメントによると、プライベートメンバーはデフォルトでは(デ)シリアル化されていません。これを解決する簡単な方法があります。

JsonAutoDetectアノテーションを追加し、保護/プライベートメンバーを検出するために適切に設定します。これはDTOに便利です

@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public class SomeClass

@JsonCreatorアノテーションを使用してファクトリ関数を追加します。これは、オブジェクトの検証または追加の変換が必要な場合に最適です。

public class SomeClass {

   // some code here

   @JsonCreator
   public static SomeClass factory(/* params here dressing them in @JsonProperty annotations*/) {
      return new SomeClass();
   }
}

もちろん、コンストラクタを自分で手動で追加することもできます。

0
user3416682

私はすべてのクラスにこのように注釈を付けました:

@JsonAutoDetect(fieldVisibility = Visibility.ANY)
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
@Data
@Accessors(fluent = true)
@NoArgsConstructor
@AllArgsConstructor

少なくとも数年間、すべてのロンボクとジャクソンのバージョンで動作しました。

例:

@JsonAutoDetect(fieldVisibility = Visibility.ANY)
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
@Data
@Accessors(fluent = true)
@NoArgsConstructor
@AllArgsConstructor
public class Person {
    String id;
    String first;
    String last;
}

以上です。ロンボクとジャクソンは魅力のように一緒に遊ぶ。

0
where_

LombokにConstructorProperies注釈を追加しないようにすることで問題が発生していたため、反対に進み、Jacksonがその注釈を表示できないようにしました。

原因は JacksonAnnotationIntrospector.findCreatorAnnotation です。通知:

if (_cfgConstructorPropertiesImpliesCreator
            && config.isEnabled(MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES)

また注意してください JacksonAnnotationIntrospector.setConstructorPropertiesImpliesCreator

public JacksonAnnotationIntrospector setConstructorPropertiesImpliesCreator(boolean b)
{
    _cfgConstructorPropertiesImpliesCreator = b;
    return this;
}

したがって、2つのオプションは、MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIESをfalseに設定するか、JacksonAnnotationIntrospectorを作成してsetConstructorPropertiesImpliesCreatorfalseに設定し、このAnnotationIntrospectorObjectMapperに設定します ObjectMapper.setAnnotationIntrospector

いくつかのことに注意してください。私はJackson 2.8.10を使用しており、そのバージョンにはMapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIESは存在しません。ジャクソンのどのバージョンに追加されたのかわかりません。したがって、存在しない場合は、JacksonAnnotationIntrospector.setConstructorPropertiesImpliesCreatorメカニズムを使用します。

0
John B

@NoArgsConstructorを追加してみてください

0
Victor Grazi