Apache Camel在Eclipse外运行时无法创建Route并抛出异常
我用Apache Camel开发了一个Java应用,根据文件所在子文件夹名称归档已排序的文件。应用在Eclipse中运行正常,但在Eclipse外启动时无法创建Route,抛出如下错误:
2023-08-07 13:20:03,527 [main] ERROR MyClass - Exception occured: org.apache.camel.FailedToCreateRouteException: Failed to create route route1 at: >>> Aggregate[LotName -> [SetHeader[CamelFileName, simple{${in.header.LotName}.zip}], Log[Finished Zipping: ${file:name}], DynamicTo[file:${in.header.CreatedPath}?fileName=${file:name.noext}-2023-08-07T13-20-03-328.${file:ext}&fileExist=Move&moveExisting=${file:name.noext}-1.${file:ext}]]] <<< in route: Route(route1)[From[EndpointA... because of Error parsing [1000] as a java.time.Duration. org.apache.camel.FailedToCreateRouteException: Failed to create route route1 at: >>> Aggregate[LotName -> [SetHeader[CamelFileName, simple{${in.header.LotName}.zip}], Log[Finished Zipping: ${file:name}], DynamicTo[file:${in.header.CreatedPath}?fileName=${file:name.noext}-2023-08-07T13-20-03-328.${file:ext}&fileExist=Move&moveExisting=${file:name.noext}-1.${file:ext}]]] <<< in route: Route(route1)[From[EndpointA because of Error parsing [1000] as a java.time.Duration. at org.apache.camel.reifier.RouteReifier.doCreateRoute(RouteReifier.java:241) at org.apache.camel.reifier.RouteReifier.createRoute(RouteReifier.java:75) at org.apache.camel.impl.DefaultModelReifierFactory.createRoute(DefaultModelReifierFactory.java:49) at org.apache.camel.impl.DefaultCamelContext.startRouteDefinitions(DefaultCamelContext.java:874) at org.apache.camel.impl.DefaultCamelContext.startRouteDefinitions(DefaultCamelContext.java:764) at org.apache.camel.impl.engine.AbstractCamelContext.doInit(AbstractCamelContext.java:2862) at org.apache.camel.support.service.BaseService.init(BaseService.java:83) at org.apache.camel.impl.engine.AbstractCamelContext.init(AbstractCamelContext.java:2568) at org.apache.camel.support.service.BaseService.start(BaseService.java:111) at org.apache.camel.impl.engine.AbstractCamelContext.start(AbstractCamelContext.java:2587) at org.apache.camel.impl.DefaultCamelContext.start(DefaultCamelContext.java:253) at org.apache.camel.main.Main.doStart(Main.java:116) at org.apache.camel.support.service.BaseService.start(BaseService.java:119) at org.apache.camel.main.MainSupport.run(MainSupport.java:69) at MyClass.main(MyClass.java:80) Caused by: java.lang.IllegalArgumentException: Error parsing [1000] as a java.time.Duration. at org.apache.camel.support.CamelContextHelper.parse(CamelContextHelper.java:556) at org.apache.camel.support.CamelContextHelper.parseDuration(CamelContextHelper.java:500) at org.apache.camel.reifier.AbstractReifier.parseDuration(AbstractReifier.java:78) at org.apache.camel.reifier.AggregateReifier.createAggregator(AggregateReifier.java:203) at org.apache.camel.reifier.AggregateReifier.createProcessor(AggregateReifier.java:54) at org.apache.camel.reifier.ProcessorReifier.makeProcessor(ProcessorReifier.java:838) at org.apache.camel.reifier.ProcessorReifier.addRoutes(ProcessorReifier.java:579) at org.apache.camel.reifier.RouteReifier.doCreateRoute(RouteReifier.java:237) ... 14 more Caused by: org.apache.camel.NoTypeConversionAvailableException: No type converter available to convert from type: java.lang.String to the required type: java.time.Duration with value 1000 at org.apache.camel.impl.converter.CoreTypeConverterRegistry.mandatoryConvertTo(CoreTypeConverterRegistry.java:275) at org.apache.camel.impl.converter.CoreTypeConverterRegistry.mandatoryConvertTo(CoreTypeConverterRegistry.java:207) at org.apache.camel.support.CamelContextHelper.parse(CamelContextHelper.java:553) ... 21 more
不清楚这个值为1000的Duration对象来源、用途。我的Route代码如下:
public void configure() throws Exception { /* Takes files from origin folder, checks for valid file names and deletes files in their source folders */ from(FILECOMPONENT + sourceFolder + "?recursive=true&include=RAW("+ lotFileRegex +")&delete=true") .log(LoggingLevel.INFO, "Starting to process file: ${file:name}") // Extract our criteria to aggregate .process(new SubfolderExtractor()) // Aggregate Files based on Header "LotName" .log(LoggingLevel.INFO, "Currently aggregating: ${in.header.LotName}") .aggregate(header("LotName"), new ZipAggregationStrategy()) .completionFromBatchConsumer().eagerCheckCompletion() .completionOnNewCorrelationGroup() // finish our archive when the subfolder is empty // Set Header FILE_NAME to LotName.zip .setHeader(Exchange.FILE_NAME, simple("${in.header.LotName}.zip")) .log(LoggingLevel.INFO, "Finished Zipping: ${file:name}") /* Drop Zip-Archives in same location as their origin, add the current date to make it unique */ .toD(FILECOMPONENT + "${in.header.CreatedPath}?fileName=${file:name.noext}-"+LocalDateTime.now().toString().replace(':', '-').replace('.', '-')+".${file:ext}&fileExist=Move&moveExisting=${file:name.noext}-1.${file:ext}"); }
曾以为是Simple语言表达式问题,把.toD()里的表达式换成原生Java代码,但问题依旧。使用Java 8、Camel 3.14.7,通过Camel的Main类启动路由。
1. 问题根源
报错中的1000是Camel Aggregate组件的默认completionTimeout值(单位毫秒),但Java 8本身没有自动注册java.time.Duration的类型转换器。Eclipse运行时可能因IDE类加载机制自动引入了相关依赖,而外部运行时缺少对应的类型转换器模块。
Camel 3.x中,java.time相关的类型转换器属于camel-core-java8模块,若未显式引入该依赖,外部运行时就会缺失Duration的转换能力。
2. 修复步骤
添加依赖:确保构建文件(Maven/Gradle)中包含
camel-core-java8依赖:
Maven:<dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-core-java8</artifactId> <version>3.14.7</version> </dependency>Gradle:
implementation 'org.apache.camel:camel-core-java8:3.14.7'显式指定completionTimeout(可选):若不想依赖额外模块,可在aggregate组件中显式设置
completionTimeout为带单位的合法Duration格式(如1000ms),避免Camel使用默认数值型字符串触发转换:.aggregate(header("LotName"), new ZipAggregationStrategy()) .completionTimeout("1000ms") // 显式指定带单位的Duration字符串 .completionFromBatchConsumer().eagerCheckCompletion() .completionOnNewCorrelationGroup()
3. 为什么Eclipse中正常?
Eclipse的类路径可能自动包含了camel-core-java8依赖(比如通过Maven依赖管理自动引入),或IDE类加载机制隐式加载了相关转换器;而外部打包(如jar包)时若未包含该依赖,就会出现缺失。
内容的提问来源于stack exchange,提问作者Krubsacius

