Skip to content

Commit 3ee8cec

Browse files
committed
Pasa las explicaciones sobre anotaciones de Jackson a JSON
1 parent 07c799c commit 3ee8cec

File tree

5 files changed

+125
-45
lines changed

5 files changed

+125
-45
lines changed

source/02.formatos/02.json/02.jackson.rst

Lines changed: 99 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ Si, en cambio, quisiéramos generar una lista de grupos y no un array:
4444

4545
.. code-block:: java
4646
47-
TypeReference<ArrayList<Grupo>> GrupoLista = new TypeReference<>(){};
48-
ArrayList<Grupo> grupos = mapper.readValue(sr, GrupoLista);
47+
TypeReference<List<Grupo>> GrupoLista = new TypeReference<>(){};
48+
List<Grupo> grupos = mapper.readValue(sr, GrupoLista);
4949
5050
.. note:: Que los miembros de cada grupo sean un array o una lista es
5151
absolutamente indiferente: la traducción se hará de igual forma.
@@ -101,6 +101,98 @@ Al escribir, es indiferente si usamos arrays o listas.
101101
102102
String contenido = mapper.writeValueAsString(grupos);
103103
104+
.. _json-jackson-annotations:
105+
106+
Anotaciones
107+
-----------
108+
Hemos visto muy por encima cómo trasladar objetos a |JSON| y viceversa. La regla
109+
es que cada atributo del objeto se traduce en una propiedad |JSON| con el mismo
110+
nombre y que conserva el mismo valor\ [#]_. Centrémonos en ``Grupo``:
111+
112+
.. code-block:: java
113+
114+
public class Grupo implements Serializable {
115+
116+
// Atributos
117+
private short nivel;
118+
private String etapa;
119+
private char grupo;
120+
private Tutor tutor;
121+
private Alumno[] miembros;
122+
123+
// Resto de la implementación
124+
}
125+
126+
La serialización de un objeto ``Grupo`` será esta:
127+
128+
.. code-block:: json
129+
130+
{
131+
"nivel": 1,
132+
"etapa": "ESO",
133+
"grupo": "C",
134+
"tutor": {
135+
// Serialización de un tutor
136+
},
137+
"miembros": [
138+
// Serialización de los alumnos
139+
]
140+
}
141+
142+
Ahora bien, ¿cómo puede personalizarse la serialización para cambiar el nombre
143+
de un atributo o no serializarlo? La librería para ello utiliza `anotaciones
144+
<https://www.geeksforgeeks.org/java/annotations-in-java/>`_ que permiten indicar
145+
todos estos particulares:
146+
147+
.. code-block:: java
148+
:emphasize-lines: 6-7
149+
150+
public class Grupo implements Serializable {
151+
152+
// Atributos
153+
private short nivel;
154+
155+
@JsonProperty("etapa_educativa")
156+
private String etapa;
157+
private char grupo;
158+
private Tutor tutor;
159+
private Alumno[] miembros;
160+
161+
// Resto de la implementación
162+
163+
}
164+
165+
De esta forma logramos que en el |JSON| la propiedad no sea ``etapa``, sino
166+
``etapa_educativa``. Si nuestra intención fuera que algún atributo no pasará al
167+
archivo, tendríamos que anotarlo con ``@JsonIgnore``. El problema de anotar
168+
directamente la clase es que quizás no nos resulte elegante o directamente no
169+
podamos, porque no dependa de nosotros la definición. Para poder añadir
170+
anotaciones sin modificar la clase original, *Jackson* proporciona un mecanismo:
171+
la mezcla. Para ello podríamos definir aparte otra clase distinta que contenga
172+
exclusivamente los atributos que necesitan anotación:
173+
174+
.. code-block:: java
175+
176+
public abstract class GrupoMixin {
177+
178+
@JsonProperty("etapa_educativo")
179+
private String etapa;
180+
}
181+
182+
Luego, al definir el mapeo. se declara que deseamos mezclar la clase original
183+
con la clase abstracta anotada:
184+
185+
.. code-block:: java
186+
:emphasize-lines: 2
187+
188+
ObjectMapper mapper = new ObjectMapper();
189+
mapper.addMixIn(Grupo.class, GrupoMixin.class);
190+
191+
.. note:: Al :ref:`serializar en formato XML <xml-jackson>` con esta librería,
192+
las anotaciones se vuelven imprescindibles, porque es la única forma de
193+
indicar, entre otras cosas, si un atributo de la clase será un elemento o un
194+
atributo |XML|.
195+
104196
.. _json-jackson-no-primitivos:
105197

106198
Tipos no primitivos
@@ -154,10 +246,6 @@ y podemos usar dos estrategias:
154246
`jackson-annotations
155247
<https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations>`_.
156248

157-
.. note:: Más adelante, al :ref:`tratar XML con esta librería <xml-jackson>`, veremos
158-
que tenemos la :ref:`posibilidad de anotar sin necesidad de tocar la clase
159-
original <jackson-mixin>`.
160-
161249
.. warning:: Al usar esta anotación puede haber desajustes al serializar las fechas
162250
como consecuencia de la zona horaria, por lo que habría que especificarla
163251
en la propia anotación:
@@ -294,6 +382,10 @@ cada uno de los atributos y hacer lo siguiente:
294382

295383
.. rubric:: Notas al pie
296384

385+
.. [#] Siempre que el tipo, claro está, sea un primitivo de |JSON| (p. ej. una
386+
cadena). Si no lo es entonces habrá que definir cómo realizar la traducción,
387+
cosa que expondremos en :ref:`json-jackson-no-primitivos`.
388+
297389
.. [#] Es decir, que si se tiene:
298390
299391
.. code-block:: java
@@ -320,4 +412,5 @@ cada uno de los atributos y hacer lo siguiente:
320412
.. |JSON| replace:: :abbr:`JSON (JavaScript Object Notation)`
321413
.. |Date| replace:: :java-util:`Date <Date>`
322414
.. |LocalDate| replace:: :java-time:`LocalDate <LocalDate>`
415+
.. |XML| replace:: :abbr:`XML (eXtensible Markup Language)`
323416

source/03.xml/02.jackson.rst

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -205,39 +205,6 @@ lectura del formato es :ref:`prácticamente la misma que para JSON <json-jackson
205205
err.printStackTrace();
206206
}
207207
208-
.. _jackson-mixin:
209-
210-
Anotaciones
211-
===========
212-
La librería, sobre todo si la usamos para leer o escribir |XML| pero no sólo,
213-
requiere en muchas ocasiones que anotemos las clases del modelo. Si no se
214-
quiere (o no se puede) hacer anotaciones directamente sobre las clases,
215-
*Jackson* proporciona un mecanismo para evitarlo: la mezcla. Ilustrémoslo con el
216-
caso de la clase Profesor original:
217-
218-
.. literalinclude:: files/Profesor.java
219-
:language: java
220-
:class: toggle
221-
:caption: Profesor.java
222-
223-
Necesitamos anotar los atributos ``id``, ``sustituye`` y ``casillero``, porque
224-
los tres deben ser atributos |XML|. Pues bien, podemos definir una clase que
225-
incluya sólo la parte anotada:
226-
227-
.. literalinclude:: files/ProfesorMixIn.java
228-
:language: java
229-
:class: toggle
230-
:caption: ProfesorMixIn.java
231-
232-
Y, luego, al crear el *mapper* para leer o escribir, podemos indicar que
233-
queremos mezclar la clase original con esta parcial anotada:
234-
235-
.. code-block:: java
236-
:emphasize-lines: 2
237-
238-
ObjectMapper mapper = new XmlMapper();
239-
mapper.addMixIn(Profesor.class, ProfesorMixIn.class);
240-
241208
.. |XML| replace:: :abbr:`XML (eXtensible Markup Language)`
242209
.. |JSON| replace:: :abbr:`JSON (JavaScript Object Notation)`
243210
.. |YAML| replace:: :abbr:`YAML (YAML Ain't Markup Language)`

source/04.conector/01.basico.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,8 +343,8 @@ a. El driver debe inferir el tipo |SQL| a partir del tipo de *Java*: eso
343343

344344
.. code-block:: java
345345
346-
if(centro == null) pstmt.setNull(1, Types.INTEGER);
347-
else pstmt.setInt(1, centro.getId());
346+
if(centro == null) pstmt.setNull(3, Types.INTEGER);
347+
else pstmt.setInt(3, centro.getId());
348348
349349
.. rubric:: Notas al pie
350350

source/98.apendices/files/Factory.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
package edu.acceso.almacenestudiantes.core;
1+
package edu.acceso.example.core;
22

33
import java.lang.reflect.Field;
44
import java.lang.reflect.InvocationTargetException;
5+
import java.net.URL;
56
import java.util.AbstractMap;
67
import java.util.ArrayList;
78
import java.util.Arrays;
@@ -35,6 +36,7 @@ public class Factory<I> {
3536
* @param interfaceClass La interfaz que implementan todas las clases que se quieren encontrar.
3637
*/
3738
public Factory(String packageName, Class<I> interfaceClass) {
39+
checkPackage(packageName);
3840
Reflections reflections = new Reflections(packageName);
3941

4042
classes = reflections.getSubTypesOf(interfaceClass)
@@ -48,6 +50,23 @@ public Factory(String packageName, Class<I> interfaceClass) {
4850
));
4951
}
5052

53+
/**
54+
* Verifica que el paquete existe.
55+
* @param packageName El nombre del paquete a verificar.
56+
*/
57+
private void checkPackage(String packageName) {
58+
if(packageName != null) {
59+
String path = packageName.replace('.', '/');
60+
URL resource = Thread.currentThread().getContextClassLoader().getResource(path);
61+
if(resource == null) {
62+
throw new IllegalArgumentException("El paquete '" + packageName + "' no existe.");
63+
}
64+
}
65+
else {
66+
throw new IllegalArgumentException("El nombre del paquete no puede ser nulo.");
67+
}
68+
}
69+
5170
/**
5271
* Lista los nombres por los que se puede referir una clase (el propio nombre
5372
* de la clase más todos los que contenga el atributo alias)

source/99.ejercicios/02.formatos.rst

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ Formatos de información
1717
#. Recapitule todo lo hecho en los ejercicios anteriores y haga la misma aplicación,
1818
pero con las siguientes características:
1919

20-
a. La aplicación puede utilizar como formato de almacenamiento |CSV|, |JSON| o
21-
la serialización directa de objetos. Qué formato se utilice se le puede
22-
preguntar al usuario como pregunta adicional de la interfaz de texto.
20+
a. La aplicación puede utilizar como formato de almacenamiento |CSV|, |JSON|,
21+
|YAML| o la serialización directa de objetos. Qué formato se utilice se le
22+
puede preguntar al usuario como pregunta adicional de la interfaz de texto.
2323

2424
#. Alternativamente a la interfaz de texto, la aplicación debería poderse
2525
correr en modo *automático*. En este modo, el propio código tiene incluidos
@@ -34,3 +34,4 @@ Formatos de información
3434

3535
.. |CSV| replace:: :abbr:`CSV (Comma-separated values)`
3636
.. |JSON| replace:: :abbr:`JSON (JavaScript Object Notation)`
37+
.. |YAML| replace:: :abbr:`YAML (YAML Ain't Markup Language)`

0 commit comments

Comments
 (0)