Published 25 Oct, 2022

Java - Is it actually possible to use generics when defining mappings in Orika?

Category Java
Modified : Nov 27, 2022
100

I know about that type erasure and would prevent to use generics when defining mappings, as this question points out how to map generics objects with Orika?. But Orika FAQ, on the Are generics supported section, claims:

Yes. Orika includes special runtime support for the mapping of generic types via a special Type class which can be used to define the exact type elements of a templated type.

Ideally something like the following should work (supposing we can somehow maintain the class parameters at runtime through some Orika functionality):

     mapperFactory.classMap(Asset<T,K>.class, AssetDto<K>.class)
    .maybeSomeCustomization...
    .byDefault()
    .register();

I was not able to find any example about the Type<?> class usage the Orika FAQ mentions.

Answers

There are 2 suggested solutions here and each one has been listed below with a detailed description. The following topics have been covered briefly such as Java, Orika. These have been categorized in sections for a clear and precise explanation.

37

It is possible, you need to use the MapperFactory#classMap(Type<A>, Type<B>) API instead of MapperFactory#classMap(Class<A>, Class<B>).

You can find a lot of examples in Orika tests in the generics package.

To construct a Type instance you can use an in-place anonymous subclass of TypeBuilder:

Type<MyGenericClass<GenericParam1, GenericParam2>> type =
    new TypeBuilder<MyGenericClass<GenericParam1, GenericParam2>>() {}.build();

Note the brackets {} after the constructor which create the anonymous subclass. That way Orika can find out the actual MyGenericClass<GenericParam1, GenericParam2> type parameter using ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments().


34

You can use the TypeBuilder API to retain the generic type information so that Orika can use it when performing the mapping.

Note that Java doesn't allow us to specify the type parameter in Class literals. For example, we can't write Asset<Book>.class. Furthermore, due to type erasure, we can't access the actual type parameter at runtime. In short raw types - i.e. Asset.class - don't provide enough information to Orika.

So firstly, we must create the generic types using TypeBuilder:

Type<Asset<Person>> sourceType = new TypeBuilder<Asset<Person>>() {}.build();
Type<AssetDto<Person>> targetType = new TypeBuilder<AssetDto<Person>>(){}.build();

Then in the classMap invocation, we must use these types:

factory.classMap(sourceType, targetType).byDefault().register();

Lastly, we can perform the mapping using these types:

factory.getMapperFacade().map(asset, sourceType, targetType);

Read the following post for a detailed explanation of generics usage with Orika.