JsonMappingException: ไม่พบตัวสร้างที่เหมาะสมสำหรับชนิด [ชนิดง่าย ๆ คลาส]: ไม่สามารถสร้างอินสแตนซ์จากวัตถุ 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 Objects ฉันกำลังใช้ Spring Framework

แก้ไข: รวมข้อผิดพลาดที่สำคัญที่ทำให้เกิดปัญหานี้ในคลาสตัวอย่างข้างต้น - โปรดดูคำตอบที่ได้รับการยอมรับสำหรับการแก้ปัญหา


2
ฉันไม่เห็นคลาสย่อยใด ๆ ในโค้ดด้านบนรหัสนี้เป็นสิ่งที่คุณพยายามหรือคุณทำขึ้นเป็นตัวอย่างที่ง่ายกว่าหรือไม่
gkamal

ฉันเพิ่มคำตอบพร้อมคำอธิบายเพิ่มเติมเกี่ยวกับวิธีการทำงาน โดยพื้นฐานแล้วคุณจำเป็นต้องรู้ว่าจาวาไม่ได้เก็บชื่ออาร์กิวเมนต์วิธีไว้ในรันไทม์
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

181
คุณสามารถใช้แจ็คสันกับคลาสภายใน (ซ้อนกัน) การทำให้เป็นอนุกรมใช้ได้ดีในกรณีนี้ บล็อกสะดุดเพียงอย่างเดียวคือคลาสภายในจะต้องทำเครื่องหมายว่า "คงที่" เพื่อให้การดีซีเรียลไลเซชั่นทำงานได้อย่างถูกต้อง ดู exlanation ที่นี่: cowtowncoder.com/blog/archives/2010/08/entry_411.html
jpennell

3
ใครช่วยอธิบายหน่อยได้ไหมว่าทำไมสิ่งนี้ถึงเกิดขึ้น ฉันมีข้อผิดพลาดที่คล้ายกันมาก คิดว่าสิ่งที่ถูกต้องอยู่ในสถานที่ก่อสร้าง แต่ไม่สามารถทำให้เสื่อมเสียได้ ใช้งานได้เฉพาะหลังจากที่ฉันเพิ่มตัวสร้างหุ่นจำลองหลังจากอ่านบทความนี้
user8658912

6
@ มนุษย์ฉันจะไม่เรียกสิ่งนี้ว่าเป็นผู้สร้างหุ่น - มันเป็นแค่ตัวสร้างปริยาย ไม่เพียง แต่จะถูกต้องสมบูรณ์แบบ แต่จำเป็นสำหรับการประมวลผลชนิดถั่ว java หลายชนิด (และแน่นอนมันทำให้ฉันสะดุด :-))
fool4jesus

2
หากคุณไม่ต้องการเพิ่มตัวสร้างเริ่มต้น (เช่นเมื่อคุณจัดการกับวัตถุที่ไม่เปลี่ยนรูป) คุณจะต้องบอกวิธีการสร้างหรือโรงงานที่จะใช้ในการยกตัวอย่างวัตถุโดยใช้คำอธิบายประกอบ JsonCreator
ราหุล

375

สิ่งนี้เกิดขึ้นเนื่องจากเหตุผลเหล่านี้:

  1. คลาสภายในของคุณควรนิยามเป็นแบบสแตติก

    private static class Condition {  //jackson specific    
    }
  2. อาจเป็นเพราะคุณไม่มีคอนสตรัคเตอร์เริ่มต้นในชั้นเรียนของคุณ ( อัพเดต:ดูเหมือนจะไม่เป็นเช่นนั้น)

    private static class Condition {
        private Long id;
    
        public Condition() {
        }
    
        // Setters and Getters
    }
  3. อาจเป็นเพราะ Setters ของคุณไม่ได้กำหนดไว้อย่างเหมาะสมหรือมองไม่เห็น (เช่นเซ็ตส่วนตัว)


95
ระดับคงที่สร้างความแตกต่างในกรณีของฉัน ขอบคุณ!
jalogar

3
และแน่นอนคุณไม่จำเป็นต้องประกาศตัวสร้างค่าเริ่มต้นที่ว่างเปล่าและไม่มีข้อโต้แย้งJava ทำเพื่อคุณ ! (ตราบใดที่คุณไม่ได้กำหนดก่อสร้างอื่น ๆ .)
Jonik

1
@ Jonik ใช่ไหม! คำตอบของฉันเก่าถ้าฉันจำได้ถูกต้องเนื่องจากแจ็กสันใช้การสะท้อนเพื่อเข้าเรียนชั้นในฉันคิดว่ามันจำเป็นต้องกำหนด constructor เริ่มต้น (อาจไม่ใช่กรณีในรุ่นที่ใหม่กว่า) แต่เนื่องจากฉันไม่ แน่ใจว่าคุณถูกต้อง
azerafati

6
ใช่ประสบการณ์ของฉันอยู่กับแจ็คสัน 2.4.4: แน่นอนว่าตัวสร้างปริยายของ Java ก็เพียงพอแล้ว คุณต้องเขียนตัวสร้าง no-args อย่างชัดเจนเฉพาะเมื่อคุณได้กำหนดconstructor อื่น ๆที่รับอาร์กิวเมนต์ (เช่นเมื่อ Java ไม่ได้สร้าง no-args ให้คุณ)
Jonik

2
นอกจากนี้ฉันยังเรียนที่ไม่หยุดนิ่งช่วยชีวิตทั้งวัน
Simon

58

ฉันต้องการเพิ่มโซลูชันอื่นให้กับสิ่งนี้โดยไม่ต้องใช้ตัวสร้างแบบจำลอง เนื่องจากตัวสร้างแบบจำลองค่อนข้างยุ่งเหยิงและสับสนในภายหลัง เราสามารถจัดให้มีคอนสตรัคเตอร์ที่ปลอดภัยและโดยใส่คำอธิบายประกอบอาร์กิวเมนต์คอนสตรัคเตอร์ที่เราอนุญาตให้แจ็คสันเพื่อกำหนดการแมประหว่างพารามิเตอร์คอนสตรัคเตอร์และฟิลด์

ดังนั้นต่อไปนี้จะใช้งานได้ หมายเหตุสตริงภายในคำอธิบายประกอบจะต้องตรงกับชื่อฟิลด์

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

เกิดอะไรขึ้นถ้าพารามิเตอร์คอนสตรัคเตอร์ไม่ตอบสนอง? สามารถฉีดอีกวิธีหนึ่งได้หรือไม่
Eddie Jaoude

ข้อมูลสำคัญเท่านั้นที่ถูกส่งมาที่นี่คือแอปเปิ้ล String ที่เป็นการตอบสนอง
PiersyP

1
สิ่งนี้มีประโยชน์สำหรับฉันเพราะฉันต้องการให้วัตถุของฉันไม่เปลี่ยนรูปดังนั้นผู้สร้างหุ่นจำลองจึงไม่มีทางเลือก
Jonathan Pullano

ในกรณีของฉันก็ยังต้องไปเพิ่มในคอนสตรัคด้วย@JsonCreator @JsonProperty
m1ld

31

เมื่อฉันพบปัญหานี้เป็นผลมาจากการพยายามใช้คลาสภายในเพื่อทำหน้าที่เป็น DO การก่อสร้างชั้นใน (เงียบ ๆ ) จำเป็นต้องใช้ตัวอย่างของคลาสที่ปิด - ซึ่งไม่สามารถใช้ได้กับแจ็คสัน

ในกรณีนี้การย้ายคลาสภายในไปยังไฟล์. java ของตัวเองแก้ไขปัญหาได้


6
ในขณะที่การย้ายชั้นในไปยังไฟล์. java ของตัวเองทำงานได้เพิ่ม ตัวแก้ไขแบบสแตติกยังแก้ไขปัญหาตามที่ระบุไว้ในคำตอบของ @ bludream
jmarks

20

โดยทั่วไปแล้วข้อผิดพลาดนี้เกิดขึ้นเพราะเราไม่ได้กำหนดค่าเริ่มต้น แต่ในกรณีของฉันปัญหามาเนื่องจากฉันได้ใช้คลาสวัตถุภายในคลาสแม่ นี่ทำให้ฉันเสียทั้งวัน


staticก็พอที่จะทำให้ชั้นซ้อนกัน
เฉื่อยชา

13

กฎนิ้วหัวแม่มือ : เพิ่มตัวสร้างเริ่มต้นสำหรับแต่ละคลาสที่คุณใช้เป็นคลาสการแมป คุณพลาดและเกิดปัญหาขึ้น!
เพียงเพิ่มตัวสร้างเริ่มต้นและควรจะทำงาน


คำตอบที่ดีขอขอบคุณบันทึกวันของฉัน
Steve

9

คุณช่วยทดสอบโครงสร้างนี้ได้ไหม ถ้าฉันจำถูกต้องคุณสามารถใช้วิธีนี้:

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

ประการที่สองโปรดเพิ่มตัวสร้างเริ่มต้นให้กับแต่ละคลาสที่อาจช่วยได้เช่นกัน


ไม่ทำงาน: รับข้อผิดพลาดต่อไปนี้: "org.codehaus.jackson.map.exc.UnrecognizedPropertyException: ฟิลด์ที่ไม่รู้จัก & quot; applesRequest & quot; (Class com.smartshop.dao.AllApplesDO), ไม่ได้ทำเครื่องหมายว่าไม่สามารถเพิกเฉยได้"
Lucky Murari

ก่อนหน้านี้มันเคยมีข้อผิดพลาดอย่างน้อยสำหรับ AllApplesDO และพ่นเฉพาะคลาสที่ปิด .. ตอนนี้มันพ่นสำหรับคลาสแรกเอง
Lucky Murari

ต้องการตัวสร้างเริ่มต้น ขอบคุณ!
Planky

ไม่ควรเลือกสิ่งนี้เป็นคำตอบที่ถูกต้อง?
ฟันเร็ว

7

คุณต้องสร้างตัวสร้างหุ่นที่ว่างเปล่าในคลาสโมเดลของเราดังนั้นขณะทำการแมป json มันถูกกำหนดโดยเมธอดเซเตอร์


นี่คือการแก้ไข
David Kobia

นั่นคือกรณีสำหรับฉัน ฉันมีคอนสตรัคเตอร์ที่แตกต่างกันมากมายสำหรับวัตถุของฉันและดังนั้นฉันเพิ่งสร้างอันใหม่ที่ว่างเปล่าซึ่งเห็นได้ชัดว่าใช้โดยแจ็คสัน
Alessandro Roaro

5

หากคุณเริ่มสร้างหมายเหตุประกอบตัวสร้างคุณต้องใส่คำอธิบายประกอบฟิลด์ทั้งหมด

โปรดสังเกตว่าฟิลด์ Staff.name ของฉันถูกแมปกับ "ANOTHER_NAME" ในสตริง JSON

     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 คุณต้องใช้คำอธิบายประกอบตามที่ @PiersyP พูดถึงในคำตอบของเขา คุณยังสามารถใช้รูปแบบการสร้าง หากคุณพบข้อยกเว้นโชคดี การจัดการข้อผิดพลาดในแจ็คสันดูดครั้งใหญ่มันยากที่จะเข้าใจซึ่งพูดพล่อยๆในข้อความแสดงข้อผิดพลาด


เหตุผลที่คุณต้องการ "default no argument constructor" FooClass () น่าจะเป็นเพราะ Spring เป็นไปตามข้อกำหนด JavaBean ซึ่งจำเป็นต้องใช้สิ่งนี้ในการจัดการ marshalling และ unmarshalling โดยอัตโนมัติเมื่อซีเรียลไลซ์
atom88

การทำให้เป็นอันดับจาวาและการดีซีเรียลไลเซชันเป็นไบนารีสตรีมนั้นไม่ใช่คำถาม ดังนั้นจึงเป็นเรื่องดีที่แจ็คสันเสนอหลายรูปแบบที่จะใช้กับการดีซีเรียลไลเซชัน ฉันชอบรูปแบบการสร้างเป็นพิเศษเพราะมันทำให้วัตถุที่เป็นผลให้ไม่เปลี่ยนรูป
Vlasec

3

เกี่ยวกับสิ่งพิมพ์ล่าสุดที่ฉันมีปัญหาเดียวกันกับที่ใช้ลอมบอก 1.18. * สร้างปัญหา

โซลูชันของฉันคือการเพิ่ม @NoArgsConstructor (ตัวสร้างโดยไม่มีพารามิเตอร์) เนื่องจาก @Data รวมโดย @RequiredArgsConstructor เป็นค่าเริ่มต้น (ตัวสร้างพร้อมพารามิเตอร์)

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

ความล้มเหลวของแจ็คสันที่กำหนดเอง Serializers / Deserializers ก็อาจเป็นปัญหา แม้ว่าจะไม่ใช่กรณีของคุณ แต่ก็คุ้มค่าที่จะกล่าวถึง

ฉันประสบข้อยกเว้นเดียวกันและเป็นกรณี


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

ใช้ 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>

แก้ไขปัญหา ไม่แน่ใจว่าทำไม แต่ต้องการเอกสารเพื่ออนาคต

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.