@Retention(RetentionPolicy.RUNTIME)
@Target(value = { ElementType.FIELD, ElementType.METHOD })
@LinkkiBoundProperty(BindValueAnnotationBoundPropertyCreator.class)
@LinkkiAspect(BindFieldValueAspectDefinitionCreator.class)
public @interface BindValue {
String pmoProperty() default "";
String modelObject() default ModelObject.DEFAULT_NAME;
String modelAttribute() default "";
...
}
Extending linkki
Custom Annotation with Binder
Binder
is used for manual binding of UI components that are annotated with the annotation @Bind. The annotation specifies certain properties that are commonly bound to UI components such as the value, as well as the visible/enabled/required states. In addition, it also defines how a bound property is identified with the help of the attributes pmoProperty
, modelObject
and modelAttribute
.
If the annotation does not suit your needs then a custom annotation could be implemented easily. For example, it can be useful if you want to bind each property with an individual annotation.
The following example demonstrates how to design a custom @BindValue
annotation to bind only the value of a component:
The custom annotation class must be annotated with another annotation called @LinkkiBoundProperty
which provides a BoundProperty
. A BoundProperty
is necessary as it describes which property in the PMO and the business model should be bound to the annotated component. @LinkkiBoundProperty
provides the BoundProperty
by defining a creator Class that implements the interface BoundPropertyCreator
. This creator must have a default constructor that can be later called by the linkki framework to create a BoundProperty
.
In the example, the @BindValue
annotation defines the BindValueAnnotationBoundPropertyCreator
as its @LinkkiBoundProperty
:
class BindValueAnnotationBoundPropertyCreator implements BoundPropertyCreator<BindValue> {
@Override
public BoundProperty createBoundProperty(BindValue annotation, AnnotatedElement annotatedElement) {
return getPmoProperty(annotation, annotatedElement)
.withModelObject(annotation.modelObject())
.withModelAttribute(annotation.modelAttribute());
}
private BoundProperty getPmoProperty(BindValue annotation, AnnotatedElement annotatedElement) {
String pmoPropertyName = annotation.pmoProperty();
if (StringUtils.isEmpty(pmoPropertyName)) {
if (annotatedElement instanceof Method) {
return BoundProperty.of((Method)annotatedElement);
} else if (annotatedElement instanceof Field) {
return BoundProperty.of((Field)annotatedElement);
} else {
throw new IllegalArgumentException("The @" + BindValue.class.getSimpleName()
+ " annotation only supports reading the property name from " + Field.class.getSimpleName()
+ "s and " + Method.class.getSimpleName() + "s");
}
} else {
return BoundProperty.of(pmoPropertyName);
}
}
}
The example above works quite similar to the existing @Bind
annotation. But it is also possible to define the bound property in a different way. For example, the model attribute and model object might be specified by another annotation.
Finally, the @BindValue
annotation needs to define BindFieldValueAspectDefinition
as a @LinkkiAspect
(see Aspects).
Now the @BindValue
annotation can be used with a Binder
for manual binding:
@BindValue(pmoProperty = "zip", modelAttribute = Address.PROPERTY_ZIP)
private final TextField zipTxt;
Just as the @Bind
annotation, the new annotation can also be used on getter methods:
@BindValue(pmoProperty = "zip")
public TextField getZipTxt() {
return zipTxt;
}