6

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.

Community
  • 1
  • 1
David Fernandez
  • 585
  • 1
  • 6
  • 20

2 Answers2

8

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().

Adam Michalik
  • 9,678
  • 13
  • 71
  • 102
  • 1
    Thank you, that makes sense, subclassing to find out the type arguments. The Orika FAQ could have actually pointed to the unit tests you mention. – David Fernandez Feb 18 '16 at 10:28
0

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.

isaolmez
  • 1,015
  • 11
  • 14