supriyo_basak
supriyo_basak

Reputation: 505

Spring ModelMapper error: Mapping already exists for controller

I am getting data from my form through a DTO and mapping it to my Hibernate entity. I wanted to skip a date field as the incoming data is all strings and I need to convert the string field into a date separately from other fields. The rest of the fields are to be directly mapped from the incoming DTO. The process works fine for the first request, but on subsequent requests, the following exception is thrown:

     1) A mapping already exists for com.ibm.calypso.entity.WmCompIdfn.setEffStartDate().

1 error
    at org.modelmapper.internal.Errors.toConfigurationException(Errors.java:250)
    at org.modelmapper.internal.TypeMapImpl.addMappings(TypeMapImpl.java:76)
    at org.modelmapper.internal.TypeMapStore.getOrCreate(TypeMapStore.java:110)
    at org.modelmapper.ModelMapper.addMappings(ModelMapper.java:93)
    at com.ibm.calypso.service.CompanyServiceImpl.updateIdentificationIdfn(CompanyServiceImpl.java:48)
    at com.ibm.calypso.controller.CompanyController.updateIdentificationIdfn(CompanyController.java:76)
    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 org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:806)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:729)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
    at org.springframework.web.servlet.FrameworkServlet.doPut(FrameworkServlet.java:883)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:651)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at com.ibm.calypso.filter.CORSFilter.doFilterInternal(CORSFilter.java:29)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
    at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2500)
    at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2489)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

The error had already been raised but no one seems to have responded to it.

https://github.com/jhalterman/modelmapper/issues/103

My code structure is similar to the one in the link.

Upvotes: 5

Views: 13039

Answers (7)

Hemel
Hemel

Reputation: 88

Most probably this is happening because you are using the same modelMapper Bin in both of the requests. The default bin scope is singleton. Configure this particular bean to be request scoped. Then the problem should be solved.

  @Bean
  @RequestScope
  public ModelMapper modelMapper() {
    return new ModelMapper();
  }

Upvotes: 0

Abhishek Chandel
Abhishek Chandel

Reputation: 199

You can use:

TypeMap<Source, Dest> typeMap = modelMapper.typeMap(Source.class, Dest.class);

Returns the TypeMap for the sourceType, destinationType, creates TypeMap automatically if none exists. Throws: IllegalArgumentException – is sourceType, destinationType are null

Upvotes: 0

Tohid Makari
Tohid Makari

Reputation: 2494

For me this error was because of adding twice createTypeMap for same object!

Upvotes: 0

TheLebDev
TheLebDev

Reputation: 531

I tried the answers supplied by horizon7 and RakeshB. Two issues:

  1. It's a workaround, not a fix
  2. It didn't work for me, unfortunately. 2.1. Disclaimer, had it worked for me I wouldn't have raised this

Anyways, further searching showed me that this is because the model mapper must be a singleton. On the first request after launching the application, it will work well, on the second request, the mapper will try to add a mapping that already exists and will thus throw the error.

When it's a Singleton, it will always be a new mapper on every request

Ref: https://stackoverflow.com/a/65346728/2918731

Upvotes: 0

Jeffrey Maier
Jeffrey Maier

Reputation: 131

I know that this is an old question, but I had the same error but for a potentially different reason. Here is the code that was causing problems:

private static final ModelMapper mapper = new ModelMapper();
{
    PropertyMap<SomeSourceClass, SomeTargetClass> map =
        new PropertyMap<SomeSourceClass, SomeTargetClass>() {
            @Override
            protected void configure() {
                // my configuration
            }
        };
    mapper.addMappings(map);
}

The issue was that ModelMapper was a static field, but that my initialization was happening every time that a new object of this class was created, the correct code uses a static initializer instead:

private static final ModelMapper mapper = new ModelMapper();
static {
    PropertyMap<SomeSourceClass, SomeTargetClass> map =
        new PropertyMap<SomeSourceClass, SomeTargetClass>() {
            @Override
            protected void configure() {
                // my configuration
            }
        };
    mapper.addMappings(map);
}

Hope this can help someone with the same problem!

Upvotes: 1

RakeshB
RakeshB

Reputation: 206

I am not sure if you found a solution to this already. But I did a work around to get past this problem. I was doing modelMapper.addMappings(myPropertymap) in my service method. So it tries to add mappings for every incoming request. I added the below check to make sure it adds only if the mapping doesn't exist already

// Before
modelMapper.addMappings(myPropertyMap);


// After
TypeMap<Source, Dest> typeMap = modelMapper.getTypeMap(Source.class, Dest.class);
if (typeMap == null) { // if not  already added
   modelMapper.addMappings(myPropertyMap);
}

Upvotes: 19

horizon7
horizon7

Reputation: 1293

The above workaround works but with following condition:

if (typeMap == null) { modelMapper.addMappings(myPropertyMap); }

With not null condition mapping will never be added to the modelMapper.

Upvotes: 2

Related Questions