Default methods aspect oriented programming on JPA entities
When working with entity classes it is common not to add additional logic to the objects. This avoids dependencies in the code to keep it modular and maintainable. With default methods it is possible to enhance the entities in a simple way without affecting the original notion of a business object that just keeps the data.
Usually the entities are loaded from a database via the persistence layer, and are then used within the runtime context of the application. Modern frameworks provide descriptive mechanisms to define which entity attributes are to be displayed within the controls of the user interface.
public class Person { @NotNull @Size(min = 3, max = 40) private String firstName; private String name; @NotNull private Date birthday; }
If the Person entity is to be displayed in a GUI the programmer only declares the columns of the table with the names of the class attributes. Modern frameworks then automatically load the values from the databean and display them in the user interface.
public Date getBirthday() { return birthday; } public int getAgeInYears() { long ageInMillis = System.currentTimeMillis() - getBirthday().getTime(); Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(ageInMillis); return cal.get(Calendar.YEAR); }
In the above example the age of a person is an aspect of the person class that can be derived from the current date and the persons birthday. Adding such a method will enable the framework to also show the current age. However it is these kind of methods that make the code harder to maintain as they are usually scattered around in several places of code. At best the developers have managed to put them into a common utility class. (which is used as a library in different versions throughout the project..) .
To generally avoid adding logic to the entity class by introducing a getter as shown one declares it as an adapter in the GUI logic. That way the birthday is converted to the age by the presentation layer.
interface AgeAspect { Date getBirthday(); /** * See also * {@linkplain https://stackoverflow.com/questions/1116123/how-do-i-calculate-someones-age-in-java} * @return the age in years relative to today */ default int getAgeInYears() { long ageInMillis = System.currentTimeMillis() - getBirthday().getTime(); Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(ageInMillis); return cal.get(Calendar.YEAR); } } public class Person implements AgeAspect { @NotNull @Size(min = 3, max = 40) private String firstName; private String name; @NotNull private Date birthday; public Date getBirthday() { return birthday; } }
With the new default methods introduced in Java 8 one can enhance every class that has a getBirthday()
method can be amended with the age aspect by simply implementing the interface and without breaking any existing inheritance hierarchies.
The Viritin library that adds functionality for JPA entities in the Vaadin web app gui framework will soon have support for default methods, see pull request here.
Currently most frameworks do not support calling the default methods and the introspection only determines normal properties of classes. However the regular reflection api introduced in Java 4 is fully sufficient to implement this functionality therefore the libraries supporting it are still compatible with older Java releases.
Hopefully more library implementations such as the apache commons beanutils will support default methods soon.