简体   繁体   English

Orika-映射可选对象

[英]Orika - mapping Optional object

I have following two classes : 我有以下两节课:

public class TodoDto {

    private Long id;
    private String description;
    private String title;
    private long version;

    //Getters & Setters
}

@Entity
@Table(name = "todos")
public class Todo {

    public static final int MAX_LENGTH_DESCRIPTION = 500;
    public static final int MAX_LENGTH_TITLE = 100;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(name = "description", length = MAX_LENGTH_DESCRIPTION)
    private String description;

    @Column(name = "title", nullable = false, length = MAX_LENGTH_TITLE)
    private String title;

    @Version
    private long version;

    // Getters & Setters
}

I'm using the latest orika dependency : 我正在使用最新的orika依赖项:

<!-- Orika mapping -->
<dependency>
    <groupId>ma.glasnost.orika</groupId>
    <artifactId>orika-core</artifactId>
    <version>1.4.6</version>
</dependency>

I'm trying to map Optional<Todo> into Optional<TodoDto> . 我正在尝试将Optional<Todo>映射到Optional<TodoDto>

Here is the main method : 这是主要方法:

@Override
public Optional<TodoDto> findById(final Long id) {
    final MapperFacade mapper = new ConfigurableMapper() {
        @Override
        protected void configure(final MapperFactory factory) {
            factory.registerMapper(new CustomMapper<Optional<Todo>, Optional<TodoDto>>() {
                @Override
                public void mapAtoB(final Optional<Todo> s, Optional<TodoDto> d, final MappingContext context) {
                    d = Optional.empty();
                    d.get().setId(s.get().getId());
                    // ...
                }
            });
        }
    };
    final Type<Optional<Todo>> optionalOfTodo = new TypeBuilder<Optional<Todo>>() {
    }.build();
    final Type<Optional<TodoDto>> optionalOfTodoDto = new TypeBuilder<Optional<TodoDto>>() {
    }.build();
    return mapper.map(todoRepository.findById(id), optionalOfTodo, optionalOfTodoDto);
}

My test method : 我的测试方法:

@Test
public void testFindByIdNoException() {
    final Optional<TodoDto> todoDto = todoManager.findById(1L);
    todoDto.orElseThrow(NoSuchElementException::new);
    assertThat(
            todoDto.get(),
            allOf(hasProperty("id", is(1L)), hasProperty("title", is("Foo")),
                    hasProperty("description", is("Lorem ipsum"))));
}

Here is the error : 这是错误:

ma.glasnost.orika.MappingException: While attempting the following mapping:
sourceClass = class java.util.Optional
sourceType = java.util.Optional<Todo>
destinationType = java.util.Optional<TodoDto>
resolvedStrategy = InstantiateAndUseCustomMapperStrategy<Optional<Todo>, Optional<TodoDto>> {customMapper: com.mycompany.core.manager.TodoManagerImpl$1$1@359b1f57, unenhancer: ma.glasnost.orika.unenhance.BaseUnenhancer@14be750c, objectFactory: ma.glasnost.orika.generated.Optional_Optional_ObjectFactory419300372496922419300467640277$1@3be80ece}
Error occurred: java.lang.IllegalArgumentException: java.util.Optional is an unsupported source class for constructing instances of java.util.Optional
-----begin dump of current state-----------------------------
Registered object factories: 1 (approximate size: 6 850,1 kB)
  [Optional<TodoDto>] : {Optional<Todo>=ma.glasnost.orika.generated.Optional_Optional_ObjectFactory419300372496922419300467640277$1@3be80ece}
-------------------------------------------------------------
Registered mappers: 1 (approximate size: 8 149,4 kB)
  [0] : com.mycompany.core.manager.TodoManagerImpl$1$1@359b1f57
-------------------------------------------------------------
Registered concrete types: 6 (approximate size: 225,4 kB)
  [interface java.util.Collection] : ArrayList<Object>
  [interface java.util.List] : ArrayList<Object>
  [interface java.util.Set] : LinkedHashSet<Object>
  [interface java.util.Map$Entry] : MapEntry<Object, Object>
  [class java.util.Optional] : Optional<Object>
  [interface java.util.Map] : LinkedHashMap<Object, Object>
-------------------------------------------------------------
Resolved strategies: 1 (approximate size: 8 149,7 kB)
{source: Optional, dest: Optional<TodoDto>, in-place:false}: InstantiateAndUseCustomMapperStrategy<Optional<Todo>, Optional<TodoDto>> {customMapper: com.mycompany.core.manager.TodoManagerImpl$1$1@359b1f57, unenhancer: ma.glasnost.orika.unenhance.BaseUnenhancer@14be750c, objectFactory: ma.glasnost.orika.generated.Optional_Optional_ObjectFactory419300372496922419300467640277$1@3be80ece}
-------------------------------------------------------------
Unenhance strategy: ma.glasnost.orika.unenhance.BaseUnenhancer@14be750c
-----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 ma.glasnost.orika.impl.ConfigurableMapper.map(ConfigurableMapper.java:222)
    at com.mycompany.core.manager.TodoManagerImpl.findById(TodoManagerImpl.java:55)
    at com.mycompany.core.manager.TodoManagerTest.testFindByIdNoException(TodoManagerTest.java:48)
    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:483)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:73)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:73)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:224)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:68)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: java.lang.IllegalArgumentException: java.util.Optional is an unsupported source class for constructing instances of java.util.Optional
    at ma.glasnost.orika.generated.Optional_Optional_ObjectFactory419300372496922419300467640277$1.create(Optional_Optional_ObjectFactory419300372496922419300467640277$1.java)
    at ma.glasnost.orika.impl.mapping.strategy.InstantiateAndUseCustomMapperStrategy.getInstance(InstantiateAndUseCustomMapperStrategy.java:55)
    at ma.glasnost.orika.impl.mapping.strategy.UseCustomMapperStrategy.map(UseCustomMapperStrategy.java:61)
    at ma.glasnost.orika.impl.MapperFacadeImpl.map(MapperFacadeImpl.java:269)
    ... 34 more

When i use the entity and dto object without java.util.Optional everything works fine. 当我使用不带java.util.Optional的实体和dto对象时,一切正常。

Solution : 解决方案:

@Override
public Optional<TodoDto> findById(final Long id) {
    return todoRepository.findById(id).map(entity -> mapper.map(entity, TodoDto.class));
}

You don't need to pass Optional to the Orika mapper. 您无需将Optional传递给Orika映射器。

Optional is a monad, a container type that allows you to perform operations inside the container. monad是可选的,一种容器类型,允许您在容器执行操作。 In other words, don't use Optional inside your findById method, but do put your findById code inside the Optional :) 换句话说,不要在findById方法中使用Optional,而是将findById代码放在Optional中:)

Eg If your Entity Repo method findBy(id) returns Optional 例如,如果您的实体回购方法findBy(id)返回Optional

final Type<Todo> todoType = new TypeBuilder<Todo>() {}.build();
final Type<TodoDto> todoDtoType = new TypeBuilder<TodoDto>() {}.build();

return todoRepository.findById(id).
                  map(entity-> mapper.map(entity, todoType,todoDtoType)); 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM