Bonjour à tous,
Je souhaite utiliser l'API JackSON dans un projet Java pour manipuler des fichiers dont le contenu est formaté en JSON.
Il me faut donc, a priori, un .JAR.
Savez-où le télécharger dans cette page ? Je ne m'y retrouve pas... https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.7.4
Utilise maven ou gradle et mets la dépendance qui va bien
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.7.4</version>
</dependency>
Tu peux le télécharger comme indiqué sur le github ( https://github.com/FasterXML/jackson-core ) directement en jar depuis le repo maven et l'inclure dans le /lib de ton application :
http://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-core/
Mais utilise plutôt maven/gradle ![]()
En fait j'ai réussi, sans utiliser Gradle/Maven !
Pour ceux que ça intéresse il suffit de télécharger le jar core + le jar databind + le jar annotations .
!
Mais merci !
Alors par contre j'ai une nouvelle question. J'utilise l'ObjectMapper et sa méthode readValue pour créer une instance d'une classe A que j'ai écrite depuis un JSON (désérialisation).
J'ai remarqué que je ne peux pas, dans la classe A, mettre un constructeur à arguments car celui-ci écrase le constructeur vide. Apparemment, JackSON, pour effectuer la désérialisation, fait appel au constructeur vide. Est-ce que je me trompe ?
Et du coup la désérialisation avec le constructeur vide consiste à parcourir chaque valeur du fichier JSON et à l'attribuer aux attributs de la classe A dans l'ordre dans lequel ceux-ci apparaissent ? C'est le principe de la désérialisation quand il y a un constructeur vide, je crois....
![]()
Enfin bref si quelqu'un peut m'éclairer à ce sujet ce serait vachement cool !
Ah je viens d'utiliser JsonCreator et JsonProperty pour pouvoir faire usage d'un constructeur à paramètres ! C'est cool je trouve
![]()
En réalité pour ton problème, tu peux tout-à-fait mettre des constructeurs à arguments.
Cependant, pour faire fonctionner ton objectMapper il faut absolument que ton pojo aie un constructeur par défaut.
Donc en gros si tu mets des constructeurs avec paramètres, ajoute un constructeur vide sans paramètre ![]()
public class Toto {
// Constructeur par défaut (vide), utilisé par Jackson
public Toto() {}
// Constructeur avec paramètre
public Toto(Integer i) {
}
}
Le 10 juin 2016 à 15:19:20 SemenceDeTroll a écrit :
En réalité pour ton problème, tu peux tout-à-fait mettre des constructeurs à arguments.
Cependant, pour faire fonctionner ton objectMapper il faut absolument que ton pojo aie un constructeur par défaut.Donc en gros si tu mets des constructeurs avec paramètres, ajoute un constructeur vide sans paramètre
public class Toto { // Constructeur par défaut (vide), utilisé par Jackson public Toto() {} // Constructeur avec paramètre public Toto(Integer i) { } }
Oui mais en utilisant les annotations JsonCreator et Jsonproperty, on peut très bien ne pas avoir de constructeur vide ^^ !
Oui en effet,
c'est juste que tu te lies très fortement à Jackson en utilisant les annotations, et que le jour où tu changeras de librairies ça risque d'avoir un coût non négligeable d'effectuer la dite migration.
Le constructeur vide (sauf si tu souhaites absolument l'éviter car sémantiquement ne répond pas à ta modélisation) est une petite astuce permettant d'éviter cela.
Je ne vois d'ailleurs pas pourquoi un POJO devrait être fortement lié à Jackson via des annotations (qui reste une librairie - donc tierce), côté modélisation objet je trouve cela très mauvais.
Une petite discussion d'ailleurs, apparemment JDK8 permet d'autres choses :
http://stackoverflow.com/questions/21920367/why-when-a-constructor-is-annotated-with-jsoncreator-its-arguments-must-be-ann
Le 11 juin 2016 à 14:50:35 SemenceDeTroll a écrit :
Oui en effet,
c'est juste que tu te lies très fortement à Jackson en utilisant les annotations, et que le jour où tu changeras de librairies ça risque d'avoir un coût non négligeable d'effectuer la dite migration.Le constructeur vide (sauf si tu souhaites absolument l'éviter car sémantiquement ne répond pas à ta modélisation) est une petite astuce permettant d'éviter cela.
Tout à fait ! Après je ne suis pas sûr d'avoir très bien compris comment fonctionne Jackson. Est-ce que ça te dérangerait que je pose une ou 2 questions à ce sujet ![]()
Je ne suis absolument pas expert Jackson hein^^. Moi j'ai plutôt l'habitude de l'utiliser comme un simple service.
Le souci de ne pas mettre les annotations c'est qu'il va utiliser le nom des attributs dans le JSON, ce qui peut être dangereux en cas de renommage/refactoring et ne pas permettre la rétrocompatibilité (d'où l'existence des annotations qui supprime la corrélation entre nom des attributs et JSON généré, permettant le refactoring).
Cependant on peut très bien changer le texte dans l'annotation et tout autant casser la rétrocompatibilité.
C'est pour ça que je préfère finalement ne pas lié l'objet à sérialiser à jackson. Ca me permet de ne pas les coupler entre eux et de minimiser le temps de migration le jour où je changerai de librairie ![]()
Par ex :
@Component
public class JSONDelegateImpl implements JSONDelegate {
private static final Logger logger = LoggerFactory.getLogger(JSONDelegateImpl.class);
// Injections
//----------------------------------------------------
@Resource(name="jsonMapper")
private ObjectMapper jsonMapper;
// Process
//----------------------------------------------------
@Override
public String serialize(Object obj) {
String str = null;
try {
if(obj != null) {
str = jsonMapper.writeValueAsString(obj);
}
} catch (JsonProcessingException e) {
logger.warn("Unable to serialize object in JSON", e);
}
return str;
}
@Override
public <T> T unserialize(String str, Class<T> clazz) {
T object = null;
try {
object = jsonMapper.readValue(str, clazz);
}
catch (JsonParseException e) { errorJSON(str, clazz, e); }
catch (JsonMappingException e) { errorJSON(str, clazz, e); }
catch (IOException e) { errorJSON(str, clazz, e); }
return object;
}
// Private methods
//----------------------------------------------------
private static <T> void errorJSON(String str, Class<T> clazz, Exception e) {
logger.error("Unable to load unserialize {} in {}.class : {}", str, clazz.getName(), e.getMessage());
}
}
où ObjectMapper est un singleton.
<bean id="jsonMapper" class="com.fasterxml.jackson.databind.ObjectMapper" />
Puis on l'utilise (sans savoir que c'est Jackson qui sert à sérialiser) :
Toto toto = new Toto("a", "b", "c");
String jsonToto = JSONDelegate.serialize(toto);
Je vois.
Mais la méthode ObjectMapper::readValue, concrètement, que fait-elle ? J'ai du mal à comprendre le deuxième argument, car celui-ci peut très bien être une classe, ou une structure Java Collection, ou encore un TypeReference qu'on instancie... C'est bizarre...
ObjectMapper::readValue permet de désérialiser un object String (JSON) en un object Java.
Le deuxième argument permet à Jackson de savoir quel type d'objet utiliser.
Par ex :
Toto toto = new Toto("a", "b", "c");
String jsonToto = JSONDelegate.serialize(toto);
Toto toto2 = JSONDelegate.unserialize(jsonToto, Toto.class); // on doit retrouver l'objet Toto, donc toto2.equals(toto) == true
"Le deuxième argument permet à Jackson de savoir quel type d'objet utiliser."
Quel type d'objet Java utiliser ?
String json; // Ta String JSON
objectMapper.readValue(json, MyClass.class);Jackson va essayer de créer une instance de la classe MyClass à partir du json fourni.
D'accord donc ça va j'avais bien compris. ^^
Et dans ce genre de trucs, qu'essaie-t-il de faire ?Map<String,Object> userData = mapper.readValue(new File("user.json"), Map.class);
http://stackoverflow.com/questions/2525042/how-to-convert-a-json-string-to-a-mapstring-string-with-jackson-json![]()
Mmmh moui merci x)
En fait je n'ai jamais utilisé Jackson dans ton cas d'utilisation (à chaque fois je l'utilise avec mes propres types définis).
J'imagine que le fait de lui donner une Map.class (une interface donc) est problématique et qu'il faille lui fournir une vraie classe pouvant être instanciée (donc ni interface, ni classe abstraite).
Map<String,String> map = new HashMap<String,String>();
ObjectMapper mapper = new ObjectMapper();
map = mapper.readValue(string, HashMap.class);
Ca semble marcher d'après ce que dis qqn. Ou sinon essaie de passer par les TypeReference.
Mmmh merci ^^
En fait je te demande tout ça car je n'arrive pas à utiliser un JSON dont le contenu est un objet sans nom contenant 2 arrays d'objets...
C'est fatiguant...
Tu peux donner ton JSON (ou du moins juste un exemple, pas forcément le tout si c'est énorme...) pour que j'y jette un oeil ?