openxava / documentation / Lesson 8: View inheritance

Course: 1. Getting started | 2. Basic domain model (1) | 3. Basic domain model (2) | 4. Refining the user interface | 5. Agile development | 6. Mapped superclass inheritance | 7. Entity inheritance | 8. View inheritance | 9. Java properties  | 10. Calculated properties | 11. @DefaultValueCalculator in collections | 12. @Calculation and collections totals | 13. @DefaultValueCalculator from file | 14. Manual schema evolution | 15. Multi user default value calculation | 16. Synchronize persistent and computed propierties | 17. Logic from database  | 18. Validating with @EntityValidator 19. Validation alternatives  | 20. Validation on remove  21. Custom Bean Validation annotation  | 22. REST service call from validation  | 23. Attributes in annotations  | 24. Refining the standard behavior | 25. Behavior & business logic | 26. References & collections | A. Architecture & philosophy | B. Java Persistence API | C. Annotations | D. Automated testing

Table of contents

Lesson 8: View inheritance
The extendsView attribute
View for Invoice using inheritance
View for Order using inheritance
Using @ReferenceView and @CollectionView to refine views
Summary
You can use inheritance not only for reusing the Java code and mapping, but also for reusing the user interface definition, the @View definitions. This lesson shows how view inheritance works.

If you don't like videos follow the instructions below.

The extendsView attribute

Both Order and Invoice use a user interface generated by default with all its members one in each line. Note that the annotation @View that we have declared in CommercialDocument is not inherited by default. That is, if you do not define a view for an entity a default one is generated, and the @View of the parent entity is not used. Just in this way:
@View(members = "a, b, c;") // This view is used to display Parent, but not for Child
public class Parent { ... }
 
public class Child extends Parent { ... }   // Child is displayed using an automatically
                                            // generated view, not the view from Parent
Usually the view of the parent entity “as is” is not very useful because it does not contain the new properties that the current entity has. So this behavior is good for default behavior.
Although, in a non-trivial entity you may need to refine the user interface, and it might be useful to inherit (instead of copy and paste) the view from the parent. You can do it using the extendsView attribute in @View:
@View(members = "a, b, c;") // This view with no name is the DEFAULT view
public class Parent { ... }
 
@View(name="A" members = "d", // Adds d to the inherited view
    extendsView = "super.DEFAULT") // Extends the default view from Parent
@View(name="B" members = "a, b, c; d") // View B is equals to view A
public class Child extends Parent { ... }   // Child is displayed using an automatically
                                            // generated view, not the view from Parent
Using extendsView the members that appear will be those of the extended view plus those declared in members of the current one.
We are going to use this feature for defining the views for CommercialDocument, Order and Invoice.

View for Invoice using inheritance

Given that the @View of CommercialDocument has not inherited the current user interface for Invoice it's pretty ugly to see, all the members, each in a line. We are going to define a better user interface. A view similar to the one we defined previously, but adding a tab for orders, thus:
inheritance_en060.png
Note that we have put all the members from the CommercialDocument part of the Invoice in the header and the first tab (data), and the collection of orders in the other tab. The next code shows the way to define this view without inheritance.
@View( members=
    "year, number, date;" +
    "data {" +
        "customer;" +
        "details;" +
    "remarks" +
    "}" +
    "orders { orders } "
)
public class Invoice extends CommercialDocument {
You can note how all except the orders part is common for every CommercialDocument. Therefore, we are going to move this part to CommercialDocument and then redefine this view using view inheritance.
Remove the old @View in CommercialDocument, and write this one:
@View(members=
    "year, number, date," + // The members for the header part in one line
    "data {" + // A tab 'data' for the main data of the document
        "customer;" +
        "details;" +
        "remarks" +
    "}"
)
abstract public class CommercialDocument extends Identifiable {
This view indicates how to layout the common data for all commercial documents. Now we can redefine the view for Invoice from this one:
@View(extendsView="super.DEFAULT", // Extends from the CommercialDocument view
    members="orders { orders }" // We add the orders inside a tab
)
public class Invoice extends CommercialDocument {
In this way declaring the view for Invoice is shorter. What's more, the common layout for Order, Invoice and all other possible CommercialDocument objects are all in one place. So if you add a new property to CommercialDocument you only need to touch the view for CommercialDocument.

View for Order using inheritance

Now that you have a suitable view in CommercialDocument, declararing the view for Order is plain vanilla. We want something like this:
inheritance_en070.png
To get this result, you can define the view for Order by extending the default view for CommercialDocument, adding the referenced invoice in a new tab:
@View(extendsView="super.DEFAULT", // Extends from the CommercialDocument view
    members="invoice { invoice } " // We add the invoice inside a tab
)
public class Order extends CommercialDocument {
With this we get all the data from CommercialDocument plus a tab with the invoice.

Using @ReferenceView and @CollectionView to refine views

When an order is to be viewed from the Invoice user interface, we want the view used to do so to be simple, with no customer or invoice information, because this data is redundant in this case:
inheritance_en080.png
To get this result define a simpler view in Order:
@View( extendsView="super.DEFAULT", // The default view
    members="invoice { invoice } "
)
@View( name="NoCustomerNoInvoice", // A view named NoCustomerNoInvoice
    members=                       // that does not include customer and invoice.
        "year, number, date;" +    // Ideal to be used from Invoice
        "details;" +
        "remarks"
)
public class Order extends CommercialDocument {
This new view defined in Order named NoCustomerNoInvoice can be referenced from Invoice to display the individual elements of the orders collection using @CollectionView:
public class Invoice extends CommercialDocument {

    ...

    @OneToMany(mappedBy="invoice")
    @CollectionView("NoCustomerNoInvoice") // This view is used to display orders
    private Collection<Order> orders;
And with this code only, the orders collection will use a more appropriate view from Invoice to display individual elements.
Moreover, we do not want to display the customer and order information from the Order user interface because it is redundant data in this case. To do so, we are going to define a simpler view in Invoice:
@View( extendsView="super.DEFAULT", // The default view
    members="orders { orders }"
)
@View( name="NoCustomerNoOrders", // A view named NoCustomerNoOrders
    members=                      // that does not include customer and orders
        "year, number, date;" +   // Ideal to be used from Order
        "details;" +
        "remarks"
)
public class Invoice extends CommercialDocument {
This new view defined in Invoice named NoCustomerNoOrders can be referenced from Order to display the reference to Invoice using @ReferenceView:
public class Order extends CommercialDocument {
 
    @ManyToOne
    @ReferenceView("NoCustomerNoOrders") // This view is used to display invoice
    private Invoice invoice;
 
    ...
Now the invoice reference will be displayed from Order without customers and orders so you'll get a simpler user interface:
inheritance_en090.png

Summary

This lesson has shown you how to use inheritance to simplify the definition of the user interface, by using the extendsView attribute of @View. Along the way you also have seen some examples of simplifying the way the references and collections are displayed using @ReferenceView and @CollectionView.

Download source code of this lesson

Any problem with this lesson? Ask in the forum Everything fine? Go to Lesson 9