Performance

The OTC framework has a great performance which was tested on a laptop with an 8GB RAM, 4 cores CPU running at 2.4GHz running Java 8. The test consisted of copying just one single 'String' type field from a source object to a target object. The performance was compared with Mapstruct, a know framework among the many existing object-mapping frameworke in Java. It was an apples-to-apples comparison with the exact same operation executed across both the frameworks.

The performance comparison test was done using Java Microbenchmark Harness (JMH) for throughput. And presented below is a graphical representation of the results.

OTC performance vs mapstruct performance

It shows various parameters but, I would like to draw your focus on the max throughput. The Mapstruct framework gave a performance of around 0.9+ million OPS. But whereas the OTC framework was more than eleven times faster giving a performance of 10.1+ million OPS.

The JMH test classes used for both the tests are available as part of the download.

Unique Features

The OTC framework also stands out in its features and so thrives in making the life of a developer easy when it comes to object transformations.

Before touching upon the unique features, let me introduce some common terms for some common ground -


Here is an example -
travelers.traveler[*].anonymousTravelerMap[*,*]<V>.given[*].value

What we just saw is an example of an OTCS (Object Tree Convertor Script) object-path. If you have worked with Spring's SpEL or OGNL, then this should look familiar to you. But OTC-Scripts as a whole (not just the object-path) is more elaborate and has a different purpose and is central to the OTC Framework.

In the example we notice that the depth of the object-path is 6 levels. The first field-name "travelers" is the child of a parent object which is the root object (not shown here). So from the root to the leaf-node "value" field, we have 6 levels. However there is no limit on the depth of the object-path that can be represented.

With this understanding, now let me introduce you to the unique features -

  1. Complex Deep-object-paths with collections: An object-path can have collections (arrays, lists, dictionaries which has key-and-value entries - aka. maps) The generic types in collections (including the map-keys or the map-values) may be of a composite type with each one extending the tree further down going deeper and thereby giving rise to complex deep object paths. OTC handles all of them with ease.

  2. Mappings of disparate collection-types: Both the object paths can have mixes and matches of disparate collection types. These mixes and matches in each object-path can also be disparate across both the source and target object-paths. In simple words, in OTC there are no restrictions to restrict same collection-types on both the source and target object-paths. Say for example, if the source-object-path has a dictionary, there is no restriction that the target-object-path as well should have a corresponding dictionary. Nor is there any restriction restricting the number of collections to be equal across both the object-paths. Also, one may have a collection type while the other may not have any collection-type at all for that matter. In such scenarios OTC applies some defaults.

  3. Permutations and Combinations: Take a moment to consider the number of permutations and combinations of the source and target object-paths that can arise. Deeper the object paths, more exponential are the mappings. The mixes and matches mentioned above in Deep-object-paths can result in very high number of permutations and combinations.

  4. Collection correlations: When both the source and the target object-paths have collections, and, if the target has a count more than the collection-count than the source, the first collection in the source has to correlate with one of the multiple collections in the target. OTC applies a default correlation in such scenarios.

  5. Anchoring: This is one of the main unique highlights of the OTC framework. What if the default correlation explained above is not applicable in your situation ?
    Not to worry - OTC has a very unique feature called Anchoring. It allows you to override the default correlation by just placing an Anchor character at the appropriate collection. Examples on Anchoring is given under the below sub-title ("Examples on Anchoring") to give more clarity.

  6. Performance: As already seen above, OTC delivers unmatched performance.

  7. No Annotations / Interfaces: There is no need to create interfaces or induce any annotations.

  8. Fully automated: There is no need to write lengthy configurations or code anything manually.

Examples on Anchoring


Note: XML was chosen in the below outputs for representation purposes only. But OTC works on any object meant to hold data which could be "DTOs" or "Entity objects" or "JAXB objects" to generate/consume XML or "JSON objects" to generate/consume JSON used in SOAP or REST services or the "View objects" to integrate with the UI, etc.

Consider this object path -
dataLists.passengerList.passenger[*].identityDocuments[*].givenName[*]

This object-path has 3 collections - 'passenger[*]', 'identityDocuments[*]' and 'givenName[*]'. Lets say, the framework creates an object as represented by the below output in its default behavior -

  1. This below output has a
          - single passenger in the 'Passenger' collection and
          - a single identityDocument in the 'IdentityDocument' collection
          - but with multiple name in the 'GivenName' collection.

    <DataLists>
        <PassengerList>
            <Passenger>
                <IdentityDocument>
                    <GivenName>Rajesh</GivenName>
                    <GivenName>Prem</GivenName>
                    <GivenName>Malik</GivenName>
                    <GivenName>Mahesh</GivenName>
                </IdentityDocument>
            </Passenger>
        </PassengerList>
    </DataLists>

  2. But lets ask ourselves - will this be the case always ?

    No. You might want to create an object with the values accommodated in a different way structurally by stretching the 'IdentityDocument' and contracting the 'GivenName' as shown below -

    <DataLists>
        <PassengerList>
            <Passenger>
                <IdentityDocument>
                    <GivenName>Rajesh</GivenName>
                    <GivenName>Prem</GivenName>
                </IdentityDocument>
                <IdentityDocument>
                    <GivenName>Malik</GivenName>
                    <GivenName>Mahesh</GivenName>
                </IdentityDocument>
            </Passenger>
        </PassengerList>
    </DataLists>

  3. Or, as in this one with multiple 'Passenger' and each one with its own 'IdentityDocument' :

    <DataLists>
        <PassengerList>
            <Passenger>
                <IdentityDocument>
                    <GivenName>Rajesh</GivenName>
                    <GivenName>Prem</GivenName>
                </IdentityDocument>
            </Passenger>
            <Passenger>
                <IdentityDocument>
                    <GivenName>Malik</GivenName>
                    <GivenName>Mahesh</GivenName>
                </IdentityDocument>
            </Passenger>
        </PassengerList>
    </DataLists> 
    All you need to do is use OTC's Anchoring feature by placing the Anchor character appropriately on the object path to switch between any of the stretching-contracting shown above and have the code generated in just few milliseconds.