JsonMappingException : [단순 유형, 클래스] 유형에 적합한 생성자가 없습니다. JSON 객체에서 인스턴스를 생성 할 수 없습니다.


438

JSON 요청을 가져 와서 처리하려고 할 때 다음 오류가 발생합니다.

org.codehaus.jackson.map.JsonMappingException : [단순 유형, 클래스 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를 사용하고 있습니다.

편집 : 위의 샘플 클래스 에서이 문제를 일으키는 주요 버그가 포함되었습니다-해결책에 대한 대답을 찾으십시오.


2
위의 코드에서 하위 클래스를 볼 수 없습니다.이 코드는 당신이 시도하거나 더 간단한 예제를 만들고 있습니까?
gkamal

작동 방식에 대한 추가 설명과 함께 답변을 추가했습니다. 기본적으로 Java는 런타임에서 메소드 인수 이름을 유지하지 않는다는 것을 알아야합니다.
Vlasec

답변:


565

그래서 마침내 문제가 무엇인지 깨달았습니다. 내가 의심 한 것처럼 Jackson 구성 문제는 아닙니다.

실제로 문제는 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
내부 (중첩) 클래스와 함께 jackson을 사용할 수 있습니다.이 경우 직렬화가 제대로 작동합니다. 직렬화 해제가 제대로 작동하려면 내부 클래스를 "정적"으로 표시해야합니다. 설명을 보시려면 여기를 클릭하십시오 : cowtowncoder.com/blog/archives/2010/08/entry_411.html
jpennell

3
왜 이런 일이 발생했는지 설명해 주시겠습니까? 비슷한 오류가 발생했습니다. 올바른 생성자가 모두 있다고 생각했지만 역 직렬화 할 수는 없습니다. 이 게시물을 읽은 후 더미 생성자를 추가 한 후에 만 ​​작동했습니다.
user8658912 14

6
@Suman 나는 이것을 더미 생성자로 부르지 않을 것입니다-그것은 단지 기본 생성자입니다. 완벽하게 유효 할뿐만 아니라 많은 종류의 Java Bean 유형 처리에 필요합니다. (물론, 그것은 나를 넘어
뜨렸다

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

3
물론 빈 인수가없는 기본 생성자를 선언 할 필요 가 없습니다 . Java가이를 수행합니다 ! (다른 생성자를 정의하지 않는 한)
Jonik

1
@Jonik, 맞아! Jackson이 내부 클래스에 도달하기 위해 리플렉션을 사용하고 있기 때문에 내 대답은 오래되었습니다. 내 생각은 오래되었지만 기본 생성자를 정의하는 것이 필요하다고 생각합니다 (최신 버전의 경우는 아닐 수도 있음). 당신이 맞을 수 있는지 확인하십시오.
azerafati

6
예, 잭슨 2.4.4에 대한 경험은 실제로 Java의 암시 적 기본 생성자로 충분합니다. 인수를 취하는 다른 생성자를 정의한 경우 에만 (즉, Java가 인수 없음을 생성하지 않는 경우) 인수 없음 생성자를 명시 적으로 작성해야합니다 .
Jonik

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

생성자 매개 변수가 응답에 없으면 어떻게합니까? 다른 방법으로 주사 할 수 있습니까?
Eddie Jaoude

여기에 전송되는 유일한 중요한 데이터는 문자열 사과입니다 입니다 응답.
PiersyP

1
내 객체를 변경할 수 없기 때문에 유용했습니다. 따라서 더미 생성자는 옵션이 아니 었습니다.
Jonathan Pullano

제 경우에는로 @JsonCreator생성자 를 추가해야합니다 @JsonProperty.
m1ld

31

이 문제에 부딪쳤을 때 내부 클래스를 사용하여 DO 역할을 수행 한 결과였습니다. 내적 계급의 건설은 (묵묵히) 잭슨이 이용할 수 없었던 폐쇄 계급의 실체가 필요했다.

이 경우 내부 클래스를 자체 .java 파일로 이동하면 문제가 해결되었습니다.


6
내부 클래스를 자체 .java 파일로 이동하는 반면 정적 수정자를 추가하면 @bludream의 답변에 언급 된 것처럼 문제가 해결됩니다.
jmarks

20

일반적 으로이 오류는 기본 생성자를 만들지 않기 때문에 발생하지만 제 경우에는 부모 클래스 내에서 객체 클래스를 사용했기 때문에 문제가 발생했습니다. 이것은 하루 종일 낭비되었습니다.


중첩 클래스를 만드는 것으로 충분합니다 static.
나무 늘보

13

Thumb Rule : 매핑 클래스로 사용한 각 클래스의 기본 생성자를 추가합니다. 당신이 이것을보고 문제가 발생합니다!
기본 생성자를 추가하면 작동합니다.


좋은 답변. 감사합니다. 내 하루를 저장했습니다.
Steve

9

이 구조를 테스트 해 주시겠습니까? 내가 올바른 것을 기억하면 다음과 같이 사용할 수 있습니다.

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

둘째, 각 클래스에 기본 생성자를 추가하여 도움이 될 수도 있습니다.


작동하지 않음 : 다음 오류가 발생했습니다. "org.codehaus.jackson.map.exc.UnrecognizedPropertyException : 인식 할 수없는 필드"applesRequest "(class com.smartshop.dao.AllApplesDO), 무시할 수없는 것으로 표시됨"
Lucky Murari

이전에는 적어도 AllApplesDO에서 오류를 겪지 않고 동봉 된 클래스에 대해서만 발생했습니다. 이제 첫 번째 클래스 자체에 대해 발생합니다
Lucky Murari

기본 생성자가 필요했습니다. 감사!
Planky

이것이 올바른 답변으로 선택되어서는 안됩니까?
빠른 치아

7

모델 클래스에서 더미 빈 생성자를 만들어야하므로 json을 매핑하는 동안 setter 메서드로 설정됩니다.


이것은 수정입니다.
David Kobia

저도 마찬가지입니다. 내 객체에 대해 여러 가지 생성자가 있었기 때문에 jackson이 사용하는 또 다른 빈 생성자를 만들었습니다.
Alessandro Roaro

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

deserialization에 Jackson이 사용할 수있는 옵션을 알고 있어야합니다. Java에서는 메소드 인수 이름이 컴파일 된 코드에 없습니다. 그렇기 때문에 Jackson은 일반적으로 생성자를 사용하여 이미 설정된 모든 항목으로 잘 정의 된 객체를 만들 수 없습니다.

따라서 빈 생성자가 있고 세터도있는 경우 빈 생성자와 세터를 사용합니다. 세터가 없으면 어두운 마법 (반사)을 사용합니다.

Jackson과 함께 생성자를 사용하려면 @PiersyP에서 언급 한대로 주석을 사용해야합니다. 빌더 패턴을 사용할 수도 있습니다. 예외가 발생하면 행운을 빕니다. Jackson의 오류 처리는 시간이 많이 걸리므로 오류 메시지에서 그 횡설수설을 이해하기 어렵습니다.


"기본 인수없는 생성자"FooClass ()가 필요한 이유는 Spring이 JavaBean Specification을 따르기 때문일 가능성이 높습니다. 이는 객체를 직렬화 및 직렬화 해제 할 때 자동으로 마샬링 및 비 정렬 화하기 위해 작동해야하기 때문입니다.
atom88

글쎄, Java 직렬화와 이진 스트림으로의 직렬화 해제는 문제가 아닙니다. 따라서 Jackson이 직렬화 해제와 함께 사용할 여러 패턴을 제공하는 것이 좋습니다. 결과 객체를 변경할 수 없으므로 빌더 패턴이 특히 좋습니다.
Vlasec

3

마지막 출판물에 관해서는 Lombok 1.18. *를 사용하면 문제가 발생하는 것과 동일한 문제가있었습니다.

@Data는 기본적으로 @RequiredArgsConstructor (매개 변수가있는 생성자)를 포함하기 때문에 내 솔루션은 @NoArgsConstructor (매개 변수가없는 생성자)를 추가하는 것이 었습니다.

롬복 문서 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.