RESUM — Jackson (JSON i XML)
1) Introducció
- Serialització: Java → text (JSON/XML).
mapper.writeValueAsString(obj)
- Deserialització: text (JSON/XML) → Java.
mapper.readValue(text, Classe.class)
- JSON:
ObjectMapper
· XML:XmlMapper
// JSON
ObjectMapper json = new ObjectMapper();
// XML
XmlMapper xml = new XmlMapper();
Cal afegir la configuracio recomanada (indentació, dates, ignorar camps desconeguts).
- Mateix POJO val per a JSON i XML; en XML afegeixes només anotacions quan cal.
2) POJOs
- Constructor buit (obligatori).
- Getters/Setters públics (per a booleans:
isActiu()
és correcte). - Camps privats (noms en camelCase).
- Si uses dates (
LocalDate
,LocalDateTime
), registraJavaTimeModule
.
3) Mètodes de mapper
ObjectMapper (JSON)
-
Escriure
writeValueAsString(obj)
→String
writeValue(File, obj)
→ fitxerwriterWithDefaultPrettyPrinter()
→ indenta
-
Llegir
readValue(String/File, Classe.class)
→ POJOreadTree(...)
→JsonNode
(quan no tens classe)
-
Config útil
enable(SerializationFeature.INDENT_OUTPUT)
disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.registerModule(new JavaTimeModule())
disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
XmlMapper (XML)
-
Escriure
writeValueAsString(obj)
,writeValue(File, obj)
,writerWithDefaultPrettyPrinter()
-
Llegir
readValue(String/File, Classe.class)
-
Config extra
configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true)
(capçalera<?xml...?>
)- Anotacions XML (
@JacksonXml...
) per canviar elements/atributs/wrappers
4) Anotacions JSON (ús típic)
@JsonProperty("nom_json")
→ canvia el nom de la clau@JsonIgnore
→ oculta un camp (no serialitza/deserialitza)@JsonInclude(Include.NON_NULL/NON_EMPTY/NON_DEFAULT)
→ omet nuls/buits/per defecte@JsonFormat(pattern="dd-MM-yyyy", timezone="...")
→ format de dates/nombres@JsonIgnoreProperties(ignoreUnknown = true)
→ ignora camps que venen “de més” al JSON@JsonGetter("clau")
/@JsonSetter("clau")
→ clau personalitzada sense canviar el nom del mètode- (Més avançat)
@JsonAnySetter
/@JsonAnyGetter
(map de propietats dinàmiques),@JsonSerialize
/@JsonDeserialize
(custom)
5) Anotacions XML (ús típic)
@JacksonXmlRootElement(localName="arrel")
→ nom de l’element arrel@JacksonXmlProperty(localName="nom", isAttribute=true|false)
→ element o atribut@JacksonXmlElementWrapper(localName="contenidor", useWrapping=true)
→ embolcall de llistes@JacksonXmlText
→ valor com a text intern (sense subelement)@JacksonXmlCData
→ escriure contingut com a CDATA
Exemple mini (atribut + element):
@JacksonXmlRootElement(localName="animal")
class Animal {
@JacksonXmlProperty(localName="tipus", isAttribute=true) String tipusAnimal; // atribut
@JacksonXmlProperty(localName="nom") String nomComu; // subelement
}
XML
<animal tipus="mamífer">
<nom>Lleó</nom>
</animal>
6) Llistes (JSON i XML)
JSON (sense anotacions)
class Cataleg {
String nom;
List<Producte> productes;
}
JSON
{"nom":"Perifèrics","productes":[{"nom":"Ratolí","preu":19.9},{"nom":"Teclat","preu":59.9}]}
XML (amb wrapper recomanat)
class Cataleg {
String nom;
@JacksonXmlElementWrapper(localName="productes")
@JacksonXmlProperty(localName="producte")
List<Producte> productes;
}
XML
<Cataleg>
<nom>Perifèrics</nom>
<productes>
<producte><nom>Ratolí</nom><preu>19.9</preu></producte>
<producte><nom>Teclat</nom><preu>59.9</preu></producte>
</productes>
</Cataleg>
7) Dates (Java Time)
- Afegeix
jackson-datatype-jsr310
i registra elJavaTimeModule
. - Desactiva timestamps si vols “ISO” o patró personalitzat.
@JsonFormat(pattern="dd-MM-yyyy")
LocalDate inauguracio;
8) Bones pràctiques i errors típics
- Constructor buit als POJOs: sense ell, Jackson no pot crear l’objecte.
- Getters/Setters coherents (especialment booleans amb
isXxx
). - Rutes de fitxer: usa
src/main/resources
per a dades; en proves, comprovaexists()
. - Dates:
JavaTimeModule
+WRITE_DATES_AS_TIMESTAMPS
desactivat. - Col·leccions: per a XML, quasi sempre necessitaràs
@JacksonXmlElementWrapper
+@JacksonXmlProperty
. - Estructures desconegudes: si no tens POJOs,
JsonNode
és el teu amic. - Pretty-print:
INDENT_OUTPUT
owriterWithDefaultPrettyPrinter()
per a llegibilitat.
Exemple Complet JSON + XML
XML
XML d’entrada:
<persona>
<nom>Jaume Aragó</nom>
<edat>68</edat>
<adreces>
<adreca tipus="casa">
<carrer>Avinguda Datileres</carrer>
<ciutat>Benizahat</ciutat>
</adreca>
<adreca tipus="oficina">
<carrer>Canto del Bobet</carrer>
<ciutat>Benigaslo</ciutat>
</adreca>
</adreces>
<notes><![CDATA[Esta és una persona molt important.]]></notes>
</persona>
POJOs + Anotacions XML (per a mapejar exactament):
// Persona.java
import com.fasterxml.jackson.dataformat.xml.annotation.*;
import java.util.List;
@JacksonXmlRootElement(localName = "persona")
public class Persona {
@JacksonXmlProperty(localName = "nom")
private String nom;
@JacksonXmlProperty(localName = "edat")
private int edat;
@JacksonXmlElementWrapper(localName = "adreces") // <adreces> ... </adreces>
@JacksonXmlProperty(localName = "adreca") // elements fills <adreca>
private List<Adreca> adreces;
@JacksonXmlCData // Volem que vaja dins CDATA
private String notes;
public Persona() {}
// getters/setters...
}
// Adreca.java
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
public class Adreca {
@JacksonXmlProperty(isAttribute = true, localName = "tipus") // atribut <adreca tipus="...">
private String tipus;
@JacksonXmlProperty(localName = "carrer")
private String carrer;
@JacksonXmlProperty(localName = "ciutat")
private String ciutat;
public Adreca() {}
// getters/setters...
}
Deserialitzar l’XML i mostrar-ho:
// LligXML.java
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import java.io.File;
public class LligXML {
public static void main(String[] args) throws Exception {
XmlMapper xml = new XmlMapper();
// 1) Des de String (útil per a proves o exemples curts)
String xmlContent = """
<persona>
<nom>Jaume Aragó</nom>
<edat>68</edat>
<adreces>
<adreca tipus="casa">
<carrer>Avinguda Datileres</carrer>
<ciutat>Benizahat</ciutat>
</adreca>
<adreca tipus="oficina">
<carrer>Canto del Bobet</carrer>
<ciutat>Benigaslo</ciutat>
</adreca>
</adreces>
<notes><![CDATA[Esta és una persona molt important.]]></notes>
</persona>
""";
Persona p = xml.readValue(xmlContent, Persona.class);
System.out.println("Nom: " + p.getNom() + " | Edat: " + p.getEdat());
for (Adreca a : p.getAdreces()) {
System.out.println(" - " + a.getTipus() + " → " + a.getCarrer() + " (" + a.getCiutat() + ")");
}
System.out.println("Notes: " + p.getNotes());
// 2) Des de fitxer
File f = new File("src/main/resources/persona.xml");
if (f.exists()) {
Persona p2 = xml.readValue(f, Persona.class);
System.out.println("Fitxer OK → " + p2.getNom());
}
}
}
Serialitzar a XML amb capçalera i indentació:
// EscriuXML.java
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.io.File;
import java.util.List;
public class EscriuXML {
public static void main(String[] args) throws Exception {
Persona p = new Persona();
p.setNom("Jaume Aragó");
p.setEdat(68);
p.setAdreces(List.of(
crea("casa", "Avinguda Datileres", "Benizahat"),
crea("oficina", "Canto del Bobet", "Benigaslo")
));
p.setNotes("Aquesta és una persona molt important.");
XmlMapper xml = new XmlMapper();
xml.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true); // <?xml ...?>
xml.enable(SerializationFeature.INDENT_OUTPUT);
String out = xml.writeValueAsString(p);
System.out.println(out);
xml.writeValue(new File("src/main/resources/persona_out.xml"), p);
}
private static Adreca crea(String tipus, String carrer, String ciutat) {
Adreca a = new Adreca();
a.setTipus(tipus);
a.setCarrer(carrer);
a.setCiutat(ciutat);
return a;
}
}
JSON
POJOs sense anotacions (nom per defecte = nom del camp):
// Empresa.java
import java.util.List;
public class Empresa {
private String nom;
private List<Empleat> empleats;
public Empresa() {}
public Empresa(String nom, List<Empleat> empleats) {
this.nom = nom;
this.empleats = empleats;
}
public String getNom() { return nom; }
public void setNom(String nom) { this.nom = nom; }
public List<Empleat> getEmpleats() { return empleats; }
public void setEmpleats(List<Empleat> empleats) { this.empleats = empleats; }
}
public class Empleat {
private String nom;
private int edat;
public Empleat() {}
public Empleat(String nom, int edat) { this.nom = nom; this.edat = edat; }
public String getNom() { return nom; }
public void setNom(String nom) { this.nom = nom; }
public int getEdat() { return edat; }
public void setEdat(int edat) { this.edat = edat; }
}
Serialitzar a JSON amb indentació:
// EscriuJSON.java
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.io.File;
import java.util.List;
public class EscriuJSON {
public static void main(String[] args) throws Exception {
Empresa empresa = new Empresa(
"La mazmorra del Androide",
List.of(new Empleat("Jaume", 30), new Empleat("Bel", 28))
);
ObjectMapper om = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
System.out.println(om.writeValueAsString(empresa)); // a consola
om.writeValue(new File("src/main/resources/empresa.json"), empresa); // a fitxer
}
}
Deserialitzar JSON des de fitxer:
// LligJSON.java
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
public class LligJSON {
public static void main(String[] args) throws Exception {
File f = new File("src/main/resources/empresa.json");
if (!f.exists()) {
System.err.println("No trobe empresa.json. Executa abans EscriuJSON.");
return;
}
ObjectMapper om = new ObjectMapper();
Empresa emp = om.readValue(f, Empresa.class);
System.out.println("Empresa: " + emp.getNom());
for (Empleat e : emp.getEmpleats()) {
System.out.println(" - " + e.getNom() + " (" + e.getEdat() + ")");
}
}
}