7
votes

Aucun constructeur principal ou par défaut trouvé pour l'interface java.util.List Rest API Spring boot

Je passe un corps de requête à une requête POST sur le facteur similaire à ceci:

public class Element() {
@JsonProperty("elementName")
private String name;
@JsonProperty("amount")
private double amount;
@JsonProperty("measurement")
private String measurement;

public Element() {}

public Element(String name, double amount, String measurement)
{
//assignments
}
}

La méthode create dans le contrôleur rest ressemble à ceci.

public class Artifact() {
@Field("elements")
private List<Element> elements;
@JsonProperty("typeName")
private String typeName;

public Artifact() {}

public Artifact(String typeName, List<Element> elements)
{
this.typeName = typeName;
this.elements = elements;
}
}

Planet et tous ses objets imbriqués ont un constructeur par défaut tel que:

public class Planet {
@JsonProperty("name")
private String name;
@Field("artifacts")
private List<Artifact> artifacts;

public Planet() {}

public Planet(String name, List<Artifact> artifacts)
{
this.name = name;
this.artifacts = artifacts;
}
//setters and getters

}

Cependant, je ne suis pas en mesure de créer un nouvel objet planète en raison du manque de constructeur par défaut. Veuillez aider!

EDIT: Classe de planète

public Planet() {}

Classe d'artefact:

  @RequestMapping("/create")
  public Planet create(@RequestBody Planet data) {
      Planet mars = planetService.create(data.getName(),data.getArtifacts());
      return mars;

Classe d'élément:

 "name":"Mars",
"artifacts":[
   {
      "elements":[
         {
            "name":"carbon",
            "amount":0.5,
            "measurement":"g"
         }
      ],
      "typeName":"typeA"
   },
   {
      "elements":[
         {
            "name":"hydrogen",
            "amount":0.2,
            "measurement":"g"
         }
      ],
      "typeName":"typeB"
   }
]


2 commentaires

Pouvez-vous publier le Planet.java?


Fait, a publié une version simplifiée


4 Réponses :


0
votes

vous devriez écrire comme ci-dessous:

...
public String create(@RequestBody JSONObject requestParams) {
      String name=requestParams.getString("name");
      List<Planet> planetArtifacts=requestParams.getJSONArray("artifacts").toJavaList(Planet.Class);
...


1 commentaires

Salut, je pense qu'il est préférable d'avoir une classe wrapper pour recevoir le corps de votre requête. De cette façon, le contrat d'API est très clair et clair car personne n'a à passer par votre service pour déterminer réellement ce que l'API attend. Qu'est-ce que tu penses?



4
votes

Je ne comprends pas quel est le problème auquel vous êtes confronté, mais je peux voir une erreur tout de suite, alors deviner que c'est le problème auquel vous êtes confronté, je vais vous donner une solution.

Créez une classe qui correspond à votre structure de données json comme ceci:

public class Planet {
private String typeName; // key in json should match variable name for proper deserialization or you need to use some jackson annotation to map your json key to your variable name.
private List<Element> elements;

public Planet() {}

public Planet(String typeName, List<Element> elements)
{
this.typeName = typeName;
this.elements = elements;
}
//setters and getters. Remember to change your setters and getter from name to typeName.

}

Ensuite, votre contrôleur devrait ressembler à ceci. Fondamentalement, vous @RequestBody mettre @RequestBody à tous les paramètres que vous souhaitez recevoir de la demande JSON. Auparavant, vous ne @RequestBody pour le paramètre de nom et non pour le paramètre d'artefact et puisque le corps de la requête ne peut être consommé qu'une seule fois, vous avez donc besoin d'une classe wrapper pour recevoir le corps de la requête complet en utilisant une seule annotation @RequestBody .

@RequestMapping("/create")
  public String create(@RequestBody PlanetData data) {
      Planet mars = planetService.create(data.getName(),data.getArtifacts());
      return mars.toString();
  }

Edit: En regardant la classe Planet, elle a également besoin de quelques modifications

Class PlanetData {
    private String name;
    private List<Planet> artifacts;

    public PlanetData(String name, List<Planet> artifacts){
        name = name;
        artifacts = artifacts;
    }

    // include rest of getters and setters here.
}

J'espère que cela résout votre problème.


7 commentaires

Merci, cela a aidé! Je reçois Impossible de construire une instance de com.Planet (bien qu'au moins un créateur existe): pas de méthode constructeur / usine d'argument String à désérialiser à partir de la valeur String ('nom'); l'exception imbriquée est com.fasterxml.jackson.databind.exc.MismatchedInputException


C'est parce que dans votre Json, pour Planet info, votre clé est typeName , pas name , mais dans votre classe Planet, vous l'avez gardée comme name . Vérifiez la dernière section de ma réponse, j'ai changé le name en typeName dans votre classe Planet. De plus, si cela vous a aidé, veuillez le marquer comme réponse. Merci


typeName appartient à la classe Artifact


Pourquoi changez-vous autant le nom et le contenu des classes. Auparavant, votre classe Planet contenait le nom et les éléments et maintenant elle contient le nom et les artefacts. Veuillez modifier votre question une dernière fois afin que je puisse aligner ma réponse sur votre classe actuelle, sinon nous serons tous les deux confus. Ajoutez tout le code de vos classes en masquant tous les getter et setters.


Désolé pour la confusion, je l'ai changé maintenant. Merci pour l'aide


Veuillez ajouter vos autres classes ainsi que la classe Elements et la classe Artifact pour éliminer toute confusion supplémentaire.


Je suis capable de créer l'objet maintenant, merci. J'obtiens une autre erreur, devra créer un nouveau message.



0
votes

Je suppose qu'il essaie d'appeler new List() qui n'a pas de constructeur. Essayez d'utiliser le new ArrayList<>() dans vos signatures.

Si cela fonctionne de cette façon, vous avez trouvé l'erreur. Ensuite, repensez votre concept d'appel de méthodes, car vous voudriez généralement éviter d'utiliser des implémentations de List dans les signatures de méthode


2 commentaires

Merci, cela a fonctionné, mais obtenir une chaîne étrange dans l'objet qui est créé.


C'était juste une réponse précise à votre question sur le sujet. Comme je l'ai dit, vous devriez repenser votre concept. Voici déjà quelques réponses qui vous aideront



7
votes

J'ai eu la même erreur quand j'ai oublié le @RequestBody avant le paramètre

  @RequestMapping("/create")
  public Planet create(@RequestBody Planet data) {


0 commentaires