JSONリクエストを取得して処理しようとすると、次のようなエラーが表示されます。
org.codehaus.jackson.map.JsonMappingException:type [simple type、class com.myweb.ApplesDO]に適したコンストラクタが見つかりません:JSONオブジェクトからインスタンス化できません(タイプ情報を追加または有効にする必要がありますか?)
これが送信しようとしているJSONです。
{
"applesDO" : [
{
"Apple" : "Green Apple"
},
{
"Apple" : "Red Apple"
}
]
}
Controllerでは、私は以下のメソッドシグネチャを持っています。
@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オブジェクトに変換できないと思います。 JacksonがJSONをJavaオブジェクトに変換するための設定パラメータを手伝ってください。私はSpring Frameworkを使っています。
編集:上記のサンプルクラスでこの問題を引き起こしている主なバグを含みました - 解決策として受け入れられた答えを見てください。
それで、ついに私はその問題が何であるかに気づきました。私が疑ったように、それはジャクソンの構成問題ではありません。
実際には問題は ApplesDO Classにありました。
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() {
}
}
これはこれらの理由で起こります:
あなたの内部クラスは static のように定義されるべきです
private static class Condition { //jackson specific
}
それはあなたがあなたのクラスにデフォルトコンストラクタを持っていなかったということかもしれません( UPDATE: これはそうではないようです)
private static class Condition {
private Long id;
public Condition() {
}
// Setters and Getters
}
あなたのセッターが正しく定義されていないか見えないかもしれません(例えばプライベートセッター)
これにダミーのコンストラクタを必要としない別の解決策を追加したいと思います。ダミーコンストラクタは少し面倒で、その後混乱します。安全なコンストラクタを提供し、コンストラクタ引数に注釈を付けることによって、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) {
}
}
この問題に遭遇したとき、それはDOとして機能するために内部クラスを使用しようとした結果でした。内部クラスの構築には(静かに)囲むクラスのインスタンスが必要でした - これはJacksonには利用できませんでした。
この場合、内部クラスを独自の.Javaファイルに移動すると問題が解決しました。
一般にこのエラーは、デフォルトのコンストラクタを作成していないために発生しますが、私の場合は、親クラス内で使用済みオブジェクトクラスを作成したことが原因で問題が発生していました。これは私の一日を無駄にしました。
Thumb Rule :マッピングクラスとして使用した各クラスのデフォルトコンストラクタを追加します。あなたはこれを逃したし、問題が起きます!
デフォルトコンストラクタを追加するだけで動作します。
この構造をテストしてください。私が正しいことを覚えているなら、あなたはこのようにそれを使うことができます:
{
"applesRequest": {
"applesDO": [
{
"Apple": "Green Apple"
},
{
"Apple": "Red Apple"
}
]
}
}
第二に、それがまた助けるかもしれない各クラスにデフォルトコンストラクタを追加してください。
あなたは私たちのモデルクラスにダミーの空のコンストラクタを作成する必要があります。jsonをマッピングしている間、それはsetterメソッドによって設定されます。
コンストラクターに注釈を付ける場合は、すべてのフィールドに注釈を付ける必要があります。
私の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;
}
}
あなたは、Jacksonが逆シリアル化のためにどのような選択肢を持っているかを理解しなければなりません。 Javaでは、メソッド引数名はコンパイル済みコードには存在しません。だからこそ、Jacksonは一般的にコンストラクタを使用して、すでにすべてが設定された明確なオブジェクトを作成することはできません。
したがって、空のコンストラクタがあり、セッターもある場合は、空のコンストラクターとセッターを使用します。設定者がいない場合は、それを行うためにいくつかの暗い魔法(反射)が使用されます。
Jacksonでコンストラクタを使用したい場合は、@PiersyPの回答で述べられているようにアノテーションを使用する必要があります。ビルダーパターンを使用することもできます。いくつかの例外が発生した場合は、幸運を祈ります。ジャクソンでのエラー処理は大きな時間を浪費しています。エラーメッセージの意味がわからないことは理解できません。
前回の出版物に関して、私は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;
}
カスタムジャクソンシリアライザ/デシリアライザの失敗も問題になる可能性があります。それはあなたのケースではありませんが、それは言及する価値があります。
私は同じ例外に直面し、それが事実でした。
私にとっては、これは機能していましたが、ライブラリをアップグレードするとこの問題が発生しました。問題は、このようなクラスがあったことです。
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;
}
Lombokを使う
<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>
問題を修正しました。理由はわかりませんが、将来のために文書化したいと考えました。