javamodelmapper

ModelMapper: converting a `LocalDateTime` property into a `long`


I'm having a hard time configuring a ModelMapper so that it can convert a LocalDateTime property into a long.

Here is my source class:


public class Source {
     private LocalDateTime time;

     public LocalDateTime getTime() {
         return time;
     }

     public void setTime(LocalDateTime time) {
         this.time = time;
     }
}

my destination class:

public class Destination {
     private long time;

     public long getTime() {
         return time;
     }

     public void setTime(long time) {
         this.time = time;
     }
}

I configure my ModelMapper as follows:

         ModelMapper mapper = new ModelMapper();
         mapper.getConfiguration()
                 .setMatchingStrategy(MatchingStrategies.STRICT);
    
         mapper.typeMap(Source.class, Destination.class)
                 .addMappings(map -> {
             map.map(src -> toMillis(src.getTime()), Destination::setTime);
         });

...

     private static long toMillis(LocalDateTime dt) {
         if (dt == null) {
             return 0;
         }
         ZonedDateTime zdt = ZonedDateTime.of(dt, ZoneId.systemDefault());
         return zdt.toInstant().toEpochMilli();
     }

And use it as follows:

         Source src = new Source();
         src.setTime(LocalDateTime.now());
         Destination dst = mapper.map(src, Destination.class);

But I'm getting the exception bellow:


Exception in thread "main" org.modelmapper.MappingException: ModelMapper
mapping errors:

1) Converter org.modelmapper.internal.converter.NumberConverter@72967906
   failed to convert java.time.LocalDateTime to long.

1 error
at
org.modelmapper.internal.Errors.throwMappingExceptionIfErrorsExist(Errors.java:380)
at
org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:80)
at org.modelmapper.ModelMapper.mapInternal(ModelMapper.java:573)
at org.modelmapper.ModelMapper.map(ModelMapper.java:406)
at org.tastefuljava.test19.Main.main(Main.java:21)
Caused by: org.modelmapper.MappingException: ModelMapper mapping errors:

1) Error mapping 2023-01-09T12:47:56.793910 to java.lang.Long

1 error
at org.modelmapper.internal.Errors.toMappingException(Errors.java:258)
at
org.modelmapper.internal.converter.NumberConverter.numberFor(NumberConverter.java:181)
at
org.modelmapper.internal.converter.NumberConverter.convert(NumberConverter.java:75)
at
org.modelmapper.internal.converter.NumberConverter.convert(NumberConverter.java:57)
at
org.modelmapper.internal.MappingEngineImpl.convert(MappingEngineImpl.java:306)
at
org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:109)
at
org.modelmapper.internal.MappingEngineImpl.setDestinationValue(MappingEngineImpl.java:245)
at
org.modelmapper.internal.MappingEngineImpl.propertyMap(MappingEngineImpl.java:187)
at
org.modelmapper.internal.MappingEngineImpl.typeMap(MappingEngineImpl.java:151)
at
org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:105)
at
org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:71)
... 3 more
Caused by: java.lang.NumberFormatException: For input string:
"2023-01-09T12:47:56.793910"
at
java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Long.parseLong(Long.java:711)
at java.base/java.lang.Long.valueOf(Long.java:1159)
at
org.modelmapper.internal.converter.NumberConverter.numberFor(NumberConverter.java:171)
... 12 more
Command execution failed.
org.apache.commons.exec.ExecuteException: Process exited with an error:
1 (Exit value: 1)
at
org.apache.commons.exec.DefaultExecutor.executeInternal(DefaultExecutor.java:404)
at
org.apache.commons.exec.DefaultExecutor.execute(DefaultExecutor.java:166)
at
org.codehaus.mojo.exec.ExecMojo.executeCommandLine(ExecMojo.java:982)
at
org.codehaus.mojo.exec.ExecMojo.executeCommandLine(ExecMojo.java:929)
at org.codehaus.mojo.exec.ExecMojo.execute(ExecMojo.java:457)
at
org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:134)
at
org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:207)
at
org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
at
org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
at
org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:116)
at
org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:80)
at
org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
at
org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:307)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:193)
at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:106)
at org.apache.maven.cli.MavenCli.execute(MavenCli.java:863)
at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:288)
at org.apache.maven.cli.MavenCli.main(MavenCli.java:199)
at
java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:577)
at
org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
at
org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
at
org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
at
org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)

Could anyone help me fix this? Thanks in advance


Solution

  • That's an issue with ModelMapper, where it is not able to bind complete lambda for mapping and just mapping src.getTime() and that's why you are getting error so either you can have time field as long in your Source class or can move toMillis method inside Source class something like below -

    public class Source {
    private LocalDateTime time;
    
    public LocalDateTime getTime() {
        return time;
    }
    
    public void setTime(LocalDateTime time) {
        this.time = time;
    }
    
    public long toMillis() {
        if (time == null) {
            return 0;
        }
        ZonedDateTime zdt = ZonedDateTime.of(time, ZoneId.systemDefault());
        return zdt.toInstant().toEpochMilli();
    }
    }
    

    and then can change mapping code like below -

     mapper.typeMap(Source.class, Destination.class)
                .addMappings(map -> map.map(Source::toMillis, Destination::setTime));