Curso:
1. Primeros pasos |
2. Modelo básico del dominio (1) |
3. Modelo básico del dominio (2) |
4. Refinar la interfaz de usuario |
5. Desarrollo ágil |
6. Herencia de superclases mapeadas |
7. Herencia de entidades |
8. Herencia de vistas |
9. Propiedades Java |
10. Propiedades calculadas |
11. @DefaultValueCalculator en colecciones |
12. @Calculation y totales de colección |
13. @DefaultValueCalculator desde archivo |
14. Evolución del esquema manual |
15. Cálculo de valor por defecto multiusuario |
16. Sincronizar propiedades persistentes y calculadas |
17. Lógica desde la base de datos |
18. Validando con @EntityValidator |
19. Alternativas de validación |
20. Validación al borrar |
21. Anotación Bean Validation propia |
22. Llamada REST desde una validación |
23. Atributos en anotaciones |
24. Refinar el comportamiento predefinido |
25. Comportamiento y lógica de negocio |
26. Referencias y colecciones |
A. Arquitectura y filosofía |
B. Java Persistence API |
C. Anotaciones |
D. Pruebas automáticas
La herencia no solo sirve para reutilizar código Java y mapeos, sino también para reutilizar la definición de la interfaz de usuario, las definiciones
@View. Esta lección muestra como funciona la herencia de vistas.
Si no te gustan los videos sigue las instrucciones a continuación.
El atributo extendsView
Tanto
Pedido como
Factura usan una interfaz de usuario generada por defecto con todos sus miembros uno por cada línea. Nota como la
@View que hemos declarado en
DocumentoComercial no se ha heredado. Es decir, si no defines una vista para la entidad se genera una por defecto, la
@View de la entidad padre no se usa. Como se muestra aquí:
@View(members = "a, b, c;") // Esta vista se usa para visualizar Padre, pero no para Hijo
public class Padre { ... }
public class Hijo extends Padre { ... } // Hijo se visualiza usando la vista
// generada automáticamente, no la vista de Padre
Generalmente la vista de la entidad padre “tal cual” no es demasiado útil porque no contiene todas las propiedades de la entidad actual. Por tanto este comportamiento suele venir bien como comportamiento por defecto.
Aunque, en una entidad no trivial necesitas refinar la interfaz de usuario y quizás sea útil heredar (en lugar de copiar y pegar) la vista del padre. Puedes hacer esto usando el atributo
extendsView en
@View:
@View(members = "a, b, c;") // Esta vista sin nombre es la vista DEFAULT
public class Padre { ... }
@View(name="A" members = "d", // Añade d a la vista heredada
extendsView = "super.DEFAULT") // Extienda la vista por defecto de Padre
@View(name="B" members = "a, b, c; d") // La vista B es igual a la vista A
public class Hijo extends Padre { ... } // Hijo se visualiza usando la vista
// generada automáticamente, no la vista de Padre
Usando
extendsView los miembros a mostrar serán aquellos en la vista que extendemos más aquellos en
members de la actual.
Vamos a usar esta característica para definir las vistas para
DocumentoComercial,
Pedido y
Factura.
Vista para Factura usando herencia
Dado que la
@View de
DocumentoComercial no se hereda, la interfaz de usuario actual para
Factura es bastante fea: todos los miembros, uno por línea. Vamos a definir una interfaz de usuario mejor. Una vista parecida a la que ya teníamos, pero añadiendo una pestaña para pedidos, así:
Nota que ponemos todos los miembros de la parte de
DocumentoComercial de
Factura en la cabecera y la primera pestaña (datos), y la colección de pedidos en la otra pestaña. El siguiente código muestra la forma de definir esto sin herencia.
@View( members=
"anyo, numero, fecha;" +
"datos {" +
"cliente;" +
"detalles;" +
"observaciones" +
"}" +
"pedidos { pedidos } "
)
Puedes notar como todos los miembros, excepto la parte de
pedidos, son comunes para todos los
DocumentoComercial. Por lo tanto, vamos a mover esta parte común a
DocumentoComercial y redefinir la vista usando herencia.
Quita el viejo
@View de
DocumentoComercial y escribe esto:
@View(members=
"anyo, numero, fecha," + // Los miembros para la cabecera en una línea
"datos {" + // Una pestaña 'datos' para los datos principales del documento
"cliente;" +
"detalles;" +
"observaciones" +
"}"
)
abstract public class DocumentoComercial extends Identifiable {
Esta vista indica como distribuir los datos comunes para todos los documentos comerciales. Ahora podemos redefinir la vista de
Factura a partir de esta:
@View(extendsView="super.DEFAULT", // Extiende de la vista de DocumentoComercial
members="pedidos { pedidos }" // Añadimos pedidos dentro de una pestaña
)
public class Factura extends DocumentoComercial {
De esta forma declarar la vista para
Factura es más corto, es más, la distribución común para
Pedido,
Factura y todos los demás posibles
DocumentoComercial está en un único sitio, por tanto, si añades una nueva propiedad a
DocumentoComercial solo has de tocar la vista de
DocumentoComercial.
Vista para Pedido usando herencia
Ahora que tienes una vista adecuada para
DocumentoComercial, declarar una vista para
Pedido es lo más fácil del mundo. La vista que queremos contiene toda la información del pedido, y su factura asociada en otra pestaña:
Para obtener este resultado, puedes definir la vista de
Pedido extendiendo la vista por defecto de
DocumentoComercial y añadiendo la referencia a factura, así:
@View(extendsView="super.DEFAULT", // Extiende de la vista de DocumentoComercial
members="factura { factura } " // Añadimos factura dentro de una pestaña
)
public class Pedido extends DocumentoComercial {
Con esto conseguimos toda la información de
DocumentoComercial más una pestaña con la factura.
Usar @ReferenceView y @CollectionView para refinar vistas
Queremos que cuando un pedido sea visualizado desde la interfaz de usuario de
Factura la vista a usar sea simple, sin cliente ni factura, porque estos datos son redundantes en este caso:
Para obtener este resultado define una vista más simple en
Pedido:
@View( extendsView="super.DEFAULT", // La vista por defecto
members="factura { factura } "
)
@View( name="SinClienteNiFactura", // Una vista llamada SinClienteNiFactura
members= // que no incluye cliente ni factura
"anyo, numero, fecha;" + // Ideal para ser usada desde Factura
"detalles;" +
"observaciones"
)
public class Pedido extends DocumentoComercial {
Esta nueva vista definida en
Pedido llamada
SinClienteNiFactura puede ser referenciada desde
Factura para visualizar elementos individuales de la colección
pedidos usando
@CollectionView:
public class Factura extends DocumentoComercial {
...
@OneToMany(mappedBy="factura")
@CollectionView("SinClienteNiFactura") // Esta vista se usa para visualizar pedidos
private Collection<Pedido> pedidos;
Y tan solo con este código la colección
pedidos usará una vista más apropiada de
Factura para visualizar elementos individuales.
Además, queremos que desde la interfaz de usuario de
Pedido la factura no muestre el cliente y los pedidos, porque son datos redundantes en este caso. Para conseguirlo, vamos a definir una vista más simple en
Factura:
@View( extendsView="super.DEFAULT", // La vista por defecto
members="pedidos { pedidos } "
)
@View( name="SinClienteNiPedidos", // Una vista llamada SinClienteNiPedidos
members= // que no incluye cliente ni pedidos
"anyo, numero, fecha;" + // Ideal para usarse desde Pedido
"detalles;" +
"observaciones"
)
public class Factura extends DocumentoComercial {
Esta nueva vista definida en
Factura llamada
SinClienteNiPedidos puede ser referenciada desde
Pedido para visualizar la referencia a
Factura usando
@ReferenceView:
public class Pedido extends DocumentoComercial {
@ManyToOne
@ReferenceView("SinClienteNiPedidos") // Esta vista se usa para visualizar factura
private Factura factura;
...
Ahora la referencia
factura será visualizada desde
Pedido sin incluir el cliente y los pedidos, por lo que tendrás la interfaz de usuario más simple:
Resumen
Esta lección ha mostrado cómo usar la herencia para simplificar la definición de la interfaz de usuario, por medio del atributo
extendsView de
@View. Por el camino hemos visto también algunos ejemplo de simplificar la forma en que se visualizan las referencias y colecciones usando
@ReferenceView y
@CollectionView.