java convertir - JsonMappingException:no se encontró un constructor adecuado para el tipo[tipo simple, clase]:no se puede crear una instancia del objeto JSON




gson parsear (11)

Recibo el siguiente error al intentar obtener una solicitud JSON y procesarla:

org.codehaus.jackson.map.JsonMappingException: No se encontró un constructor adecuado para el tipo [tipo simple, clase com.myweb.ApplesDO]: no se puede crear una instancia del objeto JSON (¿es necesario agregar / habilitar información de tipo?)

Aquí está el JSON que estoy tratando de enviar:

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

En Controller, tengo el siguiente método de firma:

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

AllApplesDO es un envoltorio de ApplesDO:

public class AllApplesDO {

    private List<ApplesDO> applesDO;

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

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

Manzanas:

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

Creo que Jackson no puede convertir JSON en objetos Java para subclases. Por favor, ayuda con los parámetros de configuración para que Jackson convierta JSON en objetos Java. Estoy usando Spring Framework.

EDITAR: Incluyó el error principal que está causando este problema en la clase de muestra anterior. Por favor, busque la respuesta aceptada.


Answers

Debe darse cuenta de las opciones que Jackson tiene disponibles para la deserialización. En Java, los nombres de los argumentos de los métodos no están presentes en el código compilado. Es por eso que Jackson generalmente no puede usar constructores para crear un objeto bien definido con todo ya configurado.

Por lo tanto, si hay un constructor vacío y también hay establecedores, utiliza el constructor y los definidores vacíos. Si no hay colocadores, se utiliza algo de magia oscura (reflexiones) para hacerlo.

Si desea usar un constructor con Jackson, debe usar las anotaciones mencionadas por @PiersyP en su respuesta. También puedes usar un patrón de construcción. Si encuentras algunas excepciones, buena suerte. El manejo de errores en Jackson apesta a la perfección, es difícil entender que no haya errores en los mensajes de error.


Regla del pulgar : agregue un constructor predeterminado para cada clase que usó como clase de mapeo. Te perdiste esto y surgió el problema!
Simplemente agrega el constructor por defecto y debería funcionar.


Cuando me topé con este problema, fue el resultado de tratar de usar una clase interna para servir como DO. La construcción de la clase interna (en silencio) requería una instancia de la clase adjunta, que no estaba disponible para Jackson.

En este caso, mover la clase interna a su propio archivo .java solucionó el problema.


Para mí, esto solía funcionar, pero la actualización de las bibliotecas hacía que apareciera este problema. El problema era tener una clase como esta:

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

Utilizando lombok:

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

Cayendo de nuevo a

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

Solucionado el problema. No estoy seguro de por qué, pero quería documentarlo para el futuro.


Debe crear un constructor vacío ficticio en nuestra clase de modelo. Por lo tanto, al asignar json, se establece mediante el método de establecimiento.


En general, este error se produce porque no creamos el constructor predeterminado, pero en mi caso, el problema se produjo solo porque he creado una clase de objeto usado dentro de la clase principal. Esto ha desperdiciado todo mi día.


¿Puedes por favor probar esta estructura? Si recuerdo bien puedes usarlo de esta manera:

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

En segundo lugar, agregue el constructor predeterminado a cada clase, también podría ayudar.


Entonces, finalmente me di cuenta de cuál es el problema. No es un problema de configuración de Jackson como dudaba.

En realidad el problema estaba en la clase 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
    }
}

Hubo un constructor personalizado definido para la clase que lo convierte en el constructor predeterminado. La introducción de un constructor ficticio ha cometido el error de desaparecer:

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() {
    }

}

Me gustaría agregar otra solución a esto que no requiera un constructor ficticio. Dado que los constructores ficticios son un poco desordenados y, posteriormente, confusos. Podemos proporcionar un constructor seguro y al anotar los argumentos del constructor, permitimos que jackson determine la asignación entre el parámetro y el campo del constructor.

por lo que lo siguiente también funcionará. Tenga en cuenta que la cadena dentro de la anotación debe coincidir con el nombre del campo.

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

}

Si comienza a realizar anotaciones en el constructor, debe anotar todos los campos.

Observe que mi campo Staff.name se asigna a "ANOTHER_NAME" en la cadena 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;
       }        
    }

Cualquiera de los dos cambios

public Class Wrapper {
    private List<Student> students;
    //getters & setters here
}

a

public Class Wrapper {
    private List<Student> wrapper;
    //getters & setters here
}

---- o ----

Cambia tu cadena JSON a

{"students":[{"id":"13","name":"Fred"}]}




java json spring annotations jackson