Beim Versuch, eine JSON-Anforderung abzurufen und zu verarbeiten, wird die folgende Fehlermeldung angezeigt:
org.codehaus.jackson.map.JsonMappingException: Kein geeigneter Konstruktor für Typ [einfacher Typ, Klasse com.myweb.ApplesDO] gefunden: Kann nicht aus JSON-Objekten instanziieren (müssen Typinformationen hinzufügen/aktivieren?)
Hier ist der JSON, den ich zu senden versuche:
{
"applesDO" : [
{
"Apple" : "Green Apple"
},
{
"Apple" : "Red Apple"
}
]
}
In Controller habe ich die folgende Methodensignatur:
@RequestMapping("showApples.do")
public String getApples(@RequestBody final AllApplesDO applesRequest){
// Method Code
}
AllApplesDO ist ein Wrapper von 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
}
}
Ich denke, dass Jackson JSON nicht in Java-Objekte für Unterklassen konvertieren kann. Bitte helfen Sie mit den Konfigurationsparametern für Jackson, um JSON in Java-Objekte zu konvertieren. Ich benutze Spring Framework.
BEARBEITEN: Der Hauptfehler, der dieses Problem verursacht, wurde in die obige Beispielklasse aufgenommen. Bitte suchen Sie nach einer akzeptierten Antwort.
So wurde mir endlich klar, was das Problem ist. Es ist kein Jackson-Konfigurationsproblem, wie ich bezweifelte.
Eigentlich war das Problem in 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
}
}
Für die Klasse wurde ein benutzerdefinierter Konstruktor definiert, der ihn zum Standardkonstruktor macht. Die Einführung eines Dummy-Konstruktors hat den Fehler gemacht, zu verschwinden:
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() {
}
}
Dies geschieht aus folgenden Gründen:
ihre innere Klasse sollte als static definiert sein.
private static class Condition { //jackson specific
}
Möglicherweise haben Sie in Ihrer Klasse keinen Standardkonstruktor ( UPDATE: Dies scheint nicht der Fall zu sein).
private static class Condition {
private Long id;
public Condition() {
}
// Setters and Getters
}
Möglicherweise sind Ihre Setter nicht richtig definiert oder nicht sichtbar (z. B. private Setter)
Ich möchte eine weitere Lösung hinzufügen, für die kein Dummy-Konstruktor erforderlich ist. Da Dummy-Konstruktoren ein bisschen chaotisch und anschließend verwirrend sind. Wir können einen sicheren Konstruktor bereitstellen. Indem wir die Konstruktorargumente kommentieren, können wir die Zuordnung zwischen Konstruktorparameter und Feld bestimmen.
das Folgende wird auch funktionieren. Beachten Sie, dass die Zeichenfolge in der Anmerkung mit dem Feldnamen übereinstimmen muss.
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) {
}
}
Als ich auf dieses Problem stieß, war es das Ergebnis eines Versuchs, eine innere Klasse als DO zu verwenden. Der Bau der inneren Klasse (lautlos) erforderte eine Instanz der umgebenden Klasse - die Jackson nicht zur Verfügung stand.
In diesem Fall wurde das Problem durch Verschieben der inneren Klasse in eine eigene .Java-Datei behoben.
Im Allgemeinen tritt dieser Fehler auf, weil wir keinen Standardkonstruktor erstellen, aber in meinem Fall. Das hat meinen ganzen Tag verschwendet.
Thumb Rule : Fügt einen Standardkonstruktor für jede Klasse hinzu, die Sie als Zuordnungsklasse verwendet haben. Sie haben dies verpasst und es entstehen Probleme!
Fügen Sie einfach den Standardkonstruktor hinzu und es sollte funktionieren.
Können Sie bitte diese Struktur testen? Wenn ich mich recht erinnere, können Sie es folgendermaßen verwenden:
{
"applesRequest": {
"applesDO": [
{
"Apple": "Green Apple"
},
{
"Apple": "Red Apple"
}
]
}
}
Zweitens fügen Sie bitte zu jeder Klasse einen Standardkonstruktor hinzu, der möglicherweise ebenfalls hilfreich ist.
Sie müssen einen leeren Dummy-Konstruktor in unserer Modellklasse erstellen. Wenn Sie also json abbilden, wird dies durch die Setter-Methode festgelegt.
Wenn Sie mit dem Kommentieren des Konstruktors beginnen, müssen Sie alle Felder mit Anmerkungen versehen.
Beachten Sie, dass mein Staff.name-Feld in JSON-Zeichenfolge "ANOTHER_NAME" zugeordnet ist.
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;
}
}
Sie müssen wissen, welche Möglichkeiten Jackson zur Deserialisierung zur Verfügung hat. In Java sind Methodenargumentnamen nicht im kompilierten Code vorhanden. Aus diesem Grund kann Jackson Konstruktoren nicht generell verwenden, um ein gut definiertes Objekt zu erstellen, in dem bereits alles festgelegt ist.
Wenn also ein leerer Konstruktor vorhanden ist und es auch Setter gibt, werden der leere Konstruktor und die Setter verwendet. Wenn es keine Setter gibt, wird dazu dunkle Magie (Reflexionen) verwendet.
Wenn Sie einen Konstruktor mit Jackson verwenden möchten, müssen Sie die von @PiersyP in seiner Antwort genannten Anmerkungen verwenden. Sie können auch ein Builder-Muster verwenden. Wenn Sie auf einige Ausnahmen stoßen, viel Glück. Die Fehlerbehandlung in Jackson ist eine Scheiße, es ist schwer zu verstehen, dass in Fehlermeldungen Quatsch gemacht wird.
In Bezug auf die letzte Veröffentlichung hatte ich das gleiche Problem, bei dem die Verwendung von Lombok 1.18. * Das Problem verursachte.
Meine Lösung bestand darin, @NoArgsConstructor (Konstruktor ohne Parameter) hinzuzufügen, da @Data standardmäßig @RequiredArgsConstructor (Konstruktor mit Parametern) enthält.
lombok Documentation https://projectlombok.org/features/all
Das würde das Problem lösen:
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;
}
Das Versagen von benutzerdefinierten Jackson-Serialisierern/Deserialisierern könnte ebenfalls das Problem sein. Obwohl es nicht Ihr Fall ist, ist es erwähnenswert.
Ich sah die gleiche Ausnahme und das war der Fall.
Für mich funktionierte das früher, aber beim Aktualisieren von Bibliotheken wurde dieses Problem angezeigt. Das Problem war, eine Klasse wie diese zu haben:
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 verwenden:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.0</version>
</dependency>
Rückfall auf
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
Problem behoben Nicht sicher warum, wollte es aber für die Zukunft dokumentieren.