Conditional values
Conditional values simplify conditional logic and get rid of if-statements in the code.
The main purpose is to find the best result from many predefined conditions.
For example, we should edit form fields based on some conditions. This conditions could be:
- form type with many different values (contract, order, incoming document, etc.)
- form state with many different values (draft, approval, active, etc.)
- user role (viewer, editor, administrator, etc.)
- some other conditions
And based on this conditions there are different editable fields (title, subject, due date, etc.).
First we create a ValueSet
object for each distinct condition and store this objects in a single ConditionalValues
object:
ConditionalValuesBuilder<String> conditionalValuesBuilder = ConditionalValuesBuilder.newInstance();
ValueSetBuilder<String> valueSetBuilder = ValueSetBuilder.newInstance();
valueSetBuilder.addCondition("type", "contract");
valueSetBuilder.addCondition("state", "draft");
valueSetBuilder.addCondition("role", "viewer");
valueSetBuilder.addValues("title", "subject");
conditionalValuesBuilder.addValueSet(valueSetBuilder.build());
valueSetBuilder.addCondition("type", "contract");
valueSetBuilder.addCondition("state", "approval")
.addCondition("state", "active");
valueSetBuilder.addCondition("role", "viewer");
valueSetBuilder.addValues("subject", "due date");
conditionalValuesBuilder.addValueSet(valueSetBuilder.build());
valueSetBuilder.addCondition("type", "contract");
valueSetBuilder.addCondition("state", "approval")
.addCondition("state", "active");
valueSetBuilder.addCondition("role", "editor");
valueSetBuilder.addValues("title", "due date");
conditionalValuesBuilder.addValueSet(valueSetBuilder.build());
ConditionalValues<String> conditionalValues = conditionalValuesBuilder.build();
This ConditionalValues
object could be created during design-time, for example in the class static initializer.
In runtime now we can define editable fields based on current condition (current form type, current form state, current user role, etc). To perform this we create a ConditionSet
object:
ConditionSetBuilder conditionSetBuilder = ConditionSetBuilder.newInstance();
conditionSetBuilder.addCondition("type", "contract");
conditionSetBuilder.addCondition("state", "approval");
conditionSetBuilder.addCondition("role", "editor");
ConditionSet conditionSet = conditionSetBuilder.build();
And perform lookup for the best matching ValueSet
objects from ConditionalValues
object:
Values<String> values = conditionalValues.lookup(conditionSet);
Now we can use Values
to get all editable fields.
The lookup algorithm for the best matching ValueSet
objects is the following. First, all matching ValueSet
objects are defined. A ValueSet
object matches if all the object's conditions match a ConditionSet
object. Then less specific ValueSet
objects are removed. The ValueSet
object is less specific than another one if another object has all of the conditions this object has, and some more additional conditions. And, according to the previous step, both objects match a ConditionSet
object. Then values of remaining ValueSet
objects are joined and returned as a lookup result.
For example, there are predefined conditions:
Value Set 1
- type: contract
- isViewer: true
Value Set 2
- type: contract
- isEditor: true
Value Set 3
- type: contract
- state: draft
- isViewer: true
Then if we have runtime conditions (type = contract, state = draft, isViewer = true), then the best matching value set is Value Set 3 (the only one matching value set).
If we have runtime conditions (type = contract, state = approval, isViewer = true), then the best matching value set is Value Set 1 (the only one matching value set).
If we have runtime conditions (type = contract, isViewer = true, isEditor = true), then the best matching value sets are Value Set 1 and Value Set 2 (Values
object contains values from both ValueSet
objects).
If we have runtime conditions (type = contract, state = draft, isViewer = true, isEditor = true), then the best matching value sets are Value Set 2 and Value Set 3 (Value Set 1 also matches, but Value Set 3 is more specific then Value Set 1).
If we have runtime conditions (type = contract, isViewer = true), then the best matching value set is Value Set 1 (the only one matching value set).
If we have runtime conditions (isViewer = true, isEditor = true), then there are no matching value sets (Values
object is empty).
To select conditions the following should be considered. Form in the example above could be only in one state at any given moment of time. So the condition with the name state and values draft, approval, active is good enough. If the user in the examample above could have only one role, then condition with the name role and values viewer, editor, administrator is also good enough. But if the user can have several roles simultaneously, then this condition would not work. In this case several conditions should be used: condition with the name isViewer and values true and false, condition with the name isEditor and values true and false, condition with the name isAdministrator and values true and false. Then if the user has several roles, then this user could edit form fields available for each role.
Latest release
Conditional values:
- <groupId>: ru.d-shap
- <artifactId>: conditional-values
- <version>: 1.2
Donation
If you find my code useful, you can bye me a coffee