Gradle scala class already defined with combined Java compilation - java

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 = []
}

Related

Gradle can not compile the code with the generated sources by annotationProcessor

How to make the gradle build/compile a project using generated source by annotationProcessor?
I have a project with 2 modules
app-annotation -> is a module that defines one annotation and a successor of the AbstractProcessor
app-api -> contains Entities with annotation from the previous module
The idea was to generate default CRUD Repositories and Services for each entity, also if it is needed have the possibility to extend some service.
The problem is, it generates all the needed java files (even Intellij Idea see those files) but as soon as I want to extend one of the services it fails while it is being compiled because as I understand at the moment of compiling my class there is not its superclass which is generated after.
If I do then recompile only my class then it is ok
Moreover, eclipse somehow compiles with no error at all, only when I build with Idea or gradlew build.
To fix it the solution below is used, but it looks not very nice
configurations {
preProcessAnnotation
}
def defaultSrcDir = "$projectDir/src/main/java"
def entitySources = "$projectDir/src/main/java/com/abcd/app/entity"
def generatedSources = "$buildDir/generated/sources/annotationProcessor/java/main"
def generatedOutputDir = file("$generatedSources")
// Explicitly run the annotation processor against the entities
task preProcessAnnotation (type: JavaCompile) {
source = entitySources
classpath = sourceSets.main.compileClasspath
destinationDirectory = generatedOutputDir
options.sourcepath = sourceSets.main.java.getSourceDirectories()
options.annotationProcessorPath = configurations.getByName("preProcessAnnotation")
options.compilerArgs << "-proc:only"
options.encoding = "ISO-8859-1"
}
// Explicitly specify the files to compile
compileJava {
dependsOn(clean)
dependsOn(preProcessAnnotation)
def files = []
fileTree(defaultSrcDir).visit { FileVisitDetails details ->
files << details.file.path
}
fileTree(generatedSources).visit { FileVisitDetails details ->
files << details.file.path
}
source = files
options.compilerArgs << "-Xlint:deprecation"
options.compilerArgs << "-Xlint:unchecked"
options.encoding = "ISO-8859-1"
}
....
dependencies {
preProcessAnnotation project(':app-annotation')
// Generate the crud repositories and services
compile project(':app-annotation')
implementation project(':app-annotation')
...
}
I am just curious how similar frameworks of code generation such as Lombok, Dagger2 work without any problem.
PS. I feel it should be much simpler, doesn't it?
Eventually, all it is my mistake, I used wrong method to save a generated java file.
// Wrong!
javax.annotation.processing.Filer#createResource(StandardLocation.SOURCE_OUTPUT, packageName, className + ".java")
// Correct
javax.annotation.processing.Filer#createSourceFile(packageName + "." + className)
As you realised - any code generation must be done before compile.
A cleaner approach is to have your code generation logic / annotation as dependency.
task codeGen {
// creates under build/genSrc
}
//add to default source set
sourceSets.main.java.srcDir "build/genSrc"
//this has access to all code
compile.dependsOn codeGen

Failed to apply plugin [id 'forge']

This is a continuation of this question My initial issue has been solved, but a new one came after.
Following the tutorial mentioned in it, having solved a few errors, I now get an error when I try to run .\gradlew tasks:
FAILURE: Build failed with an exception.
* Where:
Build file 'C:\Users\benji\MinecraftWorkspace\forge-1.7.10-10.13.4.1614-1.7.10-src\build.gradle' line: 18
* What went wrong:
A problem occurred evaluating root project 'forge-1.7.10-10.13.4.1614-1.7.10-src'.
> Failed to apply plugin [id 'forge']
> You must set the Minecraft Version!
> java.lang.NullPointerException (no error message)
How do I set the Minecraft version? (1.7.10 in this instance)
Edit to include build.gradle:
buildscript {
repositories {
mavenCentral()
maven {
name = "forge"
url = "http://files.minecraftforge.net/maven"
}
maven {
name = "sonatype"
url = "https://oss.sonatype.org/content/repositories/snapshots/"
}
}
dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:1.2-SNAPSHOT'
}
}
apply plugin: 'forge'
version = "1.0"
group= "com.yourname.modid" // http://maven.apache.org/guides/mini/guide-naming-conventions.html
archivesBaseName = "modid"
minecraft {
version = "1.7.10-10.13.4.1614-1.7.10"
runDir = "eclipse"
}
dependencies {
// you may put jars on which you depend on in ./libs
// or you may define them like so..
//compile "some.group:artifact:version:classifier"
//compile "some.group:artifact:version"
// real examples
//compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env
//compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env
// for more info...
// http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
// http://www.gradle.org/docs/current/userguide/dependency_management.html
}
processResources
{
// this will ensure that this task is redone when the versions change.
inputs.property "version", project.version
inputs.property "mcversion", project.minecraft.version
// replace stuff in mcmod.info, nothing else
from(sourceSets.main.resources.srcDirs) {
include 'mcmod.info'
// replace version and mcversion
expand 'version':project.version, 'mcversion':project.minecraft.version
}
// copy everything else, thats not the mcmod.info
from(sourceSets.main.resources.srcDirs) {
exclude 'mcmod.info'
}
}
Good day.
For minecraft version 1.7.10.
I was with the same problem, searching the forum in Japanese.
this link Forum
You have to modify the repositories and dependencies of the build.gradle and change the gradle-wrapper.properties to version 5.6.4.
As indicated in this link ForgeGradle-1.2
Contains an example to modify your build.gradle example
build.gradle
buildscript {
repositories {
mavenCentral()
maven { url = "https://jcenter.bintray.com/" }
maven {
name = "forge"
url = "https://files.minecraftforge.net/maven"
}
maven {
name = "sonatype"
url = "https://oss.sonatype.org/content/repositories/snapshots/"
}
}
dependencies {
classpath ('com.anatawa12.forge:ForgeGradle:1.2-1.0.+') {
changing = true
}
}
gradle-wrapper.properties
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-bin.zip
I made it work
Sorry, my English is very basic. I'm using a translator.
pls update the plugin to latest one . For reference check this link and link.
also try deleting the .gradle folder in your User Home and run it again.
I solved this by installing the 'Recommended' version of Forge 1.7.10 instead of the 'Latest'. Simple fix really, although I've already hit another wall.

Delombok'ing source code with added jar dependencies

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.

Include additional Sources for recompile in gwtSuperDev Task

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')
...
}

How to set Gradle `options.bootClasspath` in an os independent manner?

Because my Java sources and targets must be JRE 1.6 compatible, I need to set options.bootClasspath to a path that contains the 1.6 versions of rt.jar and jce.jar. It must build on both Windows and Unix (Linux/Solaris). What is the proper way to do this? I now use the following approach in my top-level build.gradle, it works, but it seems far from elegant, especially the os-dependent separator : or ;:
import org.apache.tools.ant.taskdefs.condition.Os
subprojects {
apply plugin: 'java'
compileJava {
sourceCompatibility = 1.6
targetCompatibility = 1.6
def java6_home = System.getenv("JAVA_HOME_6")
def java6_lib = "C:/localdata/Program Files (x86)/Java/jdk1.6.0_45/jre/lib/"
if (java6_home != null) {
java6_lib = java6_home + "/jre/lib/"
}
def sep = ':'
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
sep = ';'
}
options.bootClasspath = java6_lib + "rt.jar" + sep + java6_lib + "jce.jar"
}
}
I am using the following code (assuming the JDK6_HOME points to the root of the JDK 1.6 installation):
tasks.withType(JavaCompile) {
doFirst {
if (sourceCompatibility == '1.6' && System.env.JDK6_HOME != null) {
options.fork = true
options.bootClasspath = "$System.env.JDK6_HOME/jre/lib/rt.jar"
options.bootClasspath += "$File.pathSeparator$System.env.JDK6_HOME/jre/lib/jsse.jar"
// use the line above as an example to add jce.jar
// and other specific JDK jars
}
}
}
This approach automatically detects the presence of the environment variable and automatically sets the bootClasspath for all modules that declare sourceCompatibility as 1.6.
The options.fork = true is required when you use bootClasspath.
The accepted answer can work, but if you're using some classes outside java.lang (e.g. javax.crypto.*) you may find you'll get various ClassNotFoundExceptionException's being raised as more JAR files need to be added to the bootClasspath.
To avoid this, I use the following which has the following advantages;
The options are only set if required
All the JAR files are added to the bootClasspath
The extensionDirs is also set (see http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javac.html#extdirs-option)
.
tasks.withType(JavaCompile) {
doFirst {
if (JavaVersion.toVersion(sourceCompatibility) == JavaVersion.VERSION_1_6
&& JavaVersion.current() != JavaVersion.VERSION_1_6
&& System.env.JDK6_HOME != null) {
options.fork = true
options.bootClasspath = fileTree(include: ['*.jar'], dir: "$System.env.JDK6_HOME/jre/lib/").join(File.pathSeparator)
options.extensionDirs = "$System.env.JDK6_HOME/jre/lib/ext/"
}
}
}
Since Gradle 4.3 you can use CompileOptions.bootstrapClasspath instead to remove the need for an OS-dependent separator.
A slight modification of the cool solution by Oleg Estekhin above, but doesn't require JDKX_HOME to be set (calculates it on the fly.) Also, modified for doing Java 1.7 builds:
tasks.withType(JavaCompile) {
doFirst {
if (sourceCompatibility == '1.7') {
def JDK7_HOME = "/usr/libexec/java_home -v 1.7".execute().text.trim()
options.bootClasspath = "$JDK7_HOME/jre/lib/rt.jar"
options.bootClasspath += "$File.pathSeparator$JDK7_HOME/jre/lib/jsse.jar"
// use the line above as an example to add jce.jar
// and other specific JDK jars
}
}
}
I tried to add many jars to my bootClassPath using the instructions above, but never resolved my build issue. I finally resolved the build by setting my JAVA_HOME to point to the IBM JDK 1.7 required by the WebSphere server and adding it to my path. My other projects require Oracle JDK 1.8 so I did not want to make this change permanent.
set JAVA_HOME="C:\Program Files (x86)\IBM\WebSphere\AppServer\java_1.7.1_64\"
set PATH=%JAVA_HOME%\bin;%PATH%
gradle clean war
gradle clean ear deployLocal

Categories

Resources