spring boot升级到2.0.0.M7后报错ConverterNotFoundException for java.time.Duration的解决方案

最近学习搭建spring boot的脚手架过程中,boot的版本升级成了2.0.0.M7,然后发现项目启动之后redis配置那块报了错。错误信息如下

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'spring.redis-org.springframework.boot.autoconfigure.data.redis.RedisProperties': Could not bind properties to 'RedisProperties': prefix=spring.redis, ignoreInvalidFields=false, ignoreUnknownFields=true; nested exception is org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'spring.redis.jedis.pool.max-wait' to java.time.Duration
    at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.postProcessBeforeInitialization(ConfigurationPropertiesBindingPostProcessor.java:170)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:423)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1702)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:583)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:502)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:312)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:310)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:251)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1135)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1062)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:815)
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:721)
    ... 42 more
Caused by: org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'spring.redis.jedis.pool.max-wait' to java.time.Duration
    at org.springframework.boot.context.properties.bind.Binder.handleBindError(Binder.java:227)
    at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:203)
    at org.springframework.boot.context.properties.bind.Binder.lambda$bindBean$4(Binder.java:313)
    at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:70)
    at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:59)
    at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:51)
    at org.springframework.boot.context.properties.bind.Binder.lambda$null$5(Binder.java:321)
    at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
    at java.util.ArrayList$ArrayListSpliterator.tryAdvance(ArrayList.java:1351)
    at java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:126)
    at java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:498)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:485)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
    at java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:152)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:464)
    at org.springframework.boot.context.properties.bind.Binder.lambda$bindBean$6(Binder.java:322)
    at org.springframework.boot.context.properties.bind.Binder$Context.withIncreasedDepth(Binder.java:415)
    at org.springframework.boot.context.properties.bind.Binder$Context.withBean(Binder.java:405)
    at org.springframework.boot.context.properties.bind.Binder.bindBean(Binder.java:319)
    at org.springframework.boot.context.properties.bind.Binder.bindObject(Binder.java:261)
    at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:198)
    at org.springframework.boot.context.properties.bind.Binder.lambda$bindBean$4(Binder.java:313)
    at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:70)
    at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:59)
    at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:51)
    at org.springframework.boot.context.properties.bind.Binder.lambda$null$5(Binder.java:321)
    at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
    at java.util.ArrayList$ArrayListSpliterator.tryAdvance(ArrayList.java:1351)
    at java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:126)
    at java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:498)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:485)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
    at java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:152)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:464)
    at org.springframework.boot.context.properties.bind.Binder.lambda$bindBean$6(Binder.java:322)
    at org.springframework.boot.context.properties.bind.Binder$Context.withIncreasedDepth(Binder.java:415)
    at org.springframework.boot.context.properties.bind.Binder$Context.withBean(Binder.java:405)
    at org.springframework.boot.context.properties.bind.Binder.bindBean(Binder.java:319)
    at org.springframework.boot.context.properties.bind.Binder.bindObject(Binder.java:261)
    at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:198)
    at org.springframework.boot.context.properties.bind.Binder.lambda$bindBean$4(Binder.java:313)
    at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:70)
    at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:59)
    at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:51)
    at org.springframework.boot.context.properties.bind.Binder.lambda$null$5(Binder.java:321)
    at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
    at java.util.ArrayList$ArrayListSpliterator.tryAdvance(ArrayList.java:1351)
    at java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:126)
    at java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:498)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:485)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
    at java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:152)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:464)
    at org.springframework.boot.context.properties.bind.Binder.lambda$bindBean$6(Binder.java:322)
    at org.springframework.boot.context.properties.bind.Binder$Context.withIncreasedDepth(Binder.java:415)
    at org.springframework.boot.context.properties.bind.Binder$Context.withBean(Binder.java:405)
    at org.springframework.boot.context.properties.bind.Binder.bindBean(Binder.java:319)
    at org.springframework.boot.context.properties.bind.Binder.bindObject(Binder.java:261)
    at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:198)
    at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:187)
    at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:169)
    at org.springframework.boot.context.properties.ConfigurationPropertiesBinder.bind(ConfigurationPropertiesBinder.java:77)
    at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.postProcessBeforeInitialization(ConfigurationPropertiesBindingPostProcessor.java:167)
    ... 55 more
Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.Integer] to type [java.time.Duration]
    at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:321)
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:194)
    at org.springframework.boot.context.properties.bind.convert.BinderConversionService.lambda$convert$1(BinderConversionService.java:77)
    at org.springframework.boot.context.properties.bind.convert.BinderConversionService.callConversionService(BinderConversionService.java:85)
    at org.springframework.boot.context.properties.bind.convert.BinderConversionService.convert(BinderConversionService.java:77)
    at org.springframework.boot.context.properties.bind.ResolvableTypeDescriptor.convert(ResolvableTypeDescriptor.java:64)
    at org.springframework.boot.context.properties.bind.Binder.convert(Binder.java:233)
    at org.springframework.boot.context.properties.bind.Binder.bindProperty(Binder.java:303)
    at org.springframework.boot.context.properties.bind.Binder.bindObject(Binder.java:249)
    at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:198)
    ... 119 more

核心错误即是ConverterNotFoundException: No converter found capable of converting from type [java.lang.Integer] to type [java.time.Duration]

通过一番查找后在spring boot的官方GitHub的一个issue中找到解答,该错误会出现在使用的是YAML配置,因为对于数值类型参数会强转为数值类型。这个问题是M7版本的一个bug。

解决方案是用双引号将参数值包装。

server:
  session:
    timeout: "60"