I am trying to get a JavaCC plugin working properly with Gradle. The plugin generates .java files correctly, but then during the compileJavaC task it crashes and burns with cannot find symbol errors. My JavaCC .jj file contains code that references other java files that are not generated, and I am guessing that the compileJava task tries to compile the generated code without providing a reference to the non-generated code.
Here is a minimum breaking example. build.gradle:
apply plugin: 'java'
//compile .jj file in src/main/javacc
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath group: 'ca.coglinc', name: 'javacc-gradle-plugin', version: '1.0.0'
}
}
apply plugin: 'javacc'
src/main/MyClass.java:
public class MyClass {
public MyClass(){
}
}
and src/main/javacc/MyParser.jj:
options
{}
PARSER_BEGIN(MyParser)
import java.util.*;
public class MyParser {
public static void main(String[] args) throws ParseException {
MyClass mc = new MyClass();
}
}
PARSER_END(MyParser)
SKIP:
{
" "
}
TOKEN:
{
<ANYTHING: ~[]>
}
void production():
{}
{
(<ANYTHING>)+
}
Running gradle build gives the following:
gradle build
:compileJavacc
Java Compiler Compiler Version 5.0 (Parser Generator)
(type "javacc" with no arguments for help)
Reading from file C:\Users\Nate Glenn\Desktop\java_workspace\test-gradle-javacc\
src\main\javacc\MyParser.jj . . .
File "TokenMgrError.java" does not exist. Will create one.
File "ParseException.java" does not exist. Will create one.
File "Token.java" does not exist. Will create one.
File "SimpleCharStream.java" does not exist. Will create one.
Parser generated successfully.
:compileJavaC:\Users\Nate Glenn\Desktop\java_workspace\test-gradle-javacc\build\
generated\javacc\MyParser.java:5: error: cannot find symbol
MyClass mc = new MyClass();
^
symbol: class MyClass
location: class MyParser
C:\Users\Nate Glenn\Desktop\java_workspace\test-gradle-javacc\build\generated\ja
vacc\MyParser.java:5: error: cannot find symbol
MyClass mc = new MyClass();
^
symbol: class MyClass
location: class MyParser
2 errors
FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':compileJava'.
> Compilation failed; see the compiler error output for details.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug
option to get more log output.
BUILD FAILED
Total time: 9.002 secs
How can I fix my Gradle build file so that javaCompileC correctly includes non-generated files when compiling the generated files?
Your source tree for MyClass is incorrect. It should be src/main/java/MyClass.java. In gradle, just like maven, convention is that java files by default are in src/main/java, and since you're not overriding this in your build.gradle file, I assume this is just an error on your part. The plugin correctly adds the JavaCC output path to the compileJava task's classpath, so if you create your java classes in the correct path for the compileJava task, everything should be fine :)
Just tried your example this way and it works.
By the way, thanks for your contribution to the plugin.
Just some additional FYI, if you would like to overwrite the compile path, here is how you would do it:
//customized source sets to over-write the default src/main/java path
sourceSets {
main{
java {
srcDir 'Java Source'
}
resources {
srcDir 'resources'
}
}
test {
java {
srcDir 'tests'
}
}
}
Related
I am unable to delombok my Java source code, apparently due to jar dependencies that the project has, and I don't understand why. There are two jar files that have to be committed to the repo to tag along, and they are added to the project in the dependencies node of the build.gradle file by adding the line compile files('myproj1.jar'). So, the relevant part of the build.gradle file looks like this:
dependencies {
compile files('myproj1.jar')
compile files('myproj2.jar')
.....
}
When I run the delombok task I get the following error:
Execution failed for task ':delombok'.
> taskdef class lombok.delombok.ant.Tasks$Delombok cannot be found
using the classloader AntClassLoader[/path/to/repo/myproj1.jar:/path/to/repo/myproj2.jar]
Why would delombok task be using the AntClassLoader from the jar files?
I have tried the delombok'ing code from this post
Here is the task from my build.gradle file
def srcJava = 'src/main/java'
def srcDelomboked = 'build/src-delomboked'
task delombok {
// delombok task may depend on other projects already being compiled
dependsOn configurations.compile.getTaskDependencyFromProjectDependency(true, "compileJava")
// Set up incremental build, must be made in the configuration phase (not doLast)
inputs.files file(srcJava)
outputs.dir file(srcDelomboked)
doLast {
FileCollection collection = files(configurations.compile)
FileCollection sumTree = collection + fileTree(dir: 'bin')
ant.taskdef(name: 'delombok', classname: 'lombok.delombok.ant.Tasks$Delombok', classpath: configurations.compile.asPath)
ant.delombok(from:srcJava, to:srcDelomboked, classpath: sumTree.asPath)
}
}
I expect to be able to delombok my Java source code as part of the build process so that when the project is compiled there are no dependencies on Lombok.
So after continued trial an error, I have a working implementation. To answer my own question, the problem has nothing to do with the additional Jar files. Rather, when gradle runs the delombok task, the classes in the lombok jar are not in the classpath of the org.gradle.api.AntBuilder (ie, the ant task), and so it does not have a reference to lombok.delombok.ant.Tasks$Delombok anywhere (which seems obvious at this point, but not at the time).
The solution thus far has been to add those references in from configurations.compile
Combining code snippits from this post and this post you can do it with something like this:
def srcDelomboked = 'build/src-delomboked'
task delombok {
description 'Delomboks the entire source code tree'
def srcJava = 'src/main/java'
inputs.files files( srcJava )
outputs.dir file( srcDelomboked )
doFirst {
ClassLoader antClassLoader = org.apache.tools.ant.Project.class.classLoader
def collection = files( configurations.compile + configurations.testCompile )
def sumTree = collection + fileTree( dir: 'bin' )
sumTree.forEach { File file ->
antClassLoader.addURL(file.toURI().toURL())
}
ant.taskdef( name: 'delombok', classname: 'lombok.delombok.ant.Tasks$Delombok',
classpath: configurations.compile.asPath + configurations.testCompile.asPath )
ant.delombok( from: srcJava, to: srcDelomboked, classpath: sumTree.asPath )
}
}
sourceSets {
main {
java { srcDirs = [ srcDelomboked ] } //blow away the old source sets so that we only use the delomboked source sets
}
test {
java { srcDirs += [ srcDelomboked ] } //but add those new source sets to the tests so that their references are available at test time
}
}
compileJava.dependsOn(delombok)
bootJar {
mainClassName = 'com.myproj.MyMainClass' // you will need this if its a Spring Boot project
}
Hope this helps whomever else needs to delombok their code.
i have a Question about XText/Maven.
I have a XText/Maven/Java Project.
In this Project lie the Xtext Models and Java source Files.
Some of the Modelfiles reference some Java files. E.G.:
Model:
package a.b.c
import java.util.List
import x.y.z.MyClass // <-- This is one of the Javafile in the same Project
dto MyModel
{
MyClass myClass
}
Java:
package x.y.z;
public class MyClass
{
String foo;
String bar;
}
Structure:
project
|
|----src/main
|
|---/java/x/y/z/MyClass.java
|
|---/model/a/b/c/MyModel.dto
|
|---/gen/a/b/c/MyModel.java <-- here goes the generated Javafile from the Model
I have already managed to write an Xtext/Eclipse plugin, so the Eclipse build generate my Modelfiles and compiles the Javafiles just fine.
But now i try to build the Project with Maven. I Manage already accomplished the Generate process via an mwe2 Workflow with use of the Class
org.eclipse.emf.mwe2.launch.runtime.MWE2Launcher
and other Modelfiles genrate just fine, but the MyModel references a Java Class that is not yet Compiled and so it is not Found:
[ERROR] Execution Failed: Problems running workflow my.company.model.xtext.domainmodel.generator: Validation problems:
[ERROR] 49 errors:
[ERROR] MyModel.dto - <path>/model/a/b/c/MyModel.dto
[ERROR] 4: x.y.z.MyClass cannot be resolved to a type.
...
So the Error itself is clear. I tryed with sucess to Precompile the Java File first and add these to the Classpath. But i have dozen of this Problems and i hope the is a better way to tell Xtext/Mwe2Launcher that it should reference the requierd Java Files. Because in some magic way it already work in Eclipse but i have no Idea how.
I have the same problem. But I use Gradle instead of Maven. However it may be still useful for someone:
task precompile(type: JavaCompile) {
source = 'src/main/java'
classpath = sourceSets.main.compileClasspath
destinationDir = sourceSets.main.java.outputDir
}
task generateXtextLanguage(type: JavaExec) {
dependsOn precompile
main = 'org.eclipse.emf.mwe2.launch.runtime.Mwe2Launcher'
args += "src/main/mwe2/...your_path_here.../generate.mwe2"
classpath = layout.files(configurations.mwe2, sourceSets.main.java.outputDir)
inputs.file 'src/main/mwe2/...your_path_here.../generate.mwe2'
inputs.dir 'src/main/xcore'
outputs.dir 'target/generated-sources/xtext-gen'
}
I added precompile task. generateXtextLanguage dependsOn it. Also I added precompiled classes to a classpath.
I'm trying to work out how I get a Groovy test script to import a Java class during the testing phase ...
Specifically I want to use JavaFXThreadingRule: .java file from here (or rather here and so included in my Java test source path) and then import it in my Groovy test script to use as an annotation.
The Groovy test script path is src\test\ft\groovy\core\testscript.groovy.
The .java file is src\test\ft\java\core\JavaFXThreadingRule.java.
The package line I've used in both is "package core;"
My "sourceSets" clause in build.gradle looks like this:
sourceSets {
main {
java {
srcDirs = ['src/main/java']
}
}
test {
java {
srcDirs = ['src/test/ft/java' ]
}
groovy {
srcDirs = ['src/test/ft/groovy', 'src/test/ut/groovy']
}
}
}
Interestingly the build.gradle output shows that the compileTestJava task is run before the compileTestGroovy task ... and yet I get
unable to resolve class core.JavaFXThreadingRule # line 18, column 1.
import core.JavaFXThreadingRule ^
NB I also tried "import JavaFXThreadingRule" - same result.
In addition to just wanting to resolve the problem I'm also wondering how Gradle decides what order to do the tasks compileTestJava and compileTestGroovy... and whether I shouldn't perhaps make my compileTestGroovy explicitly dependent on compileTestJava...
Thanks to Tim Yates I found the "workaround" of putting this Java file in with the Groovy ones... but this answer gave me another clue, and I then changed my build.gradle to be like this:
sourceSets {
main {
java {
srcDirs = ['src/main/java']
}
}
test {
groovy {
srcDirs = ['src/test/ft/groovy', 'src/test/ut/groovy', 'src/test/ft/java' ]
}
}
}
... works ... no doubt obvious to old Gradle hands.
That question and answer referenced above were talking about the app code classes (and Gradle tasks). Unless some Gradle expert can say otherwise I'm assuming that the Groovy test compile task and Java test compile task are completely separate and can't "see" one another's classes...
I try to pass arguments from command line to gradle.
My build.gradle is:
task execute(type:JavaExec) {
main = mainClass
classpath = sourceSets.main.output
}
When I do:
gradle -PmainClass=Hello execute
I get this:
FAILURE: Build failed with an exception.
* Where:
Build file '/home/example2/build.gradle' line: 7
* What went wrong:
A problem occurred evaluating root project 'example2'.
> Could not find property 'sourceSets' on task ':execute'.
My question is that what should I provide for main? name of any java file package? any specific path? What should actually be sourceSet?
Your minimal build.gradle file should look like this:
apply plugin: 'java'
task execute(type:JavaExec) {
main = mainClass
classpath = sourceSets.main.output
}
And you need a java class located in src/main/java/Hello.java like this:
public class Hello {
public static void main(String[] a) {}
}
I have the following scala compilation issue
scala -> depends upon java source
java source -> depends upon scala source
My scala code is in src/main/scala
My java code is in src/main/java
I cant change this code so I need to compile this with gradle and it currently compiles with JRuby just fine.
I have read the following posts on how to solve this issue:
http://forums.gradle.org/gradle/topics/how_to_compile_a_java_class_that_depends_on_a_scala_class_in_gradle
http://forums.gradle.org/gradle/topics/how_to_compile_a_java_class_that_depends_on_a_scala_class_in_gradle
I added this to my build:
ext {
baseName = 'd2'
description = 'Divisional IVR.'
combinedSources = "$buildDir/combined-sources"
}
apply plugin: 'scala'
compileScala.taskDependencies.values = compileScala.taskDependencies.values - 'compileJava'
compileJava.dependsOn compileScala
sourceSets.main.scala.srcDir "$combinedSources"
sourceSets.main.java.srcDirs = []
I tried to copy all the scala and java files to one location:
compileScala.dependsOn{
copyAllSourceFiles
}
task copyAllSourceFiles(type:Copy) {
description = 'Copy All Source Files.'
from('src/main/java') {}
from('/src/main/scala') {}
into combinedSources
includeEmptyDirs = false
}
But now I get an error:
[ant:scalac] Compiling 18 source files to C:\usr\git_workspaces\xivr\d2\target\classes\main
[ant:scalac] Compiling 18 scala and 196 java source files to C:\usr\git_workspaces\xivr\d2\target\classes\main
[ant:scalac] C:\usr\git_workspaces\xivr\d2\target\combined-sources\com\comcast\ivr\d2\actors\AlternateAniWithAccountActor.scala:9: error: AlternateAniWithAccountActor is already defined as class AlternateAniWithAccountActor
It almsot seems like scalaCompile sees $combinedSources and 'src/main/scala'
It almsot seems like scalaCompile sees $combinedSources and 'src/main/scala'
That's how you configured it: src/main/scala is the default, and you added "$combinedSources". To override the default, use sourceSets.main.scala.srcDirs = [combinedSources].
In any case, you don't have to (and shouldn't) copy sources around. Here is one solution that neither requires copying nor reconfiguring of task dependencies:
sourceSets.main.scala.srcDir "src/main/java"
sourceSets.main.java.srcDirs = []
Now, your Java and Scala code will get joint-compiled, and can depend on each other arbitrarily.
PS: Instead of "$combinedSources", use combinedSources.
gradle.properties
theVersion=2.1
theSourceCompatibility=1.7
theScalaVersion=2.10.3
build.gradle
apply {
plugin 'scala'
plugin 'java'
plugin 'idea'
}
ext {
scalaVersion = theScalaVersion
}
sourceCompatibility = theSourceCompatibility
tasks.withType(ScalaCompile) {
scalaCompileOptions.useAnt = false
}
dependencies {
compile "org.scala-lang:scala-library:$theScalaVersion"
compile "org.scala-lang:scala-compiler:$theScalaVersion"
}
sourceSets {
main.scala.srcDirs = ["src/main/scala", "src/main/java"]
main.java.srcDirs = []
}