IOMapper

tag licence Maven Central Powered by documentation

IOMapper is an easy and powerful mapping tool built entirely in java language without third-party dependencies.

Main Features

Toggle mapping

Since IOMapper was designed to avoid these annoying verbose mapping lines, it’s able to identify fields with identical names and perform the mapping automatically.

Also the toggle in mapping is simply easy using a bridge class and through the outer and inner methods:

private BridgeMap<SourceObject, TargetObject> map = new IOMapBridge<>();
TargetObject mappedTarget = map.inner()
              .from(yourSourceObjectInstance)
              .to(TargetObject.class)
              .build();
SourceObject mappedSource = map.outer()
              .from(yourTargetObjectInstance)
              .to(SourceObject.class)
              .build();

Ignoring mapping fields

IOMapper allows you to ignore source fields in automatic mappings as follow:

TargetObject target = map
    ...   
    .ignoring(ignorableFields ->
      ignorableFields
          .ignore("nameSourceField1")
            .ignore("nameSourceField2")  
    ).build();

In this case, nameSourceField1 and nameSourceField2 belonging to source object instance, are ignored in automatic mapping.

Explicit mappings

If you want to carry out an explicit mapping in the case of fields with different names source-target it’s possible as follows:

TargetObject target = map
    ...
    .relate(customMapping ->  
        customMapping.relate("nameSourceField", "nameTargetField")  
    ).build();

The relate method receives two arguments: source field and target field in that order.

Functions

This is where the magic begins, IOMapper is able to execute functions on the fields as follows:

We’re going to use an example where it’s needed get a full name as a result of fields concatenation in a User object:

User user = map.inner().from(userDtoInstance).to(User.class).relate(customMapping ->  
        customMapping  
            .relate("concat(name, middleName, lastName, ['s'])", "name")  
).build(); 

As you can see, it is possible to make use of functions through custom mappings, in this case the concat function is applied to the fields: name, middleName, lastName. It should be taken into account that is necessary to use a delimiter that help us separate the fields, in this case ‘s’ is the delimiter used, which represents a blank.

Note: It is possible to set any character as a delimiter, however ‘s’ is a
preset delimiter. The delimiter must be the last argument of the
function and must also be within brackets.

It is also worth mentioning that IOMapper encourages the use of conventions, forcing the use of a comma separated by a space for multiple arguments.

field1, field2 - GOOD
field1,field2 - WRONG

If you thought it was over, wait for more …

Multiple mapping

if you need to assign the same value to multiple target fields IOMapper can do this for you.

Taking our previous example:

User user = map.inner().from(userDtoInstance).to(User.class).relate(customMapping ->  
        customMapping  
                .relate("name", "alias, userId")  
).build();

In this case, the value of name field is assigned to alias and userId target fields. As you can see, the second argument is separated by a comma in the string.

Summary

So far, IOMapper has the following features:

And in case you thought it was not possible

Nesting

As an additional touch, IOMapper can also perform operations on nested fields as we will see later.

The way to access nested fields is through the dot operator, just as you would in a Java object to access its properties or methods, thus representing the field path as follows:

Ignorable fields

Ignoring the state field inside the Address object.

ignorableFields.ignore("address.state")

remember that the ignorable field is the one belonging to the source field.

Explicit nested mapping

Mapping the zip field inside the AddressDto object to the zipCode field inside the Address object.

relate("addressDto.zip", "address.zipCode")

Once again, we have our source field as the first argument and our destination field as the second one.

Functions

The concat function is invoked at the same level where the fields to which this function will be applied are located.

customMapping.relate("addressDto.concat(state, zip, ['*'])", "fullAddress")

In this case the function is invoked within the AddressDto object for the state and zip fields.

And the stellar is for…

NESTED FUNCTIONS

IOMapper which thinks about the complexity of its assignments, has integrated support for nested functions, which allows several functions to be invoked on the value of a field or fields of an object as follows:

NumericDto numericDto = map
    .outer()
    .from(numericModelInstance)
    .to(NumericDto.class)
    .relate(customMapping ->  
        customMapping.relate("toString(add(add(byteField, shortField), 10))", "stringI")  
    ).build();

In this case we have some functions applied on pair of fields belonging to the numericModelInstance object (toString and add (twice) functions): byteField (=7), shortField (=7) and the value 10 (a random number) to finally assign the result to the stringI field (found in the NumericDto object).

Testing the previous snippet through a test assertion, the following statement must be true.

assertEquals("24", numericDto.getStringI());

Taking into account the need of the previous example, first the sum of the byteField and shortField field is done and then add its result to the number 10, finally the latter is converted to a String type to be assigned to stringI of the same type.

As you can see, it is possible to assign literals without the need of an associated field, in this case the value 10.

and as expected…

Nested functions in nested fields

Without leaving nested operations aside IOMapper is able to apply nested functions in nested fields as follows:

customMapping.relate("nestedNumericModel.toString(add(add(number1, number2), 7))", "stringI")

toString function is applied on fields of nestedNumericModel object which in turn is an object of numericModelInstance from our previous example.

Build-in-Functions

IOMapper integrates some functions commonly used for data processing.

name operation parameters
add sum numerical types int, long, float, double
concat concatenates values taken as string string and the optional last argument must also be within brackets the way: [‘delimiter’]
toBoolean convert a value to boolean any value assignable to boolean
toByte convert a value to byte any value assignable to byte
toDouble convert a value to double any value assignable to double
toFloat convert a value to float any value assignable to float
toInt convert a value to integer any value assignable to integer
toLong convert a value to long any value assignable to long
toShort convert a value to short any value assignable to short
toString convert a value to string any value assignable to string

more functions will be added soon.

If a non-existent functions is used to perform an operation you will get an annoying RuntimeException indicating the strange guest.

Another advantage offered by IOMapper is to implement your own functions, that’s right! You can create your own functions that perform operations according to your needs, this is achieved in a very simple way, you just have to implement the Callable interface that will force you to implement the invoke method that will be called by The IOMapper algorithm passing you the necessary arguments to perform your operation, pay attention to the following code:

public class YourCustomFunction implements Callable {

    @Override  
  public Result invoke(String arguments) {
    //TODO
    
    return result;
  }
  
}

we have YourCustomFunction that represents our custom function, as mentioned above, it is necessary to implement the Callable interface, in the same way as you can see, the invoke method is implemented and within this is where you should apply your functionality .

Note: The arguments are represented like a one single String comma-separated that you must split to get the single arguments.

The invoke method returns a Result object which is nothing more than a wrapper for the final result.

IMPORTANT! for IOMapper to visualize your custom implementations, its should be under the package name mapping.functions in your project class path.

Contributions

IOMapper is a young project created and thought to contribute in the Java community. If you want to be part of their growth we invite you to collaborate with new ideas or improvements. Check out the code documentation to get a better understanding of its composition.