ジャクソンとロンボクを一緒に働かせることはできません


96

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

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

}

これらは、私がクラスに追加しているJARです。

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

さらに、Netbeansプロジェクトは、「保存時にコンパイルしない」、「デバッグ情報を生成する」、「非推奨のAPIを報告する」、「Javaの依存関係を追跡する」、「アクティブ化アノテーション処理」、「エディタでアクティブ化アノテーション処理」するように設定されています。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に関する古いバグレポートと開いているが他の何かに関連しているように見える別のバグレポート見つけました。ただし、これでも、このバグとは何か、またはその修正方法については何もわかりません。また、他の場所でそれを探すのに役立つものは何も見つかりませんでした。

私がやろうとしているのは、ロンボクとジャクソンの両方の非常に基本的な使用法であるため、この問題を回避する方法についてこれ以上役立つ情報を見つけることができなかったのは奇妙に思えます。多分私は何かを逃したのですか?

ロンボクを使わない」や「ジャクソンを使わない」と言う以外に、これを解決する方法を知っている人はいますか?

回答:


59

不変であるが、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アノテーション付きの空のビルダークラスを削除できます。


ソリューションへのリンクは大歓迎ですが、それがなくても回答が役立つことを確認してください。リンクの周りにコンテキストを追加して、他のユーザーがそれが何であるか、なぜそこにあるのかを理解できるようにしてから、ページの最も関連性の高い部分を引用してください。ターゲットページが利用できない場合に再リンクします。リンクに過ぎない回答は削除される場合があります。
geisterfurz007 2018

このソリューションは、ジャクソンの頭の痛いコンストラクターベースの逆シリアル化の問題を回避しながら不変性を維持します(マルチフィールドコンストラクターは、インテリジェントなものを試すのではなく、コンストラクター引数ごとに@JsonPropertyを必要とします)。(私は運がなくてonConstructor _ = {@ JsonCreator}を試しました)
JeeBee 2018

37

イミュータブル+ロンボク+ジャクソンは次の方法で実現できます。

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

4
AllArgsConstructorすでに@Valueアノテーションの一部ではありませんか?
ゾン

8
明示的に追加すると@NoArgsConstructor@Valueアノテーションによって生成されるコンストラクターがオーバーライドされるため、追加を追加する必要があります@AllArgsConstructor
Davio 2020年

1
私が見つけた最良の解決策-私の意見では-ビルダーパターンなし。ありがとう。
Radouxca

16

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

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

lombok.config

中にこれを貼り付けます

lombok.anyConstructor.addConstructorProperties=true

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

@Data
@AllArgsConstructor
public class MyPojo {

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

2
しかし、これは変更可能ではありませんか?
vphilipnyc

不変にするには、Getter and BuilderまたはRequiredArgsConstructorでデータを変更し、すべてのフィールドを最終としてマークします
nekperu157 3920年

私の場合、なぜこれが機能しないのかについてのアイデアはありますか?Spring Bootアプリケーションがあり、src内にlombok.configを配置しましたが、それでもソリューションが機能していません。
サノスM20年

8

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

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

ジャクソンはjava.beans.ConstructorProperties 、コンストラクターに追加されたアノテーションが好きではないようです。このsuppressConstructorProperties = trueパラメーターは、Lombokに追加しないように指示します(デフォルトでは追加します)。


7
suppressConstructorProperties現在非推奨です:
lilalinux 2017

3
新しいデフォルトもであるため、これは問題ではありませんfalse
Michael Piefel 2018

4

@AllArgsConstructor(suppressConstructorProperties = true)は非推奨です。定義lombok.anyConstructor.suppressConstructorProperties=truehttps://projectlombok.org/features/configurationから)と変化するPOJOのロンボク島の注釈@Value@Data+ @NoArgsConstructor+@AllArgsConstructor私のために動作します。


14
これにより、クラスが変更可能に変更されますが、これはOPが望んでいたものではないと思います
AmitGoldstein18年

3

JanRiekeの回答から

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")
    public final String x;
    @JsonProperty("z")
    public final int z;
}

ただし、ゲッター(+セッター)でも機能するはずです。


1
これで私の問題は解決しました!どうもありがとうございます!JSONとPOJO間のspring-boot-integrationとシリアル化で立ち往生していて、エラーが発生しました:Can not deserialize instance of java.lang.String out of START_OBJECT token...そしてこれで修正されました!私は持っている必要があり@JsonProperty、各コンストラクタのパラメータとのそのほかのための注釈を@AllArgsConstructor中にすることを機器にロンボクすることができます。
マーク

2

私にとっては、lombokのバージョンを次のように更新したときに機能しました: 'org.projectlombok:lombok:1.18.0'


1

「ミックスイン」パターンを使用すれば、ジャクソンにほぼ何でも遊ばせることができます。基本的に、実際にそのクラスを変更せずに、既存のクラスにJacksonアノテーションを追加する方法を提供します。これは、ジャクソンがジャクソン機能で抱えている問題を解決するため、Lombokソリューションではなく、ここで推奨することに傾いています。したがって、長期的に機能する可能性が高くなります。


1

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

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

少なくとも2年間は、すべてのLombokバージョンとJacksonバージョンで動作しました。

例:

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

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


9
これは可変クラスです。
ŁukaszG

0
@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
public class Person {
   String id;
   String first;
   String last;
}

データクラスに加えて、ObjectMapperを正しく構成する必要があります。この場合、ParameterNamesModule構成で正常に機能し、フィールドとクリエーターメソッドの可視性を設定しています

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

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


0

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セットsetConstructorPropertiesImpliesCreatorにするfalseと、この設定AnnotationIntrospectorObjectMapper経由ObjectMapper.setAnnotationIntrospector

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


0

このモジュールも必要です。 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>

0

私も一瞬これに苦労しました。しかし、ここのドキュメント を見ると、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();
   }
}

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


-1

私は別の問題を抱えていました、そしてそれはブールプリミティブ型にありました。

private boolean isAggregate;

その結果、次のエラーがスローされていました

Exception: Unrecognized field "isAggregate" (class 

Lambokはゲッターとしてに変換isAggregateisAggregate()れ、aggregate代わりにプロパティを内部的にlombokにしますisAggregate。ジャクソン図書館はそれが気に入らず、isAggregate代わりに財産が必要です。

この問題を回避するために、プリミティブブール値をラッパーブール値に更新しました。booleanタイプを扱っている場合は、他にもオプションがあります。以下のリファレンスを参照してください。

ソル:

private Boolean isAggregate;

参照:https//www.baeldung.com/lombok-getter-boolean


プリミティブ型でisAggregateの代わりにaggregateを使用しようとしましたか?エラーも解決できると思います。また、この参照してくださいstackoverflow.com/a/42620096/6332074
ムハンマド・ワカスディラワー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.