The default scala plugin task flow compiles Java before Scala so importing Scala sources within Java causes "error: cannot find symbol".
Java and Scala can be combined in the scala sources to have them compiled jointly, e.g.
sourceSets {
main {
scala {
srcDirs = ['src/main/scala', 'src/main/java']
}
java {
srcDirs = []
}
}
If your java code use some external libraries like Lombok, using scala compiler to build java class will failed, as scala compiler don't know annotations.
My solution is to change the task dependencies, make compiling Scala before Java.
tasks.compileJava.dependsOn compileScala
tasks.compileScala.dependsOn.remove("compileJava")
Now the task compileScala runs before compileJava, that's it.
If your java code depends on scala code, you need to do two more steps,
Separate the output folder of scala and java,
sourceSets {
main {
scala {
outputDir = file("$buildDir/classes/scala/main")
}
java {
outputDir = file("$buildDir/classes/java/main")
}
}
Add the scala output as a dependency for compileJava,
dependencies {
compile files("$sourceSets.main.scala.outputDir")
}
for gradle kotlin dsl you can use this piece
sourceSets {
main {
withConvention(ScalaSourceSet::class) {
scala {
setSrcDirs(listOf("src/main/scala", "src/main/java"))
}
}
java {
setSrcDirs(emptyList<String>())
}
}
test {
withConvention(ScalaSourceSet::class) {
scala {
setSrcDirs(listOf("src/test/scala", "src/test/java"))
}
}
java {
setSrcDirs(emptyList<String>())
}
}
}
Posting this update from the future here, as it would saved me a day.
gradle 6 doesn't support task dependencies modification, but here is what you can do:
// to compile Java after Scala
tasks.compileScala.classpath = sourceSets.main.compileClasspath
tasks.compileJava.classpath += files(sourceSets.main.scala.classesDirectory)
And here is documentation.
Related
I am trying to set the verbose flag/option to true in the gradle build script (Kotlin DSL).
Gradle throws error that this property is private and not accessible in Kotlin DSL. The same thing works in Groovy DSL though.
Groovy DSL (working)
plugins {
id("java")
}
tasks.named("compileJava") {
options.verbose = true
}
Kotlin DSL (not-working)
plugins {
id("java")
}
tasks.named<JavaCompile>("compileJava") {
options.verbose = true
}
Error
Script compilation error:
Line 32: options.verbose = true;
^ Cannot access 'verbose': it is private in 'CompileOptions'
1 error
I am sure I am missing something. Any help is appreciated. Thanks.
CompileOptions has a setter for verbose, so this will work
tasks.named<JavaCompile>("compileJava") {
options.setVerbose(true)
}
It is also possible to set the flag via property:
tasks.named<JavaCompile>("compileJava") {
options.isVerbose = true
}
Not sure why it is private for Kotlin DSL and not for Groovy DSL, but found an alternative using compilerArgs from this stackoverflow post
tasks.named<JavaCompile>("compileJava") {
val compilerArgs = options.compilerArgs
compilerArgs.add("-verbose")
}
This, to me, feels a bit low-level since we are directly updating the compiler arguments instead of using objects/maps to set them. Will wait for someone to post a better solution (if it exists).
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 have a project in which I have two different 'sub-projects', the main library and a compiler for a programming language in a directory structure like this:
- build.gradle
- src
- library
- compiler
- ...
My build.gradle looks like this:
sourceSets
{
library
{
java
{
srcDir 'src/library'
srcDir 'src/asm'
}
}
compiler
{
java
{
srcDir 'src/compiler'
}
}
//...
}
// ...
task buildLib(type: Jar, dependsOn: 'classes') {
from sourceSets.library.output
classifier = 'dyvil-library'
}
task buildCompiler(type: Jar, dependsOn: 'classes') {
from sourceSets.compiler.output
classifier = 'dyvil-compiler'
}
My problem is that whenever I try to run the buildCompiler task, the build fails and the Java Compiler gives me hundreds of errors in places where the compiler source code references classes in the library. I already tried to make the compiler dependant on the library classes like this:
task buildCompiler(type: Jar, dependsOn: [ 'classes', 'libraryClasses' ]) {
from sourceSets.compiler.output
classifier = 'dyvil-compiler'
}
But that did not help. I know that I could theoretically copy the srcDirs from sourceSets.library into sourceSets.compiler like this:
compiler
{
java
{
srcDir 'src/library'
srcDir 'src/asm'
srcDir 'src/compiler'
}
}
But that seems like a bad idea for obvious reasons.
Is there another way to include the source files from the library when compiling the compiler (duh)?
There's a similar question on SO here.
I replicated your situation locally and the fix was to add a line to the sourceSets for compiler as follows:
compiler
{
java {
srcDir 'src/compiler'
}
compileClasspath += library.output
}
I use the GWT Gradle Plugin. I have a second project which I included in my main project with:
dependencies {
compile(project(':core-project')) {
transitive = false
}
}
I have also created a settings.gradle which contains
includeFlat 'core-project'
The core-project is a library project. When I run gradle gwtSuperDev and change files in my main project recompile takes place but not if I change files in my core-project.
How can I make that the core-project sources are also recompiled in SuperDevMode when they have changed?
Depending on how your gradle dependencies are organized, you can simply add their source-files to the gwt section of your build.gradle file.
I have something like this in my build file:
gwt {
gwtVersion = '2.7.0'
if (System.getProperty('devmode') != null) {
modules = ['dk.logiva.invoice.autoaccount.gwt.AutoAccountAdminDev']
compiler {
style = 'PRETTY';
strict = true;
}
// include sources from inherited module
src += project(':invoice:gwt:gwt-common').files('src/main/java')
} else {
modules = ['dk.logiva.invoice.autoaccount.gwt.AutoAccountAdmin']
}
devWar = file("${buildDir}/war")
maxHeapSize = "3G"
}
...
dependencies {
compile project(':invoice:gwt:gwt-common')
...
}
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 = []
}