Course: 1. Getting started | 2. Modeling with Java | 3. Automated testing | 4. Inheritance | 5. Basic business logic | 6. Advanced validation | 7. Refining the standard behavior | 8. Behavior & business logic | 9. References & collections | A. Architecture & philosophy | B. Java Persistence API | C. Annotations

Appendix C: Annotations

Annotations are the tool that Java provides to define metadata in your applications. In other words, it is the way to do declarative development in Java, where you refer to “what” and not the “how” part.
In this lesson you will see the annotations you can use inside an OpenXava application to define validations, user interface and some other aspects to fit your application to your needs.
The goal of this lesson is to introduce you to these annotations. On the other hand this lesson does not show you all the intricacies and use cases of all the annotations. The comprehensive coverage of all the annotations is out of the scope of this course.

Validation

OpenXava includes an easy to use and extensible validation framework. Moreover OpenXava supports Bean Validation and Hibernate Validator.

Declarative validation

The preferred way to do validation in OpenXava is by means of annotations, i.e. in a declarative way. For example, you only have to mark a property as @Required:
@Required  // This forces to validate this property as required on save
private String name;
And OpenXava will do the appropriate validation on save:
annotations_en010.png

Built-in validations

The validation annotations that OpenXava provides are:
Annotation
Apply on
Checking
@Required
Property
Checks if the property has a value
@PropertyValidator
Property
Allows you to define custom validation logic
@EntityValidator
Entity
Allows you to define a custom validation logic
@RemoveValidator
Entity
Allows you to define a custom validation logic when removing
The Bean Validation annotations are recognized by OpenXava, so you can use all the built-in Bean Validation annotations in your OpenXava applications:
Annotation
Apply on
Checking
@Max(value=)
Property (numeric)
Checks if the value is less than or equal to max
@Min(value=)
Property (numeric)
Checks if the value is greater than or equals to min
@DecimalMax(value=)
Property (numeric or string representation of a numeric)
Checks if the value is less than or equal to max which can contains decimals
@DecimalMin(value=)
Property (numeric or string representation of a numeric)
Checks if the value is greater than or equals to min which can contains decimals
@NotNull
Property
Checks if the value is not null
@Null
Property
Checks if the value is null
@Past
Property (date or calendar)
Checks if the date is in the past
@Future
Property (date or calendar)
Checks if the date is in the future
@Pattern(regexp="regexp", flags=)*
Property (string)
Checks if the property match the regular expression given a match flag
@Size(min=, max=)
Property (string, array, collection, map)
Checks if the element size is between min and max (included)
@AssertFalse
Property
Checks that the method evaluates to false (useful for constraints expressed in code rather than annotations)
@AssertTrue
Property
Checks that the method evaluates to true (useful for constraints expressed in code rather than annotations)
@Digits(integer=,fraction=)
Property (numeric or string representation of a numeric)
Checks whether the property is a number having up to integer digits and fractional digits
You can also the Hibernate Validator annotations:
Annotation
Apply on
Checking
@Length(min=, max=)
Property (string)
Checks if the string length matches the range
@NotEmpty
Property (string, array, collection, map)
Checks if the value is not null nor empty
@Range(min=, max=)
Property (numeric or string representation of a numeric)
Checks if the value is between min and max (included)
@Email
Property (string)
Checks whether the string conforms to the email address specification
@CreditCardNumber(ignoreNonDigitCharacters=)
Property (string)
Checks whether the string is a well formated credit card number (derivative of the Luhn algorithm)
@EAN
Property (string)
Checks whether the string is a properly formated EAN or UPC-A code
@LuhnCheck(startIndex=, endIndex=, checkDigitIndex=, ignoreNonDigitCharacters=)
Property (string)
Checks that the digits within the annotated character sequence pass the Luhn checksum algorithm
@Mod10Check(multiplier=, weight=, startIndex=, endIndex=, checkDigitIndex=, ignoreNonDigitCharacters=)
Property (string)
Checks that the digits within the annotated character sequence pass the generic mod 10 checksum algorithm
@Mod11Check(threshold=, startIndex=, endIndex=, checkDigitIndex=, ignoreNonDigitCharacters=, treatCheck10As=, treatCheck11As=)
Property (string)
Checks that the digits within the annotated character sequence pass the mod 11 checksum algorithm
@NotBlank
Property (string)
Checks that the annotated character sequence is not null and the trimmed length is greater than 0
@SafeHtml(whitelistType=, additionalTags=, additionalTagsWithAttributes=)
Property (string)
Checks whether the annotated value contains potentially malicious fragments such as <script/>
@ScriptAssert(lang=, script=, alias=)
Property (any type)
Checks whether the given script can successfully be evaluated against the annotated element
@URL(protocol=, host=, port= regexp=, flags=)
Property (string)
Checks if the annotated character sequence is a valid URL according to RFC2396
Custom validation
It is very easy to add your own validation logic to your entity because the @PropertyValidator, @EntityValidator and @RemoveValidator annotations allows you to indicate a class (the validator) with the validation logic.
For example, if you want a custom logic to validate an unitPrice property, you have to write something like the code:
@PropertyValidator(UnitPriceValidator.class)  // Contains the validation logic
private BigDecimal unitPrice;
And now you can write the logic you want inside UnitPriceValidator class:
public class UnitPriceValidator
    implements IPropertyValidator {  // Must implement IPropertyValidator (1)
 
    public void validate(  // Required  because of IPropertyValidator (2)
        Messages errors,  // Here you add the error messages (3)
        Object object,  // The value to validate
        String objectName,  // The entity name, usually to use in message
        String propertyName)  // The property name, usually to use in message
    {
        if (object == null) return;
        if (!(object instanceof BigDecimal)) {
            errors.add(  // If you add an error the validation fails
                "expected_type",  // Message id in i18n file
                propertyName,  // Arguments for i18n message
                objectName,
                "bigdecimal");
            return;
        }
        BigDecimal n = (BigDecimal) object;
        if (n.intValue() > 1000) {
            errors.add("not_greater_1000");  // Message id in i18n file
        }
    }
}
As you can see your validator class must implement IPropertyValidator (shown as 1), this forces you to have a validate() (shown as 2) method that receives a Messages object, that we call errors (shown as 3). It is just a container of error messages. You only need to add a message to errors in order to provoke the validation to fail.
This is a simple way to do custom validation, moreover the validation logic in your validator can be reused across your application. Although, if you want to create a reusable validation a better option is to create your own validation annotation using Bean Validation. It's more verbose than using a validator class but it's more elegant if you reuse the validation many times.

User interface

Though OpenXava automatically generates a crude but valid user interface from a naked JPA entity, this is only useful for very basic cases. In real life applications it is required to refine the ways the user interface is generated. In OpenXava this is done by annotations that, in a very abstract way, defines the user interface shape.

The default user interface

By default, OpenXava generates a user interface that shows all members of the entity sequentially. If you have a Seller entity as here:
@Entity
public class Seller {
 
    @Id @Column(length=3)
    private int number;
 
    @Column(length=40) @Required
    private String name;
 
    @OneToMany(mappedBy="seller")
    private Collection<Customer> customers;
 
    // Getters and setters
    ...
}
OpenXava will produce for you the next user interface:
annotations_en020.png
As you see, it shows the members (number, name and customers in this case) in the same order as they are declared in the Java source. OpenXava uses the JPA and validation annotations to generate a better user interface, for example it determines the size of the editors from @Column(length), shows a key icon for the @Id property and shows an icon to indicate that it is required if the property is marked as @Required, and so on.
This default interface is useful for simple cases, but for a more advanced user interface you need a way to customize it. OpenXava provides you with annotations to do so, such as @View for customizing the layout of the members.

The @View annotation

@View annotation is used to define the layout of the members in the user interface. It is defined at the entity level:
@Entity
@View(members=
    "year, number, date;" +  // Comma means in the same line
    "discounts [" +  // Between square brackets means inside a frame
    "    customerDiscount, customerTypeDiscount;" +
    "];" +
    "comment;" +  // Semicolon means new line
    "customer { customer }" +     // Between curly brackets means inside a tab
    "details { details }" +
    "amounts { amountsSum; vatPercentage; vat }" +
    "deliveries { deliveries }"
)
public class Invoice {
This is the resulting user interface:
annotations_en030.png
As you can see, defining the layout of the member is easy. You only need to enumerate them inside a string using commas to separate elements, semicolons for new line, square brackets for groups (frames), curly brackets for sections (tabs) and so on.
You may have several views for each entity. For that purpose the @Views annotation gives a name to each view:
@Entity
@Views({
    @View(
        members="number, name; address; invoices"
    ),
    @View(
        name="Simple", members="number, name"
    )
})
public class Customer {
You can leave a view without a name which will result in a default view. The view names are used from other parts of the application to choose which view to use.
Though with a @View annotation you can define the layout but you also need to define the way each member is displayed. OpenXava takes care to provide you a lot of useful annotations which you will see in the next section.

Refining member presentation

OpenXava allows you to refine the user interface for any property, reference or collection in nearly infinite ways. You only need to add the corresponding annotation. For example, by default a reference (a @ManyToOne relationship) is displayed using a frame with a detailed view. If you want to show that reference using a combo you only have to annotate the reference with @DescriptionsList:
annotations_en040.png
If you want the effect of the annotation only for some views you can do so by using the attribute forViews available in all user interface annotations:
@Views ({     // You have several views for Seller
    @View(members=" ... "),
    @View(name="Simplest",    members=" ... "),
    @View(name="Simple", members=" ... "),
    @View(name="Complete", members=" ... "),
})
public class Seller {
 
    @DescriptionsList(forViews="Simplest, Simple")    // Combo only will be used for
    @ManyToOne(fetch=FetchType.LAZY)        // 'level' in Simplest and Simple views
    private SellerLevel level;
The next table shows all OpenXava annotations for customizing the user interface of entity members.
Annotation
Description
Apply on
@Action
Associates an action to a property or reference in the view
Properties and references
@AsEmbedded
Makes the behavior of a view for a reference (or collection) to an entity be the same an embedded object (or collection of entities with CascadeType.REMOVE)
References and collections
@Collapsed
The frame surrounding the member view will be initially closed
References and collections
@CollectionView
The view of the referenced object (each collection element) which is used to display the detail
Collections
@Condition
Restricts the elements that appear in the collection
Collections
@DescriptionsList
To visualize a reference as a descriptions list (actually a combo)
References
@DetailAction
Adds an action to the detail that is being edited in a collection
Collections
@DisplaySize
The size in characters of the editor in the User Interface used to display this property
Properties
@EditAction
Allows you to define your custom action to edit a collection element
Collections
@EditOnly
The final user can modify existing elements in the collection, but not add or remove collection elements
Collections
@Editor
Name of the editor to use for displaying the member in this view
Properties, references and collections.
@HideDetailAction
In a collection it allows you to define your custom action to hide the detail view
Collections
@LabelFormat
Format to display the label of this property or reference (displayed as descriptions list)
Properties and references
@LabelStyle
Style to display the label
Properties and descriptions list references
@ListAction
To add actions to the list in a collection
Collections
@ListProperties
Properties to show in the list for visualization of a collection
Collections
@NewAction
Allows you to define your custom action to start adding a new element to a collection
Collections
@NoCreate
The final user cannot create new objects of the referenced type from here
References and collections
@NoFrame
The reference is not displayed inside a frame
References
@NoModify
The final user cannot modify the current referenced object from here
References and collections
@NoSearch
The user will not have a link to make searches with a list, filters, etc.
References
@OnChange
Action to execute when the value of this property/reference changes
Properties and references
@OnChangeSearch
Action to execute to do the search of a reference when the user types the key value
References
@OnSelectElementAction
Allows you to define an action to be executed when an element of the collection is selected or unselected
Collections
@ReadOnly
The member will never be editable by the final user in the indicated views
Properties, references and collection
@ReferenceView
View of the referenced object used to display it in a reference
References
@RemoveAction
Allows you to define a custom action to remove the element from the collection
Collections
@RemoveSelectedAction
Allows you to define your custom action to remove the selected elements from the collection
Collections
@RowAction
In collections to add an action in each row, but not in the collection button bar
Collections
@RowStyle
For indicating the row style for list and collections
Entity (by means of @Tab) and collections
@SaveAction
Allows you to define a custom action to save the collection element
Collections
@SearchAction
Allows you to specify your own action for searching
References
@SearchListCondition
Defines a condition to be used when showing list of selectable items for adding elements to a collection or assigning value to a reference
References and collections
@Tree
Displays the collection using a tree
Collections
@ViewAction
Allows you to define your custom action to view a collection element
Collections
@XOrderBy
The eXtended version of @OrderBy (JPA)
Collections
You may think that these are a lot of annotations, but to your surprise there are more yet because most of these annotations have a plural version that allow you to declare different values for different views:
@DisplaySizes({  // To use several @DisplaySize
    @DisplaySize(forViews="Simple", value=20), // name has 20 as display
                                               // size in view Simple
    @DisplaySize(forViews="Complete", value=40) // name has 40 as display
                                                // size in view Complete
})
private String name;
Don't worry if you don't know how to use all these annotations yet. You'll learn them as you develop OpenXava applications.

Learn more about the user interface

This section introduces you briefly to the user interface with OpenXava. Unfortunately, many interesting concepts still remain untouched such as nested groups and sections, actions in views, table layout for groups and sections, view inheritance, details about how to use all UI annotations, etc. Don't worry, you will learn all these things.

Other annotations

Apart from validation and user interface OpenXava has some other useful annotations:
Annotation
Description
Apply on
@DefaultValueCalculator
For calculating the initial value
Properties and references
@Hidden
A hidden property has a meaning for the developer but not for the user
Properties
@Depends
Declares that a property depends on other one(s)
Properties
@Stereotype
A stereotype is the way to determine a specific behavior of a type
Properties
@Tab
Defines the behavior for tabular data presentation (list mode)
Entities
@SearchKey
A search key property or reference is used by the user to search
Properties and references
Summary
You have seen how to use Java annotations to do declarative programming with OpenXava. Things such as the user interface or validation that are typically programming stuff, can be done just by annotating our code.
You can learn a lot of details about these annotations and even learn about more annotations in OpenXava Reference Guide and in OpenXava API Doc of org.openxava.annotations. However, the best way to learn is by example. The rest of this course is illustrative enough with pure examples that will show you how to use these annotations.
Let's start learning.

Any problem with this lesson? Ask in the forum