J'ai deux classes Java que je souhaite sérialiser en JSON à l'aide de Jackson:
public class User {
public final int id;
public final String name;
public User(int id, String name) {
this.id = id;
this.name = name;
}
}
public class Item {
public final int id;
public final String itemNr;
public final User createdBy;
public Item(int id, String itemNr, User createdBy) {
this.id = id;
this.itemNr = itemNr;
this.createdBy = createdBy;
}
}
Je souhaite sérialiser un élément dans ce JSON:
{"id":7, "itemNr":"TEST", "createdBy":3}
avec l'utilisateur sérialisé pour inclure uniquement le fichier id
. Je pourrai également sériliser tous les objets utilisateur en JSON comme:
{"id":3, "name": "Jonas", "email": "[email protected]"}
Je suppose donc que j'ai besoin d'écrire un sérialiseur personnalisé Item
et d'essayer ceci:
public class ItemSerializer extends JsonSerializer<Item> {
@Override
public void serialize(Item value, JsonGenerator jgen,
SerializerProvider provider) throws IOException,
JsonProcessingException {
jgen.writeStartObject();
jgen.writeNumberField("id", value.id);
jgen.writeNumberField("itemNr", value.itemNr);
jgen.writeNumberField("createdBy", value.user.id);
jgen.writeEndObject();
}
}
Je sérialise le JSON avec ce code de Jackson How-to: Custom Serializers :
ObjectMapper mapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule("SimpleModule",
new Version(1,0,0,null));
simpleModule.addSerializer(new ItemSerializer());
mapper.registerModule(simpleModule);
StringWriter writer = new StringWriter();
try {
mapper.writeValue(writer, myItem);
} catch (JsonGenerationException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Mais j'obtiens cette erreur:
Exception in thread "main" java.lang.IllegalArgumentException: JsonSerializer of type com.example.ItemSerializer does not define valid handledType() (use alternative registration method?)
at org.codehaus.jackson.map.module.SimpleSerializers.addSerializer(SimpleSerializers.java:62)
at org.codehaus.jackson.map.module.SimpleModule.addSerializer(SimpleModule.java:54)
at com.example.JsonTest.main(JsonTest.java:54)
Comment puis-je utiliser un sérialiseur personnalisé avec Jackson?
Voici comment je le ferais avec Gson:
public class UserAdapter implements JsonSerializer<User> {
@Override
public JsonElement serialize(User src, java.lang.reflect.Type typeOfSrc,
JsonSerializationContext context) {
return new JsonPrimitive(src.id);
}
}
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(User.class, new UserAdapter());
Gson gson = builder.create();
String json = gson.toJson(myItem);
System.out.println("JSON: "+json);
Mais je dois le faire avec Jackson maintenant, puisque Gson ne prend pas en charge les interfaces.
java
json
serialization
jackson
Jonas
la source
la source
Item
? J'ai un problème où ma méthode de contrôleur renvoie un objet sérialisé standardTypeA
, mais pour une autre méthode de contrôleur spécifique, je veux le sérialiser différemment. À quoi cela ressemblerait-il?Réponses:
Comme mentionné, @JsonValue est un bon moyen. Mais si un sérialiseur personnalisé ne vous dérange pas, il n'est pas nécessaire d'en écrire un pour Item mais plutôt un pour User - si c'est le cas, ce serait aussi simple que:
Une autre possibilité est de mettre en œuvre
JsonSerializable
, auquel cas aucun enregistrement n'est nécessaire.Quant à l'erreur; c'est bizarre - vous voulez probablement passer à une version ultérieure. Mais il est également plus sûr de l'étendre
org.codehaus.jackson.map.ser.SerializerBase
car il aura des implémentations standard de méthodes non essentielles (c'est-à-dire tout sauf un appel de sérialisation réel).la source
Exception in thread "main" java.lang.IllegalArgumentException: JsonSerializer of type com.example.JsonTest$UserSerilizer does not define valid handledType() (use alternative registration method?) at org.codehaus.jackson.map.module.SimpleSerializers.addSerializer(SimpleSerializers.java:62) at org.codehaus.jackson.map.module.SimpleModule.addSerializer(SimpleModule.java:54) at com.example.JsonTest.<init>(JsonTest.java:27) at com.exampple.JsonTest.main(JsonTest.java:102)
Vous pouvez placer
@JsonSerialize(using = CustomDateSerializer.class)
n'importe quel champ de date de l'objet à sérialiser.la source
@JsonSerialize(contentUsing= ...)
lors de l'annotation des collections (par exemple@JsonSerialize(contentUsing= CustomDateSerializer.class) List<Date> dates
)J'ai essayé de faire cela aussi, et il y a une erreur dans l'exemple de code sur la page Web de Jackson qui ne parvient pas à inclure le type (
.class
) dans l'appel à laaddSerializer()
méthode, qui devrait se lire comme ceci:En d'autres termes, ce sont les lignes qui instancient le
simpleModule
et ajoutent le sérialiseur (avec la ligne incorrecte précédente commentée):FYI: Voici la référence pour le code d'exemple correct: http://wiki.fasterxml.com/JacksonFeatureModules
la source
Utilisez @JsonValue:
@JsonValue ne fonctionne que sur les méthodes, vous devez donc ajouter la méthode getId. Vous devriez pouvoir ignorer complètement votre sérialiseur personnalisé.
la source
J'ai écrit un exemple pour une
Timestamp.class
sérialisation / désérialisation personnalisée, mais vous pouvez l'utiliser pour ce que vous voulez.Lors de la création du mappeur d'objets, procédez comme suit:
par exemple,
java ee
vous pouvez l'initialiser avec ceci:où le sérialiseur devrait être quelque chose comme ceci:
et désérialiseur quelque chose comme ceci:
la source
Ce sont des modèles de comportement que j'ai remarqués en essayant de comprendre la sérialisation de Jackson.
1) Supposons qu'il y ait un objet Classroom et un class Student. J'ai tout rendu public et définitif pour plus de facilité.
2) Supposons que ce sont les sérialiseurs que nous utilisons pour sérialiser les objets dans JSON. WriteObjectField utilise le propre sérialiseur de l'objet s'il est enregistré avec le mappeur d'objet; sinon, il le sérialise en tant que POJO. Le writeNumberField n'accepte exclusivement que les primitives comme arguments.
3) Enregistrez uniquement un DoubleSerializer avec un modèle de sortie DecimalFormat
###,##0.000
, dans SimpleModule et la sortie est:Vous pouvez voir que la sérialisation POJO fait la différence entre double et Double, en utilisant le DoubleSerialzer pour les doubles et en utilisant un format de chaîne standard pour les doubles.
4) Enregistrez DoubleSerializer et ClassroomSerializer, sans le StudentSerializer. Nous nous attendons à ce que la sortie soit telle que si nous écrivons un double comme un objet, il se comporte comme un Double, et si nous écrivons un Double comme un nombre, il se comporte comme un double. La variable d'instance Student doit être écrite en tant que POJO et suivre le modèle ci-dessus car elle ne s'enregistre pas.
5) Enregistrez tous les sérialiseurs. La sortie est:
exactement comme prévu.
Une autre note importante: si vous avez plusieurs sérialiseurs pour la même classe enregistrés avec le même module, le module sélectionnera le sérialiseur pour cette classe qui est le plus récemment ajouté à la liste. Cela ne devrait pas être utilisé - c'est déroutant et je ne sais pas à quel point c'est cohérent
Morale: si vous souhaitez personnaliser la sérialisation des primitives dans votre objet, vous devez écrire votre propre sérialiseur pour l'objet. Vous ne pouvez pas vous fier à la sérialisation de POJO Jackson.
la source
Les vues JSON de Jackson peuvent être un moyen plus simple de répondre à vos besoins, en particulier si vous disposez d'une certaine flexibilité dans votre format JSON.
Si
{"id":7, "itemNr":"TEST", "createdBy":{id:3}}
c'est une représentation acceptable, alors cela sera très facile à réaliser avec très peu de code.Vous devez simplement annoter le champ de nom de l'utilisateur comme faisant partie d'une vue et spécifier une vue différente dans votre demande de sérialisation (les champs non annotés seraient inclus par défaut)
Par exemple: définissez les vues:
Annotez l'utilisateur:
Et sérialiser en demandant une vue qui ne contient pas le champ que vous souhaitez masquer (les champs non annotés sont sérialisés par défaut):
la source
createdBy
comme valeur plutôt que comme objet?setSerializationView()
semblent être obsolètes, alors j'ai utilisé à lamapper.viewWriter(JacksonViews.ItemView.class).writeValue(writer, myItem);
place.Dans mon cas (Spring 3.2.4 et Jackson 2.3.1), configuration XML pour le sérialiseur personnalisé:
a été de manière inexpliquée réécrit par défaut par quelque chose.
Cela a fonctionné pour moi:
CustomObject.java
CustomObjectSerializer.java
Aucune configuration XML (
<mvc:message-converters>(...)</mvc:message-converters>
) n'est nécessaire dans ma solution.la source
Si votre seule exigence dans votre sérialiseur personnalisé est d'ignorer la sérialisation du
name
champ deUser
, marquez-le comme transitoire . Jackson ne sérialisera ni ne désérialisera les champs transitoires .[voir aussi: Pourquoi Java a-t-il des champs transitoires? ]
la source
User
classe? Mais je sérialiserai aussi tous les objets utilisateur. Par exemple, commencez par sérialiser toutitems
(avec uniquementuserId
comme référence à l'objet utilisateur), puis sérialisez toutusers
. Dans ce cas, je ne peux pas marquer les champs dans laUser
-classe.handledType()
méthode dans la documentation à laquelle j'ai lié et quand Eclipse génère les méthodes pour implémenter nohandledType()
est généré, donc je suis confus.Vous devez remplacer la méthode handleType et tout fonctionnera
la source
Le problème dans votre cas est qu'il manque à ItemSerializer la méthode handleType () qui doit être remplacée par JsonSerializer
Par conséquent, vous obtenez l'erreur explicite que handleType () n'est pas défini
J'espère que ça aide quelqu'un. Merci d'avoir lu ma réponse.
la source