Jackson
Introducció
Quan creem aplicacions Java, sovint necessitem convertir objectes a formats de dades que es puguen emmagatzemar, enviar per la xarxa o intercanviar amb altres sistemes. A això ho anomenem serialització (d’objectes a formats com JSON o XML) i deserialització (del format a objectes Java).
Jackson és una de les llibreries més utilitzades per la seua simplicitat, velocitat i versatilitat. Ens permet serialitzar i deserialitzar amb molt poca configuració.
Nota: En Java tradicional també podem serialitzar objectes amb la interfície
java.io.Serializablei fluxos d’objectes (ObjectOutputStream,ObjectInputStream). Jackson, en canvi, treballa amb formats textuals o binaris interoperables, com JSON, XML, YAML o CSV.
Què és Jackson?
Jackson és una biblioteca de processament de dades per a Java. La seua peça central és la classe ObjectMapper, que permet convertir objectes Java en formats com JSON, XML o CSV, i viceversa.
Jackson destaca per:
- Serialitzar objectes Java a formats JSON, XML, CSV, etc.
- Deserialitzar aquests formats a objectes Java.
- Utilitzar anotacions per controlar el procés de conversió.
Formats compatibles
- JSON:
jackson-databind(ObjectMapper) - XML:
jackson-dataformat-xml(XmlMapper) - YAML:
jackson-dataformat-yaml - CSV:
jackson-dataformat-csv - Altres:
jackson-dataformat-cbor,jackson-dataformat-smile
Alternatives a Jackson
- Gson (Google)
- Moshi (Square)
- JAXB (Java per a XML)
- XStream (XML)
POJOs i DTOs
En el desenvolupament d’aplicacions Java, sovint utilitzem classes simples per representar dades. Són els POJOs (Plain Old Java Objects) i els DTOs (Data Transfer Objects).
POJO
Un POJO és una classe Java senzilla que segueix les convencions estàndard: no hereta de cap classe especial ni implementa cap interfície concreta. El seu objectiu és representar dades de manera estructurada.
Característiques principals:
- Camps privats amb mètodes getters i setters.
- Sense dependències de frameworks.
- Fàcil de serialitzar i deserialitzar.
Exemple:
public class Producte {
private String nom;
private double preu;
private String descripcio;
public Producte() {}
public Producte(String nom, double preu, String descripcio) {
this.nom = nom;
this.preu = preu;
this.descripcio = descripcio;
}
public String getNom() { return nom; }
public void setNom(String nom) { this.nom = nom; }
public double getPreu() { return preu; }
public void setPreu(double preu) { this.preu = preu; }
public String getDescripcio() { return descripcio; }
public void setDescripcio(String descripcio) { this.descripcio = descripcio; }
@Override
public String toString() {
return "Producte [nom=" + nom + ", preu=" + preu + ", descripcio=" + descripcio + "]";
}
}
DTO
Un DTO és un tipus especial de POJO que s’utilitza per transferir dades entre capes d’una aplicació. Sovint conté només la informació necessària per a una operació concreta.
Exemple:
public class ProducteDTO {
private String nom;
private double preu;
public ProducteDTO() {}
public ProducteDTO(String nom, double preu) {
this.nom = nom;
this.preu = preu;
}
public String getNom() { return nom; }
public void setNom(String nom) { this.nom = nom; }
public double getPreu() { return preu; }
public void setPreu(double preu) { this.preu = preu; }
}
Resum:
| Aspecte | POJO | DTO |
|---|---|---|
| Propòsit | Representar dades del domini | Transferir dades entre capes |
| Contingut | Camps i mètodes senzills | Només dades essencials |
| Lògica de negoci | Pot tindre’n | No en té |
| Exemple | Producte | ProducteDTO |
Anotacions en Java
Les anotacions són metadades que descriuen el codi. En Java, s’utilitzen per a documentar, validar o configurar el comportament d’una classe, mètode o camp.
Exemples comuns
@Override: indica que un mètode sobreescriu un altre.@Deprecated: marca un element com a obsolet.@SuppressWarnings: suprimeix avisos del compilador.@FunctionalInterface: marca una interfície amb un únic mètode abstracte.
Anotacions en Jackson
Jackson utilitza anotacions per definir com es mapeja una classe Java a un format com JSON o XML.
Anotacions JSON més habituals
| Anotació | Funció |
|---|---|
@JsonProperty("nom_json") | Canvia el nom d’un camp al JSON |
@JsonIgnore | Exclou un camp del JSON |
@JsonInclude(Include.NON_NULL) | Omet els camps nuls |
@JsonFormat(pattern="dd-MM-yyyy") | Dona format a les dates |
Exemple complet amb JSON i XML
Classe Atraccio
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.dataformat.xml.annotation.*;
import java.time.LocalDate;
@JsonInclude(JsonInclude.Include.NON_NULL)
@JacksonXmlRootElement(localName = "atraccio")
public class Atraccio {
@JsonProperty("nom_atraccio")
@JacksonXmlProperty(localName = "nom_atraccio")
private String nom;
@JacksonXmlProperty(isAttribute = true)
private boolean activa;
private double alturaMinima;
@JsonFormat(pattern = "dd-MM-yyyy")
private LocalDate inauguracio;
public Atraccio() {}
public Atraccio(String nom, boolean activa, double alturaMinima, LocalDate inauguracio) {
this.nom = nom;
this.activa = activa;
this.alturaMinima = alturaMinima;
this.inauguracio = inauguracio;
}
// Getters i setters
public String getNom() { return nom; }
public void setNom(String nom) { this.nom = nom; }
public boolean isActiva() { return activa; }
public void setActiva(boolean activa) { this.activa = activa; }
public double getAlturaMinima() { return alturaMinima; }
public void setAlturaMinima(double alturaMinima) { this.alturaMinima = alturaMinima; }
public LocalDate getInauguracio() { return inauguracio; }
public void setInauguracio(LocalDate inauguracio) { this.inauguracio = inauguracio; }
}
Programa ExempleJackson.java
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.time.LocalDate;
public class ExempleJackson {
public static void main(String[] args) {
try {
Atraccio atr = new Atraccio("Tirolina Gigant", true, 1.40, LocalDate.of(2022, 6, 10));
ObjectMapper jsonMapper = new ObjectMapper();
jsonMapper.registerModule(new JavaTimeModule());
jsonMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
String json = jsonMapper.writerWithDefaultPrettyPrinter().writeValueAsString(atr);
System.out.println("JSON generat:");
System.out.println(json);
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.registerModule(new JavaTimeModule());
xmlMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
String xml = xmlMapper.writerWithDefaultPrettyPrinter().writeValueAsString(atr);
System.out.println("\nXML generat:");
System.out.println(xml);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Resultat
JSON:
{
"nom_atraccio": "Tirolina Gigant",
"activa": true,
"alturaMinima": 1.4,
"inauguracio": "10-06-2022"
}
XML:
<atraccio activa="true">
<nom_atraccio>Tirolina Gigant</nom_atraccio>
<alturaMinima>1.4</alturaMinima>
<inauguracio>10-06-2022</inauguracio>
</atraccio>
En resum
- Jackson és una llibreria molt potent per a serialitzar i deserialitzar objectes Java.
- És compatible amb diversos formats (JSON, XML, YAML, CSV…).
- L’ús de POJOs i anotacions facilita molt el treball amb dades estructurades.
- Amb
ObjectMapperiXmlMapper, podem treballar amb els dos formats principals (JSON i XML) de manera pràcticament idèntica.
Creació de POJOs a partir de JSON i XML
Quan treballem amb formats de dades com JSON o XML, moltes voltes necessitarem convertir aquestes estructures a classes Java. Això ens permet accedir a la informació amb facilitat, validar-la i processar-la dins del nostre programa.
A aquestes classes senzilles les anomenem POJOs o DTOs. Jackson i altres llibreries poden llegir o escriure dades a partir d’elles, però abans cal saber construir-les correctament.
eEr a dissenyar classes Java a partir de documents JSON o XML hem de centrar-nos en:
- Reconéixer els tipus de dades.
- Crear classes per a objectes i llistes.
- Mantindre una correspondència clara entre la informació i el codi.
1. Analitzar l’estructura del document
Abans de crear les classes, cal observar l’estructura del document JSON o XML i identificar els seus components:
| Estructura | Significat | Exemple | Representació Java |
|---|---|---|---|
| Clau/etiqueta amb valor simple | Dada senzilla | "nom": "Anna" | Atribut String nom; |
| Objecte dins d’un altre | Composició | "adreca": {"carrer": "Major"} | Classe Adreca com a camp |
| Llista o array | Repetició | "llibres": [ {...}, {...} ] | List<Llibre> |
| Valor numèric | Quantitat o codi | "edat": 23 | int edat; |
| Valor booleà | Estat o condició | "actiu": true | boolean actiu; |
2. Regles generals per crear POJOs
- Cada objecte → una classe
Si trobes un bloc amb claus ({} en JSON o <Element> en XML), crea una classe Java amb el mateix nom o un nom equivalent.
Exemple JSON:
{
"nom": "Joan",
"edat": 25
}
Classe Java:
public class Persona {
private String nom;
private int edat;
public Persona() {}
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; }
}
- Cada camp → atribut privat
Els noms de camp solen coincidir amb els del JSON/XML, però seguim les convencions Java:
- camelCase per als atributs (
dataNaixement,codiPostal). - Tipus Java segons el valor.
| Tipus de valor | Tipus Java recomanat |
|---|---|
| Text | String |
| Enter | int o Integer |
| Real | double o BigDecimal |
| Booleà | boolean o Boolean |
| Data | LocalDate |
| Llista | List<T> |
| Objecte intern | Classe pròpia |
- Constructor buit i mètodes d’accés
Totes les classes que vulguem deserialitzar necessiten:
- Un constructor buit (sense paràmetres).
- Getters i setters públics per a tots els camps.
public class Producte {
private String nom;
private double preu;
public Producte() {} // Constructor buit
public String getNom() { return nom; }
public void setNom(String nom) { this.nom = nom; }
public double getPreu() { return preu; }
public void setPreu(double preu) { this.preu = preu; }
}
3. Objectes anidats
Quan un element conté un altre objecte, creem una nova classe per a representar-lo.
- Exemple JSON
{
"nom": "Laura",
"adreca": {
"carrer": "Sant Pere",
"ciutat": "Alcoi"
}
}
- POJOs corresponents
public class Persona {
private String nom;
private Adreca adreca;
public Persona() {}
public String getNom() { return nom; }
public void setNom(String nom) { this.nom = nom; }
public Adreca getAdreca() { return adreca; }
public void setAdreca(Adreca adreca) { this.adreca = adreca; }
}
public class Adreca {
private String carrer;
private String ciutat;
public Adreca() {}
public String getCarrer() { return carrer; }
public void setCarrer(String carrer) { this.carrer = carrer; }
public String getCiutat() { return ciutat; }
public void setCiutat(String ciutat) { this.ciutat = ciutat; }
}
4. Llistes i arrays
Si hi ha una repetició d’elements, utilitzem una llista (List<T>).
- Exemple JSON
{
"nom": "València",
"monuments": [
{"nom": "La Llotja"},
{"nom": "El Micalet"}
]
}
- Classes Java
import java.util.List;
public class Ciutat {
private String nom;
private List<Monument> monuments;
public Ciutat() {}
public String getNom() { return nom; }
public void setNom(String nom) { this.nom = nom; }
public List<Monument> getMonuments() { return monuments; }
public void setMonuments(List<Monument> monuments) { this.monuments = monuments; }
}
public class Monument {
private String nom;
public Monument() {}
public String getNom() { return nom; }
public void setNom(String nom) { this.nom = nom; }
}
5. Correspondència entre JSON i XML
Les regles generals són les mateixes, però en XML sovint hi ha un element arrel que conté tots els altres.
Exemple XML
<Ciutats>
<Ciutat>
<Nom>València</Nom>
<Poblacio>790201</Poblacio>
</Ciutat>
<Ciutat>
<Nom>Sevilla</Nom>
<Poblacio>688711</Poblacio>
</Ciutat>
</Ciutats>
- Classes Java equivalents
import java.util.List;
public class Ciutats {
private List<Ciutat> ciutat;
public Ciutats() {}
public List<Ciutat> getCiutat() { return ciutat; }
public void setCiutat(List<Ciutat> ciutat) { this.ciutat = ciutat; }
}
public class Ciutat {
private String nom;
private int poblacio;
public Ciutat() {}
public String getNom() { return nom; }
public void setNom(String nom) { this.nom = nom; }
public int getPoblacio() { return poblacio; }
public void setPoblacio(int poblacio) { this.poblacio = poblacio; }
}
En XML és molt habitual tindre una classe contenidora (
Ciutats) per agrupar diverses instàncies (Ciutat).
6. Guia pas a pas per dissenyar el model
-
Llig el document complet. Identifica objectes, llistes i valors simples.
-
Dibuixa un esquema o mapa. Marca cada objecte i les seues relacions.
-
Assigna noms a les classes i camps.
- Classes en majúscula inicial (
Persona). - Camps en minúscula inicial (
nom,edat).
- Classes en majúscula inicial (
-
Decideix el tipus de cada camp.
- Números →
intodouble. - Text →
String. - Dates →
LocalDate. - Objectes → altra classe.
- Repeticions →
List<T>.
- Números →
-
Crea els constructors i accessors. Recorda: constructor buit i getters/setters.
-
Comprova la correspondència. L’estructura del POJO ha de reflectir exactament la del JSON/XML.
Exemples
Exemple 1: JSON senzill
Document
{
"titol": "El Senyor dels Anells",
"autor": "J.R.R. Tolkien",
"any": 1954
}
Classe
public class Llibre {
private String titol;
private String autor;
private int any;
public Llibre() {}
public String getTitol() { return titol; }
public void setTitol(String titol) { this.titol = titol; }
public String getAutor() { return autor; }
public void setAutor(String autor) { this.autor = autor; }
public int getAny() { return any; }
public void setAny(int any) { this.any = any; }
}
Exemple 2: JSON amb objecte i llista
Document
{
"nom": "Maria",
"contacte": {
"email": "maria@gmail.com",
"telefon": "654321987"
},
"projectes": [
{"nom": "Aplicació Mòbil"},
{"nom": "Web Corporativa"}
]
}
Classes
import java.util.List;
public class Empleat {
private String nom;
private Contacte contacte;
private List<Projecte> projectes;
public Empleat() {}
// getters i setters
}
public class Contacte {
private String email;
private String telefon;
public Contacte() {}
// getters i setters
}
public class Projecte {
private String nom;
public Projecte() {}
// getters i setters
}
8. Exercicis
Exercici 1
A partir d’aquest JSON:
{
"marca": "Toyota",
"model": "Corolla",
"any": 2020,
"motor": {
"cilindrada": 1800,
"combustible": "gasolina"
}
}
Crea les classes Cotxe i Motor amb els camps adequats, constructor buit i mètodes get/set.
Exercici 2
A partir d’aquest XML:
<Biblioteca>
<Llibre>
<Titol>Dune</Titol>
<Autor>Frank Herbert</Autor>
</Llibre>
<Llibre>
<Titol>Neuromàntic</Titol>
<Autor>William Gibson</Autor>
</Llibre>
</Biblioteca>
Crea les classes Biblioteca i Llibre perquè puguen representar aquestes dades.
Exercici 3
Observa el JSON següent:
{
"ciutat": "Madrid",
"temperatures": [19, 21, 18, 23, 20]
}
Crea la classe EstacioMeteorologica amb una llista d’enters per a les temperatures.
9. Taula Resum
| Element JSON/XML | Representació Java |
|---|---|
| Objecte | Classe |
| Camp simple | Atribut privat |
| Objecte dins d’un altre | Classe anidada o composta |
| Llista o array | List<T> |
| Valor numèric | int, double |
| Valor booleà | boolean |
| Text | String |
| Data | LocalDate |
| Constructor buit | Obligatori |
| Getters i setters | Obligatori |
- Cada objecte o element es tradueix a una classe Java.
- Cada dada esdevé un camp privat amb els seus getters i setters.
- Les llistes s’expressen amb
List<T>. - Els objectes interns són altres POJOs.
- L’estructura del JSON o XML ha de coincidir amb la del model Java.
Maven i Jackson
Maven és una eina de gestió de projectes que s’utilitza per a la construcció, dependències, i distribució de projectes Java.
Simplifica el procés de desenvolupament, ja que automatitza tasques com la compilació, la generació de paquets, i la gestió de dependències (o llibreries externes).
Estructura Bàsica d’un Projecte Maven
Un projecte Maven es compon de diversos elements clau, com ara:
pom.xml: Project Object Model (POM), és el fitxer de configuració principal de Maven que conté informació sobre el projecte, les dependències, els plugins, i altres configuracions.src/main/java: Carpeta que conté el codi font de l’aplicació. Les classes principals del projecte es troben en aquesta carpeta.src/main/resources: Carpeta que conté els recursos de l’aplicació, com el arxius JSON y XML, propietats, imatges…src/test/java: Conté les classes de proves o tests.

Arxiu pom.xml
Cada projecte Maven té un arxiu pom.xml (Project Object Model) que defineix les dependencies, plugins i la configuració del projecte.
- L’arxiu pom.xml està ubicat a la carpeta arrel del projecte.
- Maven gestiona les dependències del projecte i les descarrega automàticament d’un repositori central.
-
Les dependències s’afegeixen a l’arxiu pom.xml dins de l’element
. - El POM defineix les coordenades del projecte:
| Element | Significat | Exemple |
|---|---|---|
groupId | Organització o domini invertit | com.jaume |
artifactId | Nom del projecte o mòdul | ProjecteMaven |
version | Versió de l’aplicació | 1.0-SNAPSHOT |
<dependencies>
<dependency>
<groupId>group_id</groupId>
<artifactId>artifact_id</artifactId>
<version>versió</version>
</dependency>
<dependency>
<groupId>altre_group_id</groupId>
<artifactId>altre_artifact_id</artifactId>
<version>altre_versió</version>
</dependency>
<dependency>
...
</dependency>
</dependencies>
On:
<dependencies>: contenidor de totes les dependències.<dependency>: defineix una llibreria concreta a incloure.<groupId>: grup/proveïdor de la dependència.<artifactId>: nom concret del paquet dins del grup.<version>: versió de la dependència a utilitzar.
Nota: totes les dependències es poden buscar a Maven Central (MVNRepository) i copiar al
pom.xml. A IntelliJ, després de canviar el POM, fes Reload All Maven Projects (botó del panell Maven) per aplicar canvis.
- Inicialment l’arxiu pom.xml te la següent estructura:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.jaume</groupId>
<artifactId>ProjecteMaven</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<!-- Recomanat LTS (17 o 21). Ajustem si volem usar 22 a l’aula. -->
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
Per a utilitzar Jackson en un projecte Maven, només cal afegir la dependència de Jackson al fitxer pom.xml. Això permetrà que Maven descarregue i incloga les llibreries de Jackson en el projecte.
En este cas, accedim al Repositori Maven triem la última versió i l’afegim al pom.xml ( en este cas Jackson-databind).
- L’arxiu
pom.xmlquedaria:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.jaume</groupId>
<artifactId>ProjecteMaven</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.18.0</version>
</dependency>
</dependencies>
</project>
Nota: En IntelliJ cada volta que modifiquem l’arxiu
pom.xmlhem d’actualitzar els canvis(Ctr+Mayus+O).
Dependencies de Jackson
Per a treballar amb Jackson, normalment necessitem afegir les següents dependències al nostre fitxer pom.xml:
<dependencies>
<!-- Jackson Core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.18.0</version>
</dependency>
<!-- Jackson Databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.18.0</version>
</dependency>
<!-- Jackson Annotations -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.18.0</version>
</dependency>
</dependencies>
Aquestes dependències inclouen:
jackson-core: La biblioteca bàsica per al processament de JSON.jackson-databind: Proporciona funcionalitats per a la serialització i deserialització d’objectes Java.jackson-annotations: Conté les anotacions utilitzades per a configurar el comportament de Jackson.- Versió: Assegura’t d’utilitzar la versió més recent de Jackson per a garantir compatibilitat i accés a les últimes funcionalitats.
- Altres formats:
- XML: Si necessites treballar amb XML, afegeix la dependència
jackson-dataformat-xml. - YAML: Per a YAML, utilitza
jackson-dataformat-yaml. - CSV: Per a CSV, utilitza
jackson-dataformat-csv.
- XML: Si necessites treballar amb XML, afegeix la dependència
Nota:
jackson-databindja inclou internamentjackson-coreijackson-annotations, per tant no cal afegir-les per separat, excepte si es volen versions específiques.
- Mòduls addicionals: Si utilitzes funcionalitats a necessitem treballar en altres formats, usarem biblioteques específiques com:
<!-- YAML -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>2.18.0</version>
</dependency>
<!-- CSV -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-csv</artifactId>
<version>2.18.0</version>
</dependency>
- O el suport per a Java 8 Date/Time API, com
jackson-datatype-jsr310:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.18.0</version>
</dependency>
Que serveix per a serialitzar/deserialitzar objectes LocalDate, LocalDateTime, etc. Es a dir dades de tipus data/hora.