Many of the core behaviors of Orika can be customized, and the main entry point for those customizations is through the DefaultMapperFactory.Builder. It allows configuration of alternative strategies and factories which help provide the core behavior—see the Javadoc for more details.
The DefaultMapperFactory itself can also be extended (along with it’s Builder) where needed; take a look at the test ma.glasnost.orika.test.extensibility.DefaultMapperFactoryExtensibilityTestCase for one such example.
The default compiler strategy used by Orika is the ma.glasnost.orika.impl.generator.JavassistCompilerStrategy, which uses the Javassist library to compile source into byte-code at runtime. This strategy is favored mostly because of it’s small library footprint, decent performance, and ease of use.
One of the drawbacks of using this strategy is that it does not produce the debug information necessary to enable step-debugging of the generated class files. There is an additional strategy, the ma.glasnost.orika.impl.generator.EclipseJdtCompilerStrategy which uses the Eclipse Jdt compiler to produce formatted source files with debug information enabled on the class files to allow step debugging of the generated Mapper and ObjectFactory code.
Note, to use this alternative in your environment, you’ll need to include the orika-eclipse-tools module among your project’s dependencies.
<dependency> <groupId>ma.glasnost.orika</groupId> <artifactId>orika-eclipse-tools</artifactId> <version>1.2.1</version><!-- please verify the latest version --> </dependency>
When Orika generates code to map from one type of field to another, it uses instances of the ma.glasnost.orika.impl.generator.Specification interface. The interface is shown below:
/** * Specification encapsulates the logic to generate code for mapping comparing a pair of types */ public interface Specification { /** * Tests whether this Specification applies to the specified FieldMap */ boolean appliesTo(FieldMap fieldMap); /** * Generates code for a boolean equality test between the two variable types, * where are potentially unrelated. */ String generateEqualityTestCode(FieldMap fieldMap, VariableRef source, VariableRef destination, SourceCodeContext code); /** * Generates code to map the provided field map */ String generateMappingCode(FieldMap fieldMap, VariableRef source, VariableRef destination, SourceCodeContext code); }
The point of control for these instances of Specification is the CodeGenerationStrategy. This class contains the ordered set of Specifications which will be tested to find a Specification which can be applied to a particular FieldMap instance.
The CodeGenerationStrategy can be obtained from the DefaultMapperFactory.Builder instance while constructing the MapperFactory, via the getCodeGnerationStrategy() method. This instance can then be used to replace, reorder, and override the Specification instances which are used to generate the mapping code.
The specifications provided by default have been ordered to match the order used to resolve a MappingStrategy instance within the MapperFacade. Re-ordering these specifications can have unintended side-effects on the standard field-mapping behavior.
In addition to the set of Specification instances used to generate standard single field mappings, there is a set of ma.glasnost.orika.impl.generator.AggregateSpecification instances which are applied whenever a nested element expression is involved. A nested element expression looks like this: someListField{someElementField}
, where ‘someElementField’ references a property on the elements within ‘someListField’.
Perhaps the best way to understand what’s going on here is to check out the source code in the ma.glasnost.orika.impl.generator package.
The default ClassMapBuilder (and it’s Factory) produces default mappings which match up fields with exact name matches in the source and destination type. This behavior can be customized by specifying an alternate to the default factory, using the classMapBuilderFactory(factory) method.
One such example is the ma.glasnost.orika.metadata.ScoringClassMapBuilder.Factory, which is able to match up the fields of a pair of types using a more sophisticated field name match scoring algorithm that factors in the similarity of field names, even among nested fields of a class. You could also provide your own such strategy to customize the behavior as needed.
Some other examples used internally are:
Another aspect of Orika you may wish to customize is the way in which properties are discovered and resolved for the types being mapped. By using the propertyResolverStrategy(strategy) method on DefaultMapperFactory.Builder, you can provide your own custom implementation of this.
The default, which is the ma.glasnost.orika.property.IntrospectorPropertyResolver, is based on discovery of “properties” based on the JavaBeans specification, with a few modifications including recognition of public fields, and allowing for Boolean with the same ‘isX’ (as is valid for boolean).
One such example provided with Orika is the ma.glasnost.orika.property.RegexPropertyResolver which allows you to specify regular expressions used to resolve the getter and setter methods for a particular property name; this PropertyResolverStrategy could be used if you have getter and setter names which do not conform to the JavaBeans standard.
For example, suppose that your getter methods were named like ‘readTheXXXProperty’, and your setter methods were named like ‘writeTheXXXProperty’; a RegexPropertyResolver could be registered to read these properties using the following code snippet:
MapperFactory factory = new DefaultMapperFactory.Builder() .propertyResolverStrategy( new RegexPropertyResolver( "readThe([\\w]+)Property", "writeThe([\\w]+)Property", true, true)) .build();
Another example is shown in the test ma.glasnost.orika.test.extensibility.PropertyResolverExtensibilityTestCase.