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
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:

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:

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:

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:
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