In the previous article in this series, we had an in-depth look into how the ViewModels mechanism works in DD4T 2 for Java. This part covers the practical aspects and the basics on how to create your own ViewModels as well as having a look at how Tridion field types map to Java Object types.
In order to dive right in and start using ViewModels in your own dd4t–2-java web application, it might be handy to have a DD4T web application close by. If you haven’t got one yet and want to code while reading, read the Quick Start guide for DD4T 2 Java.
Creating a ViewModel class
Creating a ViewModel class in dd4t–2-java is pretty straightforward. A ViewModel class is nothing more than a POJO extended from the abstract org.dd4t.databind.viewmodel.base.TridionViewModelBase class:
public class Generic extends TridionViewModelBase {
}
This hooks the POJO up with basic data the dd4t-databind framework needs in order to store metadata about this ViewModel. Next, we need to add the @ViewModel annotation to give the databind framework information on when we should use this model to deserialize content into:
@ViewModel (
viewModelNames = {“genericcontent”},
rootElementNames = {“Generic”},
setComponentObject = true, // default: false
setRawData = false) // default false
public class Generic extends TridionViewModelBase {
}
The annotation has four parameters:
- viewModelNames: this is a string array of all view names (or Component Template names or the CT Metadata view names) you want this model to use for. The names generally correspond with your JSP views for Component Presentations, but this doesn’t necessarily have to be so in case you have custom view rendering logic. Finally, this is an optional parameter, but will be used the most as most ViewModels will be mapped to Component Presentation data. If you do not set this parameter, you have to set the second parameter.
- rootElementNames: this is a string array of Tridion Schema root element names. Whenever Component data is deserialized and the content in the data is based on one of the configured root element names, the databind framework will attempt to use and instantiate this ViewModel. This property is also an optional parameter. However, if you do not set it, you have to set the viewModelNames parameter with at least one view model name.
- setComponentObject: set this to true if you also want to be able to access the ComponentImpl object in your JSP view. If set to false, it will not be available, as the Component data will not be deserialized. The reason to have this parameter is simply to get a bit of a performance gain, as deserialization is an expensive process.
- setRawData: set this parameter to true if you want to access the raw Json data for whatever reason. If set to true, simply call the inherited getRawDataAsString () method to obtain it.
The nice thing about being able to set up ViewModels for multiple view names and / or root element names, is that is allows quite some flexibility and reuse of your POJO’s, mainly because it allows you to play around with how you want to offer the same (or different) content to one (or more) different views.
This mixing and matching basically comes down to the same mechanism Tridion uses when Component Presentations are constructed, as multiple content types (Schemas) can be linked to multiple Component Templates. This n:m relation is also applicable to ViewModels and can best be explained through a picture:
Creating basic ViewModel properties
Once the skeleton for the ViewModel is set up, it can already be used to instantiate ViewModels. Of course, since there are no properties inside the POJO yet, it’s not really useful. To make it useful, the actual content needs to be mapped to properties inside the ViewModel. In order to do that, we need to map the Tridion Field Type of the Schema to an actual Java Type:
Tridion Field Type | Java Type | DD4T Field Type |
Basic Types: | ||
Text | java.lang.String | TextField or XhtmlField |
Number | double | NumericField |
Date | org.joda.time.DateTime | DateField |
External Link | java.lang.String | TextField |
Complex Types: | ||
Multimedia Link | ViewModel or MultiMediaImpl or ComponentImpl | ComponentLinkField |
Component Link | ViewModel or ComponentImpl | ComponentLinkField |
Embedded Schema | ViewModel or EmbeddedField | EmbeddedField |
Keyword | Keyword or KeywordImpl/td> | KeywordField |
As you can see, there’s quite a difference between mapping Tridion’s basic field types and the more complex types. The basic field types are converted into standard Java types, while the complex types require some help from the DD4T API. The good thing about that is that the all Complex Types apart from the Keyword field types can also be converted to ViewModels.
Let’s start off by implementing the following basic schema:
The heading field is a single line text field, so the property to create is one of java.lang.String. This has to be done including getter and setter:
@ViewModel (
viewModelNames = {“genericcontent”},
rootElementNames = {“Generic”} )
public class Generic extends TridionViewModelBase {
@ViewModelProperty
private String heading;
public String getHeading () {
return heading;
}
public void setHeading (final String heading) {
this.heading = heading;
}
}
the @ViewModelProperty is a mandatory annotation for any Tridion field you want to use in your ViewModel. It has the following parameters:
- entityFieldName: this non-mandatory parameter has to be set in case the class property name (“heading”) is different than the field name in the Tridion schema.
- isMetadata: set this to true if the field you want to set should come from metadata instead of the normal content fields.
- tridionFieldType: in older DD4T versions, this parameter let’s the databind framework know which Tridion Field Type to expect. In version 2.0.2 of DD4T, this parameter is not needed anymore, so don’t use it.
These ViewmodelProperty parameters are almost never required to be set, unless Schema field names really differ from how you would name Java class parameters. The databind framework has enough data to figure things out by itself, but if you for instance would have a Metadata field called “metatitle” which you want to map to a title field in your ViewModel, then you need to set the parameters:
@ViewModelProperty(entityFieldName = “metatitle”, isMetadata = true)
private String title;
Multiple value fields
If a Tridion field has the “Allow Multiple Values” checkbox checked, the ViewModel needs to cater for that. You can do this by simply wrapping the base type in a java.util.List.
This works for all types. In our example, the body field is a multi-valued Rich Text Field and is therefore wrapper in a List. In total, the entire basic example then looks like this:
@ViewModel (
viewModelNames = {“genericcontent”},
rootElementNames = {“Generic”} )
public class Generic extends TridionViewModelBase {
@ViewModelProperty
private String heading;
@ViewModelProperty
List<String> body;
@ViewModelProperty
private double numeric;
@ViewModelProperty
private DateTime date;
@ViewModelProperty (entityFieldName = "externallink")
private String externalLink;
// getters and setters
}
Wrapping up, I hope this article showed the basics of creating ViewModels in dd4t–2-java. The next article in the series will focus on the more complex types used in ViewModels as well as using ViewModels in JSP views.