2

I am using Orika 1.4.5, and i want to make my BidirectionalConverter to map PaginatedResponse<T> to PaginatedResponse<S> and viceversa.

The PaginatedResponse class is as follows:

public class PaginatedResponse<T> {

    private List<T> items;
    private List<Sorting> orderBy;
    private PagingResponse paging;

    public PaginatedResponse(List<T> items, List<Sorting> orderBy, PagingResponse paging) {
        this.items = items;
        this.orderBy = orderBy;
        this.paging = paging;
    }

    // Getters
}

So i want that my PaginatedResponseCovnerter takes all map calls where conversion is PaginatedResponse<Something> object1 to PaginatedResponse<OtherSomething> object2, and i want that object1 and object2 have same orderBy and paging attributes. So i try doings this:

public class PaginatedResponseConverter<T, S>
    extends BidirectionalConverter<PaginatedResponse<T>, PaginatedResponse<S>>
    implements MapperAware {

    private MapperFacade mapper;
    private T clazz1;
    private S clazz2;

    public PaginatedResponseConverter(T clazz1, S clazz2) {
        this.clazz1 = clazz1;
        this.clazz2 = clazz2;
    }

    @Override
    public void setMapper(Mapper mapper) {
        this.mapper = (MapperFacade) mapper;
    }


    @Override
    @SuppressWarnings("unchecked")
    public PaginatedResponse<S> convertTo(PaginatedResponse<T> source, Type<PaginatedResponse<S>> destinationType) {
        System.out.println("ConverTo");
        PagingResponse paging = source.getPaging();
        List<Sorting> sortings = source.getOrderBy();
        List<S> items = (List<S>) this.mapper.mapAsList(source.getItems(), this.clazz2.getClass());
        return new PaginatedResponse<S>(items, sortings, paging);
    }


    @Override
    @SuppressWarnings("unchecked")
    public PaginatedResponse<T> convertFrom(PaginatedResponse<S> source, Type<PaginatedResponse<T>> destinationType) {
        // The same upside down
    }
}

But the problem with this is that i have to register this custom converter with generics arguments , and these are not always the same. I want that if i try to convert from PaginatedResponse<SomeClass1> to PaginatedResponse<SomeClass2> be the same that PaginatedResponse<AnotherClass1> to PaginatedResponse<AnotherClass2>, and by the way, i cannot do this:

converterFactory.registerConverter(new PaginatedResponseConverter<Object, Object>(Object.class, Object.class));

because by this way all PaginatedResponse calls will get into PaginatedResponseConverter but i dont know the real type from the classes, so when it goes inside the converTo or convertFrom method, that need the exact class of the generic argument to do the mapAsList() method

Can you help me with this?

jscherman
  • 5,839
  • 14
  • 46
  • 88
  • 1
    I fear that will not be possible, as in reflection (which will be used by Orika) it is not possible to retrieve the class assigned to a generic placeholder; this is completely a compiler thing. – Uwe Allner Apr 14 '15 at 13:19
  • Thanks for your response. Have you around your mind any idea about how to solve this problem? I mean, maybe i should be use a mapper instead of converter. Do you think that this would change something? Regards! – jscherman Apr 14 '15 at 17:04
  • 1
    You will have to transport this information otherwise, perhaps by another field containing the clas or class name of the generic argument. The general problem with reflection stays the same, whatever kind of tool you use. – Uwe Allner Apr 15 '15 at 07:03

1 Answers1

0

There is this solution based on Orika's TypeBuilder that creates Type-s that store their type arguments.

My code will map a PaginatedResponse<Source> to a PaginatedResponse<Dest1> and then to a PaginatedResponse<Dest2>. If you don't mind some generic warnings, here it goes:

Driver class:

public static void main(String[] args) {
    MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
    ConverterFactory converterFactory = mapperFactory.getConverterFactory();
    converterFactory.registerConverter(new PaginatedToPaginatedConverter());

    PaginatedResponse<Source> sourcePaginatedResponse = createSourceObject();
    MapperFacade mapper = mapperFactory.getMapperFacade();

    PaginatedResponse dest1PaginatedResponse = mapper.map(sourcePaginatedResponse,
            new TypeBuilder<PaginatedResponse<Source>>(){}.build(),
            new TypeBuilder<PaginatedResponse<Dest1>>(){}.build());

    PaginatedResponse dest2PaginatedResponse = mapper.map(sourcePaginatedResponse,
            new TypeBuilder<PaginatedResponse<Source>>(){}.build(),
            new TypeBuilder<PaginatedResponse<Dest2>>(){}.build());
}

Converter, observe that I did not bother to generify PaginatedResponse, instead I overrode canConvert:

public class PaginatedToPaginatedConverter extends BidirectionalConverter<PaginatedResponse, PaginatedResponse> {

    public PaginatedResponse convertTo(PaginatedResponse paginatedResponse, Type<PaginatedResponse> destinationType) {
        PaginatedResponse dest = new PaginatedResponse();
        dest.setItems(mapperFacade.mapAsList(paginatedResponse.getItems(),
                ((Type) destinationType.getActualTypeArguments()[0]).getRawType()));
        dest.setOrderBy(mapperFacade.mapAsList(paginatedResponse.getOrderBy(), Sorting.class));
        dest.setPaging(mapperFacade.map(paginatedResponse.getPaging(), PagingResponse.class));
        return dest;
    }

    public PaginatedResponse convertFrom(PaginatedResponse paginatedResponse, Type<PaginatedResponse> destinationType) {
        return null;
    }

    @Override
    public boolean canConvert(Type<?> sourceType, Type<?> destinationType) {
        return sourceType.getRawType().equals(PaginatedResponse.class)
                && destinationType.getRawType().equals(PaginatedResponse.class);
    }
}
lcfd
  • 1,326
  • 10
  • 12