JsonMappingException:タイプ[simple type、class]に適したコンストラクタが見つかりません:JSONオブジェクトからインスタンス化できません


438

JSONリクエストを取得して処理しようとすると、次のエラーが発生します。

org.codehaus.jackson.map.JsonMappingException:型に適したコンストラクターが見つかりません[単純型、クラスcom.myweb.ApplesDO]:JSONオブジェクトからインスタンス化できません(型情報を追加/有効にする必要がありますか?)

ここに私が送信しようとしているJSONがあります:

{
  "applesDO" : [
    {
      "apple" : "Green Apple"
    },
    {
      "apple" : "Red Apple"
    }
  ]
}

コントローラーには、次のメソッドシグネチャがあります。

@RequestMapping("showApples.do")
public String getApples(@RequestBody final AllApplesDO applesRequest){
    // Method Code
}

AllApplesDOはApplesDOのラッパーです:

public class AllApplesDO {

    private List<ApplesDO> applesDO;

    public List<ApplesDO> getApplesDO() {
        return applesDO;
    }

    public void setApplesDO(List<ApplesDO> applesDO) {
        this.applesDO = applesDO;
    }
}

ApplesDO:

public class ApplesDO {

    private String apple;

    public String getApple() {
        return apple;
    }

    public void setApple(String appl) {
        this.apple = apple;
    }

    public ApplesDO(CustomType custom){
        //constructor Code
    }
}

JacksonはJSONをサブクラスのJavaオブジェクトに変換できないと思います。ジャクソンがJSONをJavaオブジェクトに変換するための構成パラメーターを手伝ってください。Spring Frameworkを使用しています。

編集:上記のサンプルクラスでこの問題を引き起こしている主要なバグを含めました-解決策については、承認された回答をご覧ください。


2
上記のコードにはサブクラスがありません。このコードはあなたが試したものですか、それとも簡単な例を作っていますか?
gkamal

それがどのように機能するかについてのいくつかのより詳細な説明を含む回答を追加しました。基本的に、Javaはメソッドの引数名を実行時に保持しないことを理解する必要があります。
Vlasec

回答:


565

それで、ようやく問題が何であるかが分かりました。私が疑ったように、それはジャクソン構成問題ではありません。

実際問題ApplesDOクラスにありました:

public class ApplesDO {

    private String apple;

    public String getApple() {
        return apple;
    }

    public void setApple(String apple) {
        this.apple = apple;
    }

    public ApplesDO(CustomType custom) {
        //constructor Code
    }
}

クラスに定義されたカスタムコンストラクターがあり、それをデフォルトのコンストラクターにしています。ダミーのコンストラクターを導入すると、エラーがなくなりました。

public class ApplesDO {

    private String apple;

    public String getApple() {
        return apple;
    }

    public void setApple(String apple) {
        this.apple = apple;
    }

    public ApplesDO(CustomType custom) {
        //constructor Code
    }

    //Introducing the dummy constructor
    public ApplesDO() {
    }

}

CustomTypeの出所を尋ねてもいいですか。私はこのような構造を試していますが、Javaはまったくの初心者です。
andho 2013年

181
ジャクソンを内部(ネストされた)クラスで使用できます。この場合、シリアライズはうまく機能します。唯一の障害は、直列化復元が適切に機能するために、内部クラスが「静的」としてマークされている必要があることです。こちらの説明をご覧ください:cowtowncoder.com/blog/archives/2010/08/entry_411.html
jpennell

3
なぜこれが起こるのか誰かが説明してくれませんか?非常によく似たエラーが発生しました。適切なコンストラクタはすべて整っているとは思いますが、逆シリアル化できませんでした。この投稿を読んだ後、ダミーのコンストラクターを追加した後にのみ機能しました。
user8658912

6
@Sumanこれをダミーコンストラクタとは呼びません。これは単なるデフォルトコンストラクタです。これは完全に有効であるだけでなく、多くの種類のJava Beanタイプの処理に必要です。(そしてもちろん、それは私をつまずきました。:
fool4jesus

2
デフォルトのコンストラクターを追加したくない場合(たとえば、不変オブジェクトを処理している場合)。JsonCreatorアノテーションを使用してオブジェクトをインスタンス化するために使用するコンストラクターまたはファクトリーメソッドを指示する必要があります。
Rahul

375

これは、次の理由で発生します。

  1. 内部クラスは静的として定義する必要があります

    private static class Condition {  //jackson specific    
    }
  2. あなたのクラスにデフォルトのコンストラクタがなかった可能性があります(更新:これはそうではないようです)

    private static class Condition {
        private Long id;
    
        public Condition() {
        }
    
        // Setters and Getters
    }
  3. セッターが適切に定義されていないか、表示されていない可能性があります(プライベートセッターなど)


95
私の場合、静的クラスが違いを生みました。ありがとう!
jalogar 2014年

3
もちろん、引数のないデフォルトの空のコンストラクタを宣言する必要ありません。Javaがそれを行います。(他のコンストラクターを定義しない限り)
Jonik

1
@ジョニック、そうだ!私の答えは古いですが、ジャクソンは内部クラスに到達するためにリフレクションを使用しているため、正しいことを覚えています。あなたが正しいことを確認してください。
azerafati 2015

6
ええ、私の経験はジャクソン2.4.4に関するものです。実際、Javaの暗黙のデフォルトコンストラクターで十分です。引数を取る他のコンストラクターを定義している場合(つまり、Javaが引数なしコンストラクターを生成しない場合)のみ、引数なしのコンストラクターを明示的に記述する必要があります。
Jonik、2015

2
また、私と一緒に、静的クラスはその日を救いました。
Simon

58

これに、ダミーのコンストラクターを必要としない別のソリューションを追加したいと思います。ダミーコンストラクターは少し面倒で、後で混乱するためです。安全なコンストラクターを提供でき、コンストラクターの引数に注釈を付けることで、jacksonがコンストラクターパラメーターとフィールド間のマッピングを決定できるようにします。

したがって、以下も機能します。注釈内の文字列はフィールド名と一致する必要があることに注意してください。

import com.fasterxml.jackson.annotation.JsonProperty;
public class ApplesDO {

        private String apple;

        public String getApple() {
            return apple;
        }

        public void setApple(String apple) {
            this.apple = apple;
        }

        public ApplesDO(CustomType custom){
            //constructor Code
        }

        public ApplesDO(@JsonProperty("apple")String apple) {
        }

}

この解決策でうまくいった。次のことだけを述べておきます。コンストラクタがありましたが、パラメータの名前がインスタンスパラメータの名前と異なっていたため、マッピングできませんでした。注釈を追加することで解決しましたが、パラメータの名前を変更してもおそらく機能するでしょう。
Fico 2015

コンストラクターパラメーターが応答にない場合はどうなりますか?別の方法で注入できますか?
Eddie Jaoude 2015年

ここで送信される唯一の重要なデータ、応答である文字列アップルです。
PiersyP 2015年

1
オブジェクトを不変にしたいので、ダミーのコンストラクターはオプションではなかったので、これは私にとって便利でした。
Jonathan Pullano 2016

私の場合@JsonCreator、でコンストラクタを追加することも必要@JsonPropertyです。
m1ld

31

この問題に遭遇したのは、内部クラスを使用してDOとして機能させようとした結果です。内部クラスの構築には(黙って)囲んでいるクラスのインスタンスが必要でした-これはジャクソンには利用できませんでした。

この場合、内部クラスを独自の.javaファイルに移動すると問題が解決しました。


6
内部クラスを独自の.javaファイルに移動することはできますが、 ますが静的修飾子を、@ bludreamの回答で述べられているように、問題が解決されます。
jmarks 2016

20

通常、このエラーはデフォルトのコンストラクタを作成しないために発生しますが、私の場合、問題は親クラス内で使用されたオブジェクトクラスを作成したことが原因でした。これは私の一日を無駄にしました。


入れ子のクラスを作成するだけで十分staticです。
ナマケモノ

13

経験則:マッピングクラスとして使用した各クラスのデフォルトコンストラクターを追加します。これを見逃して問題が発生しました!
デフォルトのコンストラクタを追加するだけで動作します。


素敵な答え。ありがとうございます。
Steve

9

この構造をテストしてください。私が正しいことを覚えている場合は、次のように使用できます。

{
    "applesRequest": {
        "applesDO": [
            {
                "apple": "Green Apple"
            },
            {
                "apple": "Red Apple"
            }
        ]
    }
}

次に、デフォルトのコンストラクターを各クラスに追加してください。これも役立つ場合があります。


機能しない:次のエラーが発生する: "org.codehaus.jackson.map.exc.UnrecognizedPropertyException:認識されないフィールド&quot; applesRequest&quot;(クラスcom.smartshop.dao.AllApplesDO)、無視できるものとしてマークされていません"
Lucky Murari

以前は、AllApplesDOのエラーではなく、少なくとも囲まれたクラスでのみスローされていました。現在は、最初のクラス自体でスローされます
Lucky Murari

デフォルトのコンストラクタが必要でした。ありがとう!
Planky

これは正しい答えとして選ばれるべきではありませんか?
高速歯

7

モデルクラスにダミーの空のコンストラクターを作成する必要があるため、jsonのマッピング中に、setterメソッドによって設定されます。


これは修正です。
David Kobia

私もそうです。オブジェクトにはさまざまなコンストラクターがあり、Jacksonによって使用されていると思われる空のコンストラクターをもう1つ作成しました。
アレッサンドロロアロ

5

コンストラクタに注釈を付ける場合は、すべてのフィールドに注釈を付ける必要があります。

Staff.nameフィールドがJSON文字列の "ANOTHER_NAME"にマッピングされていることに注意してください。

     String jsonInString="{\"ANOTHER_NAME\":\"John\",\"age\":\"17\"}";
     ObjectMapper mapper = new ObjectMapper();
     Staff obj = mapper.readValue(jsonInString, Staff.class);
     // print to screen

     public static class Staff {
       public String name;
       public Integer age;
       public Staff() {         
       }        

       //@JsonCreator - don't need this
       public Staff(@JsonProperty("ANOTHER_NAME") String   n,@JsonProperty("age") Integer a) {
        name=n;age=a;
       }        
    }

4

ジャクソンがデシリアライズに利用できるオプションを理解する必要があります。Javaでは、コンパイルされたコードにメソッド引数名はありません。そのため、Jacksonは通常、コンストラクターを使用して、すべてが既に設定された明確なオブジェクトを作成できません。

したがって、空のコンストラクターがあり、セッターもある場合は、空のコンストラクターとセッターを使用します。セッターがない場合は、ダークマジック(反射)を使用して設定します。

Jacksonでコンストラクターを使用する場合は、@ PiersyPの回答で言及されているアノテーションを使用する必要があります。ビルダーパターンを使用することもできます。例外が発生した場合は、頑張ってください。ジャクソンでのエラー処理は非常に時間がかかります。エラーメッセージで意味不明なことを理解するのは困難です。


「デフォルトの引数なしコンストラクタ」FooClass()が必要な理由は、SpringがJavaBean仕様に準拠しているためと考えられます。
atom88

とにかく、Javaのシリアル化とバイナリストリームへの逆シリアル化は、とにかく問題についてではありません。したがって、Jacksonが逆シリアル化で使用する複数のパターンを提供することは良いことです。結果のオブジェクトを不変にすることができるので、私は特にビルダーパターンが好きです。
Vlasec 2017年

2

前回の出版物については、Lombok 1.18。*を使用すると問題が発生するのと同じ問題がありました。

@Dataにはデフォルトで@RequiredArgsConstructor(パラメーター付きのコンストラクター)が含まれているため、私の解決策は@NoArgsConstructor(パラメーターなしのコンストラクター)を追加することでした。

lombokドキュメント https://projectlombok.org/features/all

それで問題は解決します:

package example.counter;

import javax.validation.constraints.NotNull;

import lombok.Data;

@Data
@NoArgsConstructor
public class CounterRequest {
    @NotNull
    private final Integer int1;

    @NotNull
    private final Integer int2;
}

0

カスタムジャクソンシリアライザー/デシリアライザーの失敗も問題である可能性があります。それはあなたのケースではありませんが、言及する価値があります。

私も同じ例外に直面し、それが事実でした。


0

私にとってこれは機能していましたが、ライブラリをアップグレードするとこの問題が発生しました。問題はこのようなクラスを持っていることでした:

package example.counter;

import javax.validation.constraints.NotNull;

import lombok.Data;

@Data
public class CounterRequest {
    @NotNull
    private final Integer int1;

    @NotNull
    private final Integer int2;
}

ロンボクの使用:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.0</version>
</dependency>

にフォールバック

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.10</version>
</dependency>

問題を修正しました。理由はわからないが、将来のために文書化したかった。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.