Angenommen, ich habe ein Pojo:
import org.codehaus.jackson.map.*;
public class MyPojo {
int id;
public int getId()
{ return this.id; }
public void setId(int id)
{ this.id = id; }
public static void main(String[] args) throws Exception {
MyPojo mp = new MyPojo();
mp.setId(4);
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationConfig.Feature.WRAP_ROOT_VALUE, true);
System.out.println(mapper.getSerializationConfig().isEnabled(SerializationConfig.Feature.WRAP_ROOT_VALUE));
System.out.println(mapper.writeValueAsString(mp));
}
}
Wenn ich mit dem Jackson ObjectMapper serialisiere, bekomme ich es einfach
true
{"id":4}
aber ich möchte
true
{"MyPojo":{"id":4}}
Ich habe alles gesucht, Jacksons Dokumentation ist wirklich unorganisiert und meistens nicht mehr aktuell.
Durch Hinzufügen der Jackson-Annotation @JsonTypeInfo
auf Klassenebene können Sie die erwartete Ausgabe erhalten. Ich habe gerade keine Änderungen in Ihrer Klasse hinzugefügt.
package com.test.jackson;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
@JsonTypeInfo(include=As.WRAPPER_OBJECT, use=Id.NAME)
public class MyPojo {
// Remain same as you have
}
Ausgabe:
{
"MyPojo": {
"id": 4
}
}
Ich benutze nicht Jackson, aber beim Suchen habe ich diese Konfiguration gefunden, die scheinbar Ihren Wünschen entspricht: WRAP_ROOT_VALUE
Funktion, die aktiviert werden kann, um einen Root-Wert zu erstellen (normalerweise JSON-Objekt, kann jedoch ein beliebiger Typ sein), das in ein einzelnes Eigenschafts-JSON-Objekt eingeschlossen wird, wobei key als "root-Name" gilt, wie durch Annotation Introspector (insbesondere für JAXB, das @XmlRootElement verwendet) bestimmt .name) oder Fallback (nicht qualifizierter Klassenname). Diese Funktion ist hauptsächlich für die Kompatibilität mit JAXB gedacht.
Die Standardeinstellung ist "false" (root) Wert wird nicht verpackt.
Damit Sie Mapper konfigurieren können:
objectMapper.configure(SerializationConfig.Feature.WRAP_ROOT_VALUE, true);
Ich hoffe es hilft dir ...
Unten ist ein Weg, um dies zu erreichen
Map<String, MyPojo> singletonMap = Collections.singletonMap("mypojo", mp);
System.out.println(mapper.writeValueAsString(singletonMap));
Ausgabe {"Mypojo": {"id": 4}}
Hier ist der Vorteil, dass wir den Namen des Wurzelschlüssels von json object mit on angeben können. Mit dem obigen Code wird mypojo der Root-Schlüssel. Dieser Ansatz ist am nützlichsten, wenn wir für die Iteration von Json-Objekten eine Java-Skriptvorlage wie Mustache.js verwenden
Um dies zu erreichen, müssen Sie die Annotation JsonTypeInfo
für Ihre Klasse und insbesondere WRAPPER_OBJECT verwenden.
@JsonTypeName("foo")
@JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT ,use = JsonTypeInfo.Id.NAME)
public class Bar(){
)
Es gibt auch eine schöne Anmerkung dazu:
@JsonRootName(value = "my_pojo")
public class MyPojo{
...
}
wird generieren:
{
"my_pojo" : {...}
}
es gibt einen anderen Weg, den ich verwendet habe, und das hat für mich funktioniert. Ich arbeite mit einem Drittanbieterglas, daher habe ich keine Kontrolle über Anmerkungen. Ich musste also etwas durchschneiden.
Überschreiben: org.codehaus.jackson.map.ser.BeanSerializerFactory.findBeanProperties(SerializationConfig, BasicBeanDescription)
Fügen Sie Ihre Immobilie wie folgt hinzu
List<BeanPropertyWriter> props = super.findBeanProperties(config, beanDesc);
BeanPropertyWriter bpw = null;
try {
Class cc = beanDesc.getType().getRawClass();
Method m = cc.getMethod("getClass", null);
bpw = new BeanPropertyWriter("$className", null, null, m, null,true, null);
} catch (SecurityException e) {
// TODO
} catch (NoSuchMethodException e) {
// TODO
}
props.add(bpw);
return props;
Auf diese Weise bekomme ich mehr Kontrolle und kann auch andere Filter verwenden.
Wie wäre es mit einer möglichst einfachen Lösung? Verwenden Sie einfach eine Wrapper-Klasse wie:
class Wrapper {
public MyPojo MyPojo;
}
und in Ihrem Code einwickeln/auspacken?
Darüber hinaus wäre es hilfreich zu wissen, warum Sie einen zusätzlichen json-Objekteintrag wie diesen wünschen. Ich weiß, dass dies von libs gemacht wird, die json über xml api emulieren (wegen der Impedanz zwischen xml und json, aufgrund der Umwandlung von xml in json), aber für reine Json-Lösungen ist dies normalerweise nicht erforderlich.
Erlauben Sie es Ihnen, herauszufinden, was der tatsächliche Typ ist? Wenn dies der Fall ist, könnten Sie möglicherweise polymorphe Typinformationen aktivieren, um Jackson automatisch damit umgehen zu lassen. (Für Details siehe 1.5 Versionshinweise , Eintrag für PTH,).
Ich wäre daran interessiert, die Lösung des OP dafür zu hören. Ich habe ähnliche Probleme, bei denen mein RESTful-Webdienst Objekte als XML oder JSON für Clients serialisiert. Die Javascript-Clients müssen den Wrapping-Typ kennen, damit sie analysiert werden können. Das Koppeln des Typs an ein URI-Muster ist keine Option.
Vielen Dank.
Edit: Ich habe bemerkt, dass Spring MappingJacksonJsonMarshaller beim Marshalling die Wrapping-Klasse hinzufügt. Ich ging den Code in Debug durch und stellte fest, dass Spring in einer HashMap ein einzelnes Schlüssel-Wert-Paar durchläuft, sodass der Schlüssel der Wrapping-Name ist und der Wert der Objekt. Also habe ich JacksonJaxbJsonProvider erweitert, die writeTo () -Methode überschrieben und Folgendes hinzugefügt:
HashMap<String, Object> map = new HashMap<String, Object>();
map.put(value.getClass().getSimpleName(), value);
super.writeTo(map, type, genericType, annotations, mediaType, httpHeaders,entityStream);
Es ist ein bisschen ein Hack, aber es funktioniert gut.
Ich habe durch Erfahrung festgestellt, dass es für alle JSON eine gute Idee ist, sowohl den Backend-Typ (als String) als auch den Komponententyp zu verwenden, der für das Rendern im Front-End verwendet wird (wenn etwas wie Angle oder Vue verwendet wird).
Die Begründung dafür ist, dass Sie verschiedene Typen mit einem einzigen Codesatz verarbeiten können.
Wenn Sie beispielsweise den Namen der UI-Komponente in den Daten angeben, können Sie unter anderem einen Bildschirm mit einer Liste von untergeordneten Typen mit unterschiedlichen Typen anzeigen, wobei nur ein einziges Tag in der übergeordneten Vorlage verwendet wird.
<component :is="child.componentType"/>.
Für Backend-Systeme und Web-Services: Ich bevorzuge die Verwendung einer einzigen Web-Service-Prozessorklasse, die Protokollierung, Überwachung und Ausnahmebehandlung für alle Web-Services bereitstellt, indem die entsprechende Prozessorklasse basierend auf der eingehenden Nutzlast nachgeschlagen wird. Dadurch sieht die Implementierung aller meiner Web-Services genau gleich aus (etwa 3 Zeilen Code), und ich bekomme eine detaillierte Ereignisprotokollierung während des gesamten Lebenszyklus des Anrufs, ohne dafür je Service-Code schreiben zu müssen.
Wenn der Typ den JSON umhüllt, ist er selbstdokumentierend. Wenn Sie nur die Eigenschaften sehen, haben Sie keine Ahnung, was Sie betrachten, bis Sie den entsprechenden Endpunkt gefunden haben.
Wenn Sie datengesteuerte Software schreiben möchten, ist es eine Grundvoraussetzung, dass Sie erkennen können, was Sie verarbeiten.
@JsonTypeInfo(include=As.WRAPPER_OBJECT, use=Id.NAME)
Diese Anmerkung funktioniert perfekt, wie von Arun Prakash vorgeschlagen. Ich habe versucht, Json in dieser Form zu bekommen.
{"Rowset":{"ROW":{"receiptno":"881604199388936","status":"SUCCESS"}}}
aber so bekommen:
{"ROW":{"receiptno":"881604199388936","status":"SUCCESS"}}}
Nun löste diese Anmerkung mein Problem.
verwenden Sie withRootName.
objectMapper.writer().withRootName(MyPojo.class.getName());