openxava / documentación / Lección 8: Herencia de vistas

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 vistas9. 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

Tabla de contenidos

Lección 8: Herencia de vistas
El atributo extendsView
Vista para Factura usando herencia
Vista para Pedido usando herencia
Usar @ReferenceView y @CollectionView para refinar vistas
Resumen
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í:
inheritance_es060.png
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:
inheritance_es070.png
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:
inheritance_es080.png
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:
inheritance_es090.png

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.

Descargar código fuente de esta lección

¿Problemas con la lección? Pregunta en el foro ¿Ha ido bien? Ve a la lección 9