Orika - 将第 <T> 页映射到第 <TDto> 页

Orika - map Page<T> to Page<TDto>

我在将 Page 对象映射到 Page 对象时遇到问题。 我有以下映射器 class:

package com.agileplayers.agilemanager.core.mapper;

import com.agileplayers.agilemanager.core.domain.Account;
import com.agileplayers.agilemanager.core.domain.Entry;
import com.agileplayers.agilemanager.core.dto.AccountDto;
import com.agileplayers.agilemanager.core.dto.EntryDto;
import ma.glasnost.orika.MapperFacade;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import ma.glasnost.orika.metadata.TypeBuilder;
import org.springframework.data.domain.PageImpl;
import org.springframework.stereotype.Component;


@Component
public class Mapper {
    final static MapperFactory MAPPER_FACTORY = new DefaultMapperFactory.Builder().build();

    public MapperFacade getMapperFacade(){
        registerMappers();
        return MAPPER_FACTORY.getMapperFacade();
    }

    private void registerMappers(){
        MAPPER_FACTORY.classMap(Entry.class, EntryDto.class)
                .byDefault()
                .register();

        MAPPER_FACTORY.classMap(Account.class, AccountDto.class)
                .byDefault()
                .register();
        MAPPER_FACTORY.classMap(
                new TypeBuilder<PageImpl<Entry>>() {}.build(),
                new TypeBuilder<PageImpl<EntryDto>>() {}.build())
                .byDefault()
                .register();

    }
}

此处使用:

@Autowired
    private EntryRepository entryRepository;

    private void start() {
        Mapper mapper = new Mapper();
        Page<Entry> entryPage = entryRepository.findAll(new PageRequest(0, 2));

        Type<Page<Entry>> pageEntryType = new TypeBuilder<Page<Entry>>() {
        }.build();
        Type<Page<EntryDto>> pageEntryDtoType = new TypeBuilder<Page<EntryDto>>() {
        }.build();

        Page<EntryDto> entryDtoPage = mapper.getMapperFacade().map(entryPage, pageEntryType, pageEntryDtoType);

不幸的是,我收到以下信息:

Exception in thread "main" ma.glasnost.orika.MappingException: While attempting the following mapping:
sourceClass = class org.springframework.data.domain.PageImpl
sourceType = org.springframework.data.domain.Page<Entry>
destinationType = org.springframework.data.domain.Page<EntryDto>
resolvedStrategy = InstantiateAndUseCustomMapperStrategy<PageImpl<Entry>, PageImpl<EntryDto>> {customMapper: GeneratedMapper<PageImpl<Entry>, PageImpl<EntryDto>> {usedConverters: [], usedMappers: [], usedMapperFacades: [DefaultBoundMapperFacade<Sort, Sort>], usedTypes: [Object] }, unenhancer: ma.glasnost.orika.unenhance.BaseUnenhancer@4b5aa48b, objectFactory: ma.glasnost.orika.generated.PageImpl_PageImpl_ObjectFactory59678627946495970211838179@2dd2ff87}
Error occurred: java.lang.UnsupportedOperationException
-----begin dump of current state-----------------------------
Registered object factories: 3 (approximate size: 9,541.1 kB)
  [AccountDto] : {Account=DefaultConstructorObjectFactory<AccountDto>}
  [PageImpl<EntryDto>] : {PageImpl<Entry>=ma.glasnost.orika.generated.PageImpl_PageImpl_ObjectFactory59678627946495970211838179@2dd2ff87}
  [EntryDto] : {Entry=DefaultConstructorObjectFactory<EntryDto>}
-------------------------------------------------------------
Registered mappers: 3 (approximate size: 9,794.2 kB)
  [0] : GeneratedMapper<PageImpl<Entry>, PageImpl<EntryDto>> {usedConverters: [], usedMappers: [], usedMapperFacades: [DefaultBoundMapperFacade<Sort, Sort>], usedTypes: [Object] }
  [1] : GeneratedMapper<Entry, EntryDto> {usedConverters: [builtin:CloneableConverter(Copy by cloning:Date, Calendar, XMLGregorianCalendar)], usedMappers: [], usedMapperFacades: [DefaultBoundMapperFacade<Account, AccountDto>], usedTypes: [Date] }
  [2] : GeneratedMapper<Account, AccountDto> {usedConverters: [builtin:CloneableConverter(Copy by cloning:Date, Calendar, XMLGregorianCalendar)], usedMappers: [], usedMapperFacades: [], usedTypes: [Date, Entry, EntryDto] }
-------------------------------------------------------------
Registered concrete types: 6 (approximate size: 346.9 kB)
  [interface java.util.Collection] : ArrayList<Object>
  [interface java.util.Map] : LinkedHashMap<Object, Object>
  [interface java.util.Map$Entry] : MapEntry<Object, Object>
  [Page<Entry>] : PageImpl<EntryDto>
  [interface java.util.List] : ArrayList<Object>
  [interface java.util.Set] : LinkedHashSet<Object>
-------------------------------------------------------------
Resolved strategies: 4 (approximate size: 9,794.6 kB)
{source: PageImpl, dest: Page<EntryDto>, in-place:false}: InstantiateAndUseCustomMapperStrategy<PageImpl<Entry>, PageImpl<EntryDto>> {customMapper: GeneratedMapper<PageImpl<Entry>, PageImpl<EntryDto>> {usedConverters: [], usedMappers: [], usedMapperFacades: [DefaultBoundMapperFacade<Sort, Sort>], usedTypes: [Object] }, unenhancer: ma.glasnost.orika.unenhance.BaseUnenhancer@4b5aa48b, objectFactory: ma.glasnost.orika.generated.PageImpl_PageImpl_ObjectFactory59678627946495970211838179@2dd2ff87}
{source: Account, dest: AccountDto, in-place:false}: InstantiateAndUseCustomMapperStrategy<Account, AccountDto> {customMapper: GeneratedMapper<Account, AccountDto> {usedConverters: [builtin:CloneableConverter(Copy by cloning:Date, Calendar, XMLGregorianCalendar)], usedMappers: [], usedMapperFacades: [], usedTypes: [Date, Entry, EntryDto] }, unenhancer: ma.glasnost.orika.unenhance.BaseUnenhancer@4b5aa48b, objectFactory: DefaultConstructorObjectFactory<AccountDto>}
{source: Entry, dest: Object, in-place:false}: InstantiateAndUseCustomMapperStrategy<Entry, EntryDto> {customMapper: GeneratedMapper<Entry, EntryDto> {usedConverters: [builtin:CloneableConverter(Copy by cloning:Date, Calendar, XMLGregorianCalendar)], usedMappers: [], usedMapperFacades: [DefaultBoundMapperFacade<Account, AccountDto>], usedTypes: [Date] }, unenhancer: ma.glasnost.orika.unenhance.BaseUnenhancer@4b5aa48b, objectFactory: DefaultConstructorObjectFactory<EntryDto>}
{source: Entry, dest: EntryDto, in-place:false}: InstantiateAndUseCustomMapperStrategy<Entry, EntryDto> {customMapper: GeneratedMapper<Entry, EntryDto> {usedConverters: [builtin:CloneableConverter(Copy by cloning:Date, Calendar, XMLGregorianCalendar)], usedMappers: [], usedMapperFacades: [DefaultBoundMapperFacade<Account, AccountDto>], usedTypes: [Date] }, unenhancer: ma.glasnost.orika.unenhance.BaseUnenhancer@4b5aa48b, objectFactory: DefaultConstructorObjectFactory<EntryDto>}
-------------------------------------------------------------
Unenhance strategy: ma.glasnost.orika.unenhance.BaseUnenhancer@4b5aa48b
-----end dump of current state-------------------------------
    at ma.glasnost.orika.impl.ExceptionUtility.newMappingException(ExceptionUtility.java:55)
    at ma.glasnost.orika.impl.MapperFacadeImpl.map(MapperFacadeImpl.java:280)
    at ma.glasnost.orika.impl.MapperFacadeImpl.map(MapperFacadeImpl.java:243)
    at ma.glasnost.orika.impl.MapperFacadeImpl.map(MapperFacadeImpl.java:133)
    at com.agileplayers.agilemanager.AgileManagerApplication.start(AgileManagerApplication.java:49)
    at com.agileplayers.agilemanager.AgileManagerApplication.main(AgileManagerApplication.java:34)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: java.lang.UnsupportedOperationException
    at java.util.Collections$UnmodifiableCollection.clear(Collections.java:1074)
    at ma.glasnost.orika.generated.Orika_PageImpl_PageImpl_Mapper5970055563717[=14=].mapAtoB(Orika_PageImpl_PageImpl_Mapper5970055563717[=14=].java)
    at ma.glasnost.orika.impl.mapping.strategy.UseCustomMapperStrategy.map(UseCustomMapperStrategy.java:67)
    at ma.glasnost.orika.impl.MapperFacadeImpl.map(MapperFacadeImpl.java:266)
    ... 9 more

Entry映射到EntryDto或List映射到List都没有问题。我认为问题可能出在 PageImpl class 中的无参数构造函数,但这只是我的怀疑。 请指教,我做错了什么。

如果您使用的是 Spring Data Commons 1.10 或更新版本,Page 对象有一个 map 方法。只是利用它来发挥你的优势。

对于下一个示例,我假设您实际上正在使用它。

private void start() {
    final Mapper mapper = new Mapper();
    Page<Entry> entryPage = entryRepository.findAll(new PageRequest(0, 2));
    Page<EntryDto> entryDtoPage = entryPage.map(
        new Converter<Entry, EntryDto>() {
            public EntryDto convert(Entry source) {
                mapper.getMapperFacade().map(source, EntryDto);
            }
    });

无需提供任何其他代码来尝试 map/hack/reconstruct 实际页面。在 JDK8 上,您可能可以用一个漂亮的 lamda 替换它,从而使代码更小。

Page 对象确实有一个 .map() 方法,所以这很简单:

  Page<SomeEntity> daoPage = service.getEntities();
  Page<SomeDto> dtoPage = daoPage.map(it -> mapper.map(it, SomeDto.class));