API Editor - Mapping Tab
The Mappings Tab allows the user to map the input fields of the method to the fields of the entities, as well as to map fields of the entities and input fields to the output fields of the service method. The Auto-Complete feature helps the user add required fields to the mapping expressions quickly. This allows the user to configure each method of the service to obtain data from multiple providers and pass it in the required format to the method's output.
The Mappings Tab uses the Input and Output classes of the method, which users can customize in the Input/Output Tab, and allows them to map their fields with fields from entities.
In this tab, the user can manage the entities whose fields will be used in the mappings, add a new mapping using Input and Output fields of the method, and edit existing mapping expressions.
Auto-Complete
The Auto-Complete feature makes the process of adding a new mapping easier. For example, when the user enters the first letters of an entity's name - the editor shows a pop-up with suggestions of entity fields.
Entities
The user can manage the entities used in the mappings with the Entities list at the top of the tab. Any entity that has been added to the input or output classes in the Input/Output Tab will be listed here. The order of entities in this list represents the order in which entities will be obtained from the sessions. To view details about each entity, the user can select the required entity from the list.
The Entities list allows the user to:
Add an entity to the entity list;
Change an existing entity to another;
Remove an entity and all its mappings;
Add an alias for the entity;
Change the order of the entities;
Set an action for the entity.
Adding an Entity to the list
To add an entity, the user should click on the "+" button. This button will show an Entity selection dialog from which the user can select the required entity. This dialog shows only entity classes from the Service project or from its referred projects (if the project is orchestrated), all other classes are filtered out.
After selection, the entity will be added to the Entities list , if it was not previously added, and its fields will be available for mapping.
Changing an Existing Entity
The user can change an already added entity using the "Browse" button. It will show the same Entity selection dialog as when adding a new entity.
After selecting a new entity, the alias for the entity will not be changed to keep the old mapping expressions. The user can change it manually at any time.
Changing an existing entity should only be done with entities whose fields are not used in the mapping expressions yet, or with entities which have the same type and set of the fields. Otherwise, the change from one entity to a completely different entity will break the mapping expression, as the new entity will not have the required fields.
Removing an Entity
The user can remove an entity by clicking on the "X" button near the entity's name in the Entities list. A confirmation dialog prevents accidental removal and also informs the user that all mappings where this entity or entity's field is used will be deleted too, as they will become invalid.
Adding an Alias for the Entity
The user can set an alias for the entity using the "Name" input field. This name will be used for the entity in all mapping expressions. The old name of the entity will automatically be changed to the new alias in existing mapping expressions.
Changing the Order of the Entities
The user can change the order of the entities in the list by selecting an entity and using the Up ↑ or Down ↓ arrow buttons. The entity will be moved one position up or down. This order represents the order in which entities will be obtained from the sessions: the first entity in the list will be obtained first and the last entity from the list will be obtained last. This will impact the binding order, and perform calls of doAction method in the Service Implementation.
Setting an Action for an Entity
The user can set an action from the list of actions available for each entity. The list of the actions depends on the type of the entity. The selected action will be performed on the entity after binding in the Service Implementation, and it will be added to the @ServiceMethod annotation:
@ServiceMethod(name = "getClients", cacheDuration = 0, entities = { @EntityMapping(alias = "items", entity = com.as400_java.openlegacy.Items.class, action = SHOW.class) }, defaultMethod = false)
Input Mappings
The user can map fields from the method's input to the entities' fields. The user can use Spring Expression Language to manipulate values of multiple fields, and assign a result of the expression evaluation to the entity's field.
Adding a New Input Mapping
To add a new mapping, the user clicks on the "Add row" button to add a new empty row to the Input Mappings table.
In the first column of the "Target Entity Field" table, the user selects the required entity's field from the drop-down list. This list contains all the fields of the entities which were added to the Mappings tab. The user cannot add the same field twice.
In the second column of the table, the user adds a mapping expression. All fields from the input class are available for this.
Using Auto-Complete
The user can view a list of available fields and quickly find the required field using the Auto-Complete feature. The user can also call up the Suggestions pop-up using Eclipse's default shortcut for auto-complete - CTRL+SPACE. The user can then select the desired suggestion using the mouse or with Up and Down arrow keys and the Enter key. When the pop-up is displayed and the user enters the first letters of the field, the list of proposals will be updated with matching fields.
The created mapping will be added to the @BindInputs annotation on the Class level for the method's Input class in the Service Interface. This annotation contains an array of endpoints, represented by @BindTo annotations.
Deleting the Input Mapping
The user can delete a mapping by pressing the "X" button near the name of the entity's field. It will delete the entire row together with the mapping expression. A confirmation dialog prevents the user from accidental deletion. After confirmation, the mapping will be deleted from the @BindInputs annotation.
Output Mappings
The user can map input fields and fields from the entities to the output fields of the method. All output fields are already added to the left column of the Output mappings table. The user only needs to assign a mapping expression for the each field, in the same manner as for the Input mappings. The only difference is that the user can use fields from the entities together with fields from the Input in the mapping expressions. Also, the user can use Spring Expression Language in the expressions and Auto-Complete feature in the same way as in the Input mappings.
Please note that in Run Time, Output mappings will always be processed after Input mappings. In this case, input fields and fields from the entities will contain values determined in the Input mappings. The user needs to consider this to get the expected result when adding mapping expressions for the Output fields.
The user cannot delete a row from the Output mappings, as is possible in the Input Mappings table. The user only needs to clear the mapping expression.
Mapping Lists
The Auto-Complete suggestions pop-out allows the use of wildcards to map multiple entities in a list. So, in addition to the numerical indexing of entities in a list [0], and the mapping between indexed entities, use of the wildcard [*], allows the mapping of multiple entities.
Example: a proposal with wildcards:
Important note
To set the same value into the field of each element in the list, you must first add a mapping within we can determine the size of list.
For example:
The first mapping rule allows us to initialize the list of creditCards in the target object and allocate the same amount of elements that are in creditCards list of input object.
In other words if the size of the fininq2.dfhcommarea.creditCards list is equals to 10 then the size of the s3Out.dfhcommarea.creditCards will also be 10The second mapping rule with set a specific value into cardNumber field for each element of the list. In the image above, we will set a constant XXXX (constants are described below), but it can be a regular expression.
How Mapping Works
A ServiceBinder is used to evaluate mapping expressions and set evaluation results to the fields. It uses @BindTo and @BindFrom annotations to process mappings during run-time. Following is a description of the default ServiceBinder interface implementation workflow - DefaultServiceBinder.
Input
A @BindInputs annotation on the Class level for the Input class contains an array of endpoints, represented by @BindTo annotations. The @BindTo annotation contains two attributes: Endpoint and Expression. The Endpoint attribute represents a name of the entity's field to which the value will be set. The Expression attribute represents a mapping expression which can contain names of the input field. It is processed in the bindInput method of the ServiceBinder.
The bindInput method takes as parameters: an entity, the alias for this entity, and the Input class whose fields will be mapped to the entity's fields. Initially, this method gets a list of @BindTo annotations from the Input class. As each @BindTo annotation contains the name of the entity's field and a mapping expression for it, the method evaluates the expression and sets the result to the entity's field. If an error occurs during the evaluation - no value will be set to the field.
Output
The @BindFrom annotation is set on the output field. Its value contains mapping expression which should be set to the annotated field. This expression can contain names of input fields and fields from the entities. It is processed in the bindOutput method of the ServiceBinder. This method goes through all fields of the Output class, and if a field has @BindFrom annotation - parses the expression from it. After successful expression evaluation, the method sets the result of evaluation to this field. This method uses StandardEvaluationContext which contains a map of Input class and entity instances of the Input class and entities, together with their aliases from the mapping expression. Values of the fields are taken from it for evaluation of mapping expression.
Please note, that if a field from the Input or Output is null but it has a @ServiceField annotation with defaultValue attribute, this default value will be used in the expression evaluation instead of the null value.
Mapping Constants
Business entity fields can be mapped to constants. A constant must be a String literal.
Constants appear as follows in the editor:
The Constant expression must begin with one of the following characters '=', '#', '$', '@', '%'
Value Converters:
Strings can be converted to integers or BigDecimals, and vice versa, in both the input and output mappings
By default, we provide four default value converters: String to Integer, Integer to String, String to BigDecimal and BigDecimal to String.
When two different types are selected in the field and expression columns, and there is at least one converter registered for those types, a converter will be auto selected. If other converters are available, the user will be able to select it.
Additional Advantage of the Converters:
Users can define and use their own converters. This requires writing some Java code.
In API projects, we generate a Spring Configuration Java file by default (called ${project name}Configuration under the config package).
The user must define a Spring bean of org.openlegacy.impl.services.ws.converter.BinderValueConverter<{from type}, {to type}>
@Bean
public BinderValueConverter<String, Boolean> stringToBooleanConverter() {
return new BinderValueConverter<String, Boolean>() {
@Override
public Boolean convert(Object value) {
String stringValue = getFrom().cast(value);
return Boolean.parseBoolean(stringValue);
}
@Override
public Class<String> getFrom() {
return String.class;
}
@Override
public String getName() {
return "string-to-boolean";
}
@Override
public Class<Boolean> getTo() {
return Boolean.class;
}
@Override
public boolean isMatch(String name) {
return getName().equals(name);
}
};
}
In BinderValueConverter
, the user should be interested in three methods:
convert(Object value)
- this is a main method where conversion logic must exist. This method will be invoked by our binder only ifisMatch(String instruction)
will returntrue
isMatch(String name)
- this method determines whether to invoke theconvert(Object value)
method of this converter or not.String name
- this is a value from theconvertValue
attribute of the@BindTo
or@BindFrom
annotations.getName()
- this method must provide a name of custom converter which will be used in design-time
In addition to selecting custom converters on the Mappings page in the Web Service Editor, users must register their custom converter(s) in the .ol-config.yml
file in the root of the API project:
In property ol.config.designtime.mapping.converters:
This is not mandatory for the runtime, because custom converter will be registered as Spring Bean during application startup.
It is also not mandatory for the design-time , but if the user specifies a custom converter that is not registered in .ol-config.yml
, the system will display a Warning message on the Web Service Editor.
Registered custom converters will be available for future use in the suggestion box rather than having to be typed in every time.