Hi,
My build is using the combination of a CopyTask along with property expansion using org.apache.tools.ant.filters.ReplaceTokens.
Gradle makes this work by casting a j.u.LinkedHashMap collection to a j.u.Hashtable. In the properties collection many of the values are null. As they reasonably can be.
But Gradle has a problem casting K,V pairs when the value is null.
I am seeing this stack trace.
whitingjr@f19lite GradleSampleNPEProject $ gradle expandProperties --stacktraceFAILURE: Build failed with an exception.
-
Where: Build file ‘/somewhereoverthefilesystem/GradleSampleNPEProject/build.gradle’ line: 4
-
What went wrong: A problem occurred evaluating root project ‘GradleSampleNPEProject’. > Could not copy file ‘/somewhereoverthefilesystem/GradleSampleNPEProject/build.gradle’ to ‘/somewhereoverthefilesystem/GradleSampleNPEProject/expanded.txt’.
-
Try: Run with --info or --debug option to get more log output.
-
Exception is: org.gradle.api.GradleScriptException: A problem occurred evaluating root project ‘GradleSampleNPEProject’.
at org.gradle.groovy.scripts.internal.DefaultScriptRunnerFactory$ScriptRunnerImpl.run(DefaultScriptRunnerFactory.java:54)
at org.gradle.configuration.DefaultScriptPluginFactory$ScriptPluginImpl.apply(DefaultScriptPluginFactory.java:132)
at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:38)
at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:25)
at org.gradle.configuration.project.ConfigureActionsProjectEvaluator.evaluate(ConfigureActionsProjectEvaluator.java:34)
at org.gradle.configuration.project.LifecycleProjectEvaluator.evaluate(LifecycleProjectEvaluator.java:55)
at org.gradle.api.internal.project.AbstractProject.evaluate(AbstractProject.java:507)
at org.gradle.api.internal.project.AbstractProject.evaluate(AbstractProject.java:82)
at org.gradle.configuration.DefaultBuildConfigurer.configure(DefaultBuildConfigurer.java:31)
at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:142)
at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:113)
at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:81)
at org.gradle.launcher.exec.InProcessBuildActionExecuter$DefaultBuildController.run(InProcessBuildActionExecuter.java:64)
at org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.java:33)
at org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.java:24)
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:35)
at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:45)
at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:34)
at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:125)
at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:42)
at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:125)
at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:24)
at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:125)
at org.gradle.launcher.daemon.server.exec.StartStopIfBuildAndStop.execute(StartStopIfBuildAndStop.java:33)
at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:125)
at org.gradle.launcher.daemon.server.exec.ReturnResult.execute(ReturnResult.java:34)
at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:125)
at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:71)
at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:69)
at org.gradle.util.Swapper.swap(Swapper.java:38)
at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:69)
at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:125)
at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:60)
at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:34)
at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:125)
at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:60)
at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:34)
at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:125)
at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:45)
at org.gradle.launcher.daemon.server.DaemonStateCoordinator.runCommand(DaemonStateCoordinator.java:186)
at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy.doBuild(StartBuildOrRespondWithBusy.java:49)
at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:34)
at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:125)
at org.gradle.launcher.daemon.server.exec.HandleStop.execute(HandleStop.java:36)
at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:125)
at org.gradle.launcher.daemon.server.exec.DaemonHygieneAction.execute(DaemonHygieneAction.java:36)
at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:125)
at org.gradle.launcher.daemon.server.exec.CatchAndForwardDaemonFailure.execute(CatchAndForwardDaemonFailure.java:32)
at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:125)
at org.gradle.launcher.daemon.server.exec.DefaultDaemonCommandExecuter.executeCommand(DefaultDaemonCommandExecuter.java:51)
at org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler$ConnectionWorker.handleCommand(DefaultIncomingConnectionHandler.java:155)
at org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler$ConnectionWorker.receiveAndHandleCommand(DefaultIncomingConnectionHandler.java:128)
at org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler$ConnectionWorker.run(DefaultIncomingConnectionHandler.java:116)
at org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:66) Caused by: org.gradle.api.GradleException: Could not copy file ‘/somewhereoverthefilesystem/GradleSampleNPEProject/build.gradle’ to ‘/somewhereoverthefilesystem/GradleSampleNPEProject/expanded.txt’.
at org.gradle.api.internal.file.AbstractFileTreeElement.copyTo(AbstractFileTreeElement.java:70)
at org.gradle.api.internal.file.copy.DefaultFileCopyDetails.copyTo(DefaultFileCopyDetails.java:104)
at org.gradle.api.internal.file.copy.FileCopyAction$FileCopyDetailsInternalAction.processFile(FileCopyAction.java:44)
at org.gradle.api.internal.file.copy.NormalizingCopyActionDecorator$1$1.processFile(NormalizingCopyActionDecorator.java:62)
at org.gradle.api.internal.file.copy.DuplicateHandlingCopyActionDecorator$1$1.processFile(DuplicateHandlingCopyActionDecorator.java:60)
at org.gradle.api.internal.file.copy.CopyFileVisitorImpl.processFile(CopyFileVisitorImpl.java:60)
at org.gradle.api.internal.file.copy.CopyFileVisitorImpl.visitFile(CopyFileVisitorImpl.java:44)
at org.gradle.api.internal.file.AbstractFileTree$FilteredFileTree$1.visitFile(AbstractFileTree.java:145)
at org.gradle.api.internal.file.collections.SingletonFileTree.visit(SingletonFileTree.java:40)
at org.gradle.api.internal.file.collections.FileTreeAdapter.visit(FileTreeAdapter.java:96)
at org.gradle.api.internal.file.AbstractFileTree$FilteredFileTree.visit(AbstractFileTree.java:136)
at org.gradle.api.internal.file.CompositeFileTree.visit(CompositeFileTree.java:54)
at org.gradle.api.internal.file.copy.CopySpecActionImpl.execute(CopySpecActionImpl.java:37)
at org.gradle.api.internal.file.copy.CopySpecActionImpl.execute(CopySpecActionImpl.java:24)
at org.gradle.api.internal.file.copy.DelegatingCopySpecInternal.walk(DelegatingCopySpecInternal.java:223)
at org.gradle.api.internal.file.copy.CopySpecBackedCopyActionProcessingStream.process(CopySpecBackedCopyActionProcessingStream.java:36)
at org.gradle.api.internal.file.copy.DuplicateHandlingCopyActionDecorator$1.process(DuplicateHandlingCopyActionDecorator.java:44)
at org.gradle.api.internal.file.copy.NormalizingCopyActionDecorator$1.process(NormalizingCopyActionDecorator.java:53)
at org.gradle.api.internal.file.copy.FileCopyAction.execute(FileCopyAction.java:35)
at org.gradle.api.internal.file.copy.NormalizingCopyActionDecorator.execute(NormalizingCopyActionDecorator.java:49)
at org.gradle.api.internal.file.copy.DuplicateHandlingCopyActionDecorator.execute(DuplicateHandlingCopyActionDecorator.java:42)
at org.gradle.api.internal.file.copy.CopyActionExecuter.execute(CopyActionExecuter.java:38)
at org.gradle.api.internal.file.copy.FileCopier.doCopy(FileCopier.java:63)
at org.gradle.api.internal.file.copy.FileCopier.copy(FileCopier.java:48)
at org.gradle.api.internal.file.DefaultFileOperations.copy(DefaultFileOperations.java:139)
at org.gradle.api.internal.project.AbstractProject.copy(AbstractProject.java:855)
at org.gradle.groovy.scripts.DefaultScript.copy(DefaultScript.java:157)
at build_fr8oct40gdh2gqnb373ms71h4$_run_closure1.doCall(/somewhereoverthefilesystem/GradleSampleNPEProject/build.gradle:4)
at org.gradle.api.internal.ClosureBackedAction.execute(ClosureBackedAction.java:58)
at org.gradle.util.ConfigureUtil.configure(ConfigureUtil.java:130)
at org.gradle.util.ConfigureUtil.configure(ConfigureUtil.java:110)
at org.gradle.api.internal.AbstractTask.configure(AbstractTask.java:436)
at org.gradle.api.internal.project.AbstractProject.task(AbstractProject.java:942)
at org.gradle.api.internal.BeanDynamicObject$MetaClassAdapter.invokeMethod(BeanDynamicObject.java:246)
at org.gradle.api.internal.BeanDynamicObject.invokeMethod(BeanDynamicObject.java:134)
at org.gradle.api.internal.CompositeDynamicObject.invokeMethod(CompositeDynamicObject.java:147)
at org.gradle.groovy.scripts.BasicScript.methodMissing(BasicScript.java:79)
at build_fr8oct40gdh2gqnb373ms71h4.run(/somewhereoverthefilesystem/GradleSampleNPEProject/build.gradle:3)
at org.gradle.groovy.scripts.internal.DefaultScriptRunnerFactory$ScriptRunnerImpl.run(DefaultScriptRunnerFactory.java:52)
… 53 more Caused by: org.gradle.api.InvalidUserDataException: Error - Invalid filter specification for org.apache.tools.ant.filters.ReplaceTokens
at org.gradle.api.internal.file.copy.FilterChain$1.transform(FilterChain.java:69)
at org.gradle.api.internal.file.copy.FilterChain$1.transform(FilterChain.java:58)
at org.gradle.api.internal.ChainingTransformer.transform(ChainingTransformer.java:37)
at org.gradle.api.internal.file.copy.FilterChain.transform(FilterChain.java:39)
at org.gradle.api.internal.file.copy.FilterChain.transform(FilterChain.java:46)
at org.gradle.api.internal.file.copy.DefaultFileCopyDetails.open(DefaultFileCopyDetails.java:88)
at org.gradle.api.internal.file.AbstractFileTreeElement.copyTo(AbstractFileTreeElement.java:47)
at org.gradle.api.internal.file.copy.DefaultFileCopyDetails.copyTo(DefaultFileCopyDetails.java:96)
at org.gradle.api.internal.file.AbstractFileTreeElement.copyFile(AbstractFileTreeElement.java:88)
at org.gradle.api.internal.file.AbstractFileTreeElement.copyTo(AbstractFileTreeElement.java:65)
… 91 more Caused by: org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object ‘{ACME=null}’ with class ‘java.util.LinkedHashMap’ to class ‘java.util.Hashtable’ due to: java.lang.NullPointerException
at org.gradle.api.internal.BeanDynamicObject$MetaClassAdapter.setProperty(BeanDynamicObject.java:192)
at org.gradle.api.internal.BeanDynamicObject.setProperty(BeanDynamicObject.java:117)
at org.gradle.util.ConfigureUtil.configureByMap(ConfigureUtil.java:40)
at org.gradle.api.internal.file.copy.FilterChain$1.transform(FilterChain.java:65)
… 100 more
BUILD FAILED
Total time: 2.003 secs whitingjr@f19lite GradleSampleNPEProject $
What’s the expected behaviour of Gradle ? In my opinion a Gradle should be tolerant of build projects using properties without a value.
Using a j.u.Hashtable in this situation has highlighted a problem that any project build using this combination of Copy and ReplaceTokens is very brittle. I am wondering if there is a better way.
To test this problem I created a reproducer. This is my sample build.gradle file.
import org.apache.tools.ant.filters.ReplaceTokens
task expandProperties {
copy {
from 'build.gradle'
into './'
rename {'expanded.txt'}
filter ( ReplaceTokens, tokens: [ ACME: ant.properties['duff.property']])
}
}
Regards, Jeremy
$ gradle --version
------------------------------------------------------------ Gradle 1.9 ------------------------------------------------------------
Build time:
2013-11-19 08:20:02 UTC Build number: none Revision:
7970ec3503b4f5767ee1c1c69f8b4186c4763e3d
Groovy:
1.8.6 Ant:
Apache Ant™ version 1.9.2 compiled on July 8 2013 Ivy:
2.2.0 JVM:
1.7.0_55 (Oracle Corporation 24.51-b03) OS:
Linux 3.14.7-100.fc19.x86_64 amd64 $ java -version java version “1.7.0_55” OpenJDK Runtime Environment (fedora-2.4.7.0.fc19-x86_64 u55-b13) OpenJDK 64-Bit Server VM (build 24.51-b03, mixed mode)