<dependency>
<groupId>org.linkki-framework</groupId>
<artifactId>linkki-ips-vaadin-flow</artifactId>
</dependency>
Extending linkki
Faktor-IPS Extension
linkki is often used in conjunction with Faktor-IPS. The module linkki-ips-vaadin-flow
provides some useful functionalities for this combination.
To use the extension simply include the following Maven dependency:
Fields for Faktor-IPS Data Types
A new UI component annotation @UIDecimalField
supports the Faktor-IPS data type Decimal
. It is quite similar to @UIDoubleField
but supports Decimal
instead of Double
.
Other Faktor-IPS-specific fields - for example a Money
field - may follow.
Faktor-IPS Model Validation
Validating a Faktor-IPS object yields messages for the validation framework on the business layer. linkki uses its own validation message implementation in the UI layer. To convert these messages from Faktor-IPS to linkki, the Faktor-IPS extension provides a MessageConverter
. Objects are converted according to the following table:
Faktor-IPS | linkki | Notes |
---|---|---|
org.faktorips.runtime.Message |
org.linkki.core.binding.validation.message.Message |
|
org.faktorips.runtime.MessageList |
org.linkki.core.binding.validation.message.MessageList |
|
org.faktorips.runtime.ObjectProperty |
org.linkki.core.binding.validation.message.ObjectProperty |
The |
org.faktorips.runtime.IMarker |
org.linkki.ips.messages.ValidationMarkerWrapper |
linkki only uses the |
Calling the Faktor-IPS validation method and converting the messages should be done directly in a ValidationService, which is then provided to the BindingManager
.
ValidationService validationService = () -> MessageConverter
.convert(ipsModelObject.validate(new ValidationContext(UiFramework.getLocale())));
When the function above is called by linkki, the Faktor-IPS object is validated according to the defined validation rules. Rules can add messages to the returned MessageList
, potentially referencing specific fields using ObjectProperty
.
These messages are then converted, and displayed to the user. Messages referring to an ObjectProperty
bound by linkki to a UI field, are shown in the UI accordingly. It is possible to define further styling.
Faktor-IPS Property Dispatcher
A special PropertyDispatcher
called IpsPropertyDispatcher
can be used in a binding context to automatically retrieve information from the Faktor-IPS model when using appropriate model binding.
To override the behaviour of the IpsPropertyDispatcher , use a different attribute value in the UI annotation, such as DYNAMIC .
|
Supported aspects
The following aspects are supported:
- Label
-
In case you do not specify a label for a UI component in your PMO, the dispatcher tries to retrieve the label from the underlying model object. That means, if your underlying model object is generated by Faktor-IPS and the associated bound model attribute is a Faktor-IPS attribute, it returns the label of this Faktor-IPS attribute. If the model object is
null
, the dispatcher falls back to the declared model object class to provide the attribute label. - Required
-
If the
required
attribute in the UI annotation is set to its default valueNOT_REQUIRED
, theIpsPropertyDispatcher
checks the value set of the corresponding attribute. The field is then set toREQUIRED
if the value set does not containnull
. - Visible
-
If the
visible
attribute in the UI annotation is set to its default valueVISIBLE
, theIpsPropertyDispatcher
checks the value set of the corresponding attribute. The field is then set toINVISIBLE
if the value set isnull
or empty. - Enabled
-
If the
enabled
attribute in the UI annotation is set to its default valueENABLED
, theIpsPropertyDispatcher
checks the value set of the corresponding attribute. The field is then set toDISABLED
if the value set isnull
or empty.
- Available Values
-
If the
content
attribute in the UI annotation (present in annotations such as@UIComboBox
or@UIRadioButtons
) is set toENUM_VALUES_INCL_NULL
orENUM_VALUES_EXCL_NULL
, theIpsPropertyDispatcher
will get the value set of the corresponding attribute and sets it in the UI. If the attribute value set in the model is unrestricted theIpsPropertyDispatcher
delegates to the nextPropertyDispatcher
.
How to include IpsPropertyDispatcher
To include the IpsPropertyDispatcher
as a custom dispatcher in the BindingContext
, the IpsPropertyDispatcherFactory
can be provided to the constructor of the DefaultBindingManager
. If you already have a custom PropertyDispatcherFactory
you could simply instantiate the IpsPropertyDispatcher
in your subclass using the factory method IpsPropertyDispatcher#createIpsPropertyDispatcher
.
BindingManager bindingManager = new DefaultBindingManager(validationService,
PropertyBehaviorProvider.NO_BEHAVIOR_PROVIDER, new IpsPropertyDispatcherFactory());
When the IpsPropertyDispatcher is active, the available values set directly in the PMO will be ignored.
|
PROPERTY Constants as Model Attributes
Faktor-IPS generates constants for defined attributes containing their name. These values can be used as the modelAttribute
to easily create bound UI components.
If the used property is removed from the Faktor-IPS model while still being referenced from an annotation, a compilation error is generated. This would not be the case if hardcoded strings were used.
public static final String PROPERTY_STRING = "string";
/**
* Max allowed values for property string.
*
* @generated
*/
@IpsAllowedValues("string")
public static final ValueSet<String> MAX_ALLOWED_VALUES_FOR_STRING = new UnrestrictedValueSet<>(true);
/**
* The default value for string.
*
* @generated
*/
@IpsDefaultValue("string")
public static final String DEFAULT_VALUE_FOR_STRING = null;
/**
* The name of the property unrestrictedInclNull.
*
* @generated
*/
public static final String PROPERTY_UNRESTRICTEDINCLNULL = "unrestrictedInclNull";
/**
* Max allowed values for property unrestrictedInclNull.
*
* @generated
*/
@IpsAllowedValues("unrestrictedInclNull")
public static final ValueSet<String> MAX_ALLOWED_VALUES_FOR_UNRESTRICTED_INCL_NULL = new UnrestrictedValueSet<>(
true);
/**
* The default value for unrestrictedInclNull.
*
* @generated
*/
@IpsDefaultValue("unrestrictedInclNull")
public static final String DEFAULT_VALUE_FOR_UNRESTRICTED_INCL_NULL = "not required";
/**
* The name of the property unrestrictedExclNull.
*
* @generated
*/
public static final String PROPERTY_UNRESTRICTEDEXCLNULL = "unrestrictedExclNull";
/**
* Max allowed values for property unrestrictedExclNull.
*
* @generated
*/
@IpsAllowedValues("unrestrictedExclNull")
public static final ValueSet<String> MAX_ALLOWED_VALUES_FOR_UNRESTRICTED_EXCL_NULL = new UnrestrictedValueSet<>(
false);
/**
* The default value for unrestrictedExclNull.
*
* @generated
*/
@IpsDefaultValue("unrestrictedExclNull")
public static final String DEFAULT_VALUE_FOR_UNRESTRICTED_EXCL_NULL = "required";
/**
* The name of the property emptyValueSet.
*
* @generated
*/
public static final String PROPERTY_EMPTYVALUESET = "emptyValueSet";
/**
* Max allowed values for property emptyValueSet.
*
* @generated
*/
@IpsAllowedValues("emptyValueSet")
public static final OrderedValueSet<Marker> MAX_ALLOWED_VALUES_FOR_EMPTY_VALUE_SET = new OrderedValueSet<>(false,
null);
/**
* The default value for emptyValueSet.
*
* @generated
*/
@IpsDefaultValue("emptyValueSet")
public static final Marker DEFAULT_VALUE_FOR_EMPTY_VALUE_SET = null;
/**
* The name of the property enumerationValueSet.
*
* @generated
*/
public static final String PROPERTY_ENUMERATIONVALUESET = "enumerationValueSet";
/**
* Max allowed values for property enumerationValueSet.
*
* @generated
*/
@IpsAllowedValues("enumerationValueSet")
public static final OrderedValueSet<Marker> MAX_ALLOWED_VALUES_FOR_ENUMERATION_VALUE_SET = new OrderedValueSet<>(
false, null, Marker.REQUIRED_INFORMATION_MISSING, Marker.TECHNICAL_CONSTRAINT_VIOLATED);
/**
* The default value for enumerationValueSet.
*
* @generated
*/
@IpsDefaultValue("enumerationValueSet")
public static final Marker DEFAULT_VALUE_FOR_ENUMERATION_VALUE_SET = null;
/**
* The name of the property integerEnumerationValueSet.
*
* @generated
*/
public static final String PROPERTY_INTEGERENUMERATIONVALUESET = "integerEnumerationValueSet";
/**
* Max allowed values for property integerEnumerationValueSet.
*
* @generated
*/
@IpsAllowedValues("integerEnumerationValueSet")
public static final OrderedValueSet<Integer> MAX_ALLOWED_VALUES_FOR_INTEGER_ENUMERATION_VALUE_SET = new OrderedValueSet<>(
true, null, Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3), Integer.valueOf(4),
Integer.valueOf(5), null);
/**
* The default value for integerEnumerationValueSet.
*
* @generated
*/
@IpsDefaultValue("integerEnumerationValueSet")
public static final Integer DEFAULT_VALUE_FOR_INTEGER_ENUMERATION_VALUE_SET = null;
/**
* The name of the property integerRangeValueSet.
*
* @generated
*/
public static final String PROPERTY_INTEGERRANGEVALUESET = "integerRangeValueSet";
/**
* Max allowed range for the property integerRangeValueSet.
*
* @generated
*/
@IpsAllowedValues("integerRangeValueSet")
public static final IntegerRange MAX_ALLOWED_RANGE_FOR_INTEGER_RANGE_VALUE_SET = IntegerRange
.valueOf(Integer.valueOf("0"), Integer.valueOf(100), Integer.valueOf(5), true);
/**
* The default value for integerRangeValueSet.
*
* @generated
*/
@IpsDefaultValue("integerRangeValueSet")
public static final Integer DEFAULT_VALUE_FOR_INTEGER_RANGE_VALUE_SET = null;
/**
* The name of the property booleanValueSet.
*
* @generated
*/
public static final String PROPERTY_BOOLEANVALUESET = "booleanValueSet";
/**
* Max allowed values for property booleanValueSet.
*
* @generated
*/
@IpsAllowedValues("booleanValueSet")
public static final ValueSet<Boolean> MAX_ALLOWED_VALUES_FOR_BOOLEAN_VALUE_SET = new UnrestrictedValueSet<>(false);
/**
* The default value for booleanValueSet.
*
* @generated
*/
@IpsDefaultValue("booleanValueSet")
public static final Boolean DEFAULT_VALUE_FOR_BOOLEAN_VALUE_SET = null;
/**
* The name of the property emptyStringValueSet.
*
* @generated
*/
public static final String PROPERTY_EMPTYSTRINGVALUESET = "emptyStringValueSet";
/**
* Max allowed values for property emptyStringValueSet.
*
* @generated
*/
@IpsAllowedValues("emptyStringValueSet")
public static final OrderedValueSet<String> MAX_ALLOWED_VALUES_FOR_EMPTY_STRING_VALUE_SET = new OrderedValueSet<>(
false, null);
/**
* The default value for emptyStringValueSet.
*
* @generated
*/
@IpsDefaultValue("emptyStringValueSet")
public static final String DEFAULT_VALUE_FOR_EMPTY_STRING_VALUE_SET = null;
@IpsAttribute(name = "string", kind = AttributeKind.CHANGEABLE, valueSetKind = ValueSetKind.AllValues)
@IpsGenerated
public String getString() {
return string;
}
@ModelObject
private final IpsModelObject modelObject;
@UITextField(position = 0, modelAttribute = IpsModelObject.PROPERTY_STRING)
public void getString() {
// model binding
}