I have a simple use case of building an OSGi bundle using Gradle build tool. The build is successful if there are java files present in the build path, but it fails otherwise.
I am using 'osgi' plugin inside the gradle script and trying to build without any java files. The build always fails with following error:
Could not copy MANIFEST.MF to
I am sure there must be some way to do it in Gradle but not able to fine. Any idea what can be done to resolve this depending on your experience.
I ran into this today as well, and #Peter's fix didn't work for me (I hadn't applied the java plugin in the first place...). However, after hours of Googling I did find this thread, which helped me find the problem.
Basically, it seems that the error occurs (as Peter stated) when no class files are found in the jar - my guess is because the plugin then cannot scan the classes for package names on which to base all the Import and Export information.
My solution was to add the following to the manifest specification:
classesDir = theSourceSet.output.classesDir
classpath = theSourceSet.runtimeClasspath
In my actual build code, I loop over all source sets to create jar tasks for them, so then it looks like this:
sourceSets.each { ss ->
assemble.dependsOn task("jar${ss.name.capitalize()}", type: Jar, dependsOn: ss.getCompileTaskName('Java')) {
from ss.output
into 'classes'
manifest = osgiManifest {
classesDir = ss.output.classesDir
classpath = ss.runtimeClasspath
// Other properties, like name and symbolicName, also set based on
// the name of the source set
}
baseName = ss.name
}
}
Running with --stacktrace indicates that the osgi plugin doesn't deal correctly with the case where both the osgi and the java plugins are applied, but no Java code is present. Removing the java plugin should solve the problem.
I had the same issue also when java code was present.
Adding these two lines to the osgiManifest closure fixed the problem:
classesDir = sourceSets.main.output.classesDir
classpath = sourceSets.main.runtimeClasspath
-- erik
Related
I'm trying to create a custom source set and mark its contents in Intellij Idea as a Test Sources Root. I tried to use idea plugin and do it according to the gradle official website but it is not clear for me how it works.
First of all the documentation specifies the following configuration setup
idea {
module {
testSources.from(sourceSets["intTest"].java.srcDirs)
}
}
When I try to use it i receive Unresolved reference: testSources. Where is it coming from?
Then I tried to use:
idea {
module {
testSourceDirs = intTest.java.srcDirs
}
}
it works fine as long as I use only Java. After applying Kotlin plugin however, both kotlin and java + resources folder are again treated as Sources Root not Test Sources. To fix that I had to change from:
testSourceDirs = intTest.java.srcDirs
to:
testSourceDirs = intTest.kotlin.srcDirs
and now all folders are Test Source Root again. Since kotlin.srcDirs also includes java.srcDirs it looks like you have to specify all, otherwise it is ignored...
Now the real issue came when I used gradle-avro-plugin. Applying it made my folders marked as Sources Root again. I believe it is because it adds another avro directory, but just to main source set.
Does anyone know how to make it marked as Test Sources having both kotlin and avro plugin applied? Am I doing something wrong here? Beacause this beheviour seems to be buggy in the first place.
Tested with:
IntelliJ IDEA 2022.3.1 (Ultimate Edition)
Gradle 6.8.3 and 7.4.2
Plugin id("com.github.davidmc24.gradle.plugin.avro") version "1.5.0"
Plugin kotlin("jvm") version "1.7.0"
We have a tool that runs from the command line. One of the commands is -version.
Before we converted to the nebula release plugin, the version was in the gradle.properties file, and as part of the build we copied it from there to a src/main/resources/version.txt file, that was later read by the tool to output the version.
But now the version is never in a file that's checked into git. Instead, it is only known during the nebula release process.
We want to obtain that version during the nebula release process and inject it into the jar that nebula is about to publish. For example, it could be added to the manifest.
We've tried to figure out how to do this, but don't see any examples online, and nothing about it in the documentation.
Simply create a task that caches the version that is dynamically inferred by Nebula.
Since you originally copied/created src/main/resources/version.txt, we'll use that that model our task.
Assuming a simple/standard Java project, using the Kotlin DSL:
val cacheNebulaVersion by tasks.registering {
mustRunAfter(tasks.named("release"))
doLast {
val sourceSets = project.extensions.getByName("sourceSets") as SourceSetContainer
sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME).output.resourcesDir?.let {
// If there are not existing resources in your project then you must create
// the resources dir otherwise a FileNotFoundException will be thrown.
if (!it.exists()) {
it.mkdirs()
}
File(it, "version.txt").printWriter().use { out ->
out.println(project.version)
}
}
}
}
When I invoke ./gradlew clean build snapshot cacheNebulaVersion, the version produced by Nebula is cached/created at src/main/resources/version.txt in the build output. The task above does not bundle it with the jar.
Hopefully that gives you an idea what to do.
I'm using intellij (2019.1.1) for a java gradle (5.4.1) project and use lombok (1.18.6) for autogenerating code. Intellij puts generated sources under out/production/classes/generated/... and gradle puts them under build/generated/sources/...
This is fine, and I like that intellij keeps it's own build artifacts separate from gradles, however, intellij seems to look in both directories when running projects and it complains about the duplicate generated classes.
What is the best practice for using intellij with gradle and autogenerated sources? Do you:
tell intellij to output to the same directory as gradle (this
could lead to odd behaviour if a process outside of intellij updates
a file under build/)
tell intellij to perform all tasks with
gradle (i hear this is slower than intellij's make)
tell intellij
to simply ignore the 'build' directory (how do you even do this? and
why does intellij even care about 'build/' when it knows it outputs
to 'out/')
UPDATE: to clarify the situation, the issue is NOT with lombok autogenerated code, it is with hibernate-jpamodelgen. The problem remains the same (duplicate generated sources) but I want to clarify the it is the sources generated by jpamodelgen and not lombok.
UPDATE 2: I have tried the following configuration in an attempt to tell intellij where the generated sources live and also to tell intellij to ignore the build directory. Sadly, this did not work (still get duplicate class error on the generated source files).
apply plugin: 'idea'
idea {
module {
sourceDirs += file('out/production/classes/generated')
generatedSourceDirs += file('out/production/classes/generated')
excludeDirs += file('build')
}
}
UPDATE 3:
Tried the advice from M.Riccuiti and deleted build/, out/, .idea/, .gradle/ and reimported the gradle project but intellij is still seeing the generated sources in the build/ directory.
Here is an approach that finally worked for me. The trick is to notice that when gradle generates the classes, it puts them in:
build\generated\sources\annotationProcessor\java\main\com...
but intellij has the production sources directory set to "generated" in this case, the sources go to:
build\generated\sources\annotationProcessor\java\main\generated\com...
if you compile with gradle first and then use idea, you get both of them, which causes the problem!
To solve this, replace "generated" and "generated_test" in the intellij annotation processors "production sources directory " and "test sources directory " configuration with just a "/" this makes both gradle and intellij generate the sources in the SAME directory, overwriting each other as needed. Also make sure that the "store generated sources relative to" is set to "module content root" and REBUILD the application to clear out any other sources.
The solution I proposed in previous comment was working fine in IDEA 2018.3.x but after upgrading to IDEA 2019.1 I again got this duplicate class exception...
Below is a working solution to make this work with Gradle 5.x (tested with 5.4) and IDEA 2019.1 , to implement your solution #3 which I think is the best option (do not mix gradle & idea generated output directories, and do not delegate IDEA action do Gradle )
The key point is to use excludeDirs property from idea.module extension to make IDEA ignore generated sources managed by Gradle under build/generated/sources/...
ext {
// path to Gradle generated main sources directory
gradleGeneratedMainSourcesDir = "$buildDir/generated/sources/annotationProcessor/java/main/"
// path to Gradle generated test sources directory
gradleGeneratedTestSourcesDir = "$buildDir/generated/sources/annotationProcessor/java/test/"
// path to IDEA generated sources directory
ideaGeneratedSourcesDir = "$projectDir/out/production/classes/generated"
}
idea {
module {
// exclude main & test sources generated by Gradle from project source directories
excludeDirs += file(gradleGeneratedMainSourcesDir)
excludeDirs += file(gradleGeneratedTestSourcesDir)
// include generated sources directory managed by IDEA
sourceDirs += file(ideaGeneratedSourcesDir)
generatedSourceDirs += file(ideaGeneratedSourcesDir)
}
}
See complete sample project based on this configuration here : https://github.com/mricciuti/sample-springboot-gradle-idea
You can enter to IntelliJ Settings (Preferences):
Preferences | Build, Execution, Deployment | Build Tools | Gradle | Runner
Then you tick the checkbox Delegate IDE build/run action to Gradle
Finally, you clean and build again. The issues will be resolved.
I'm creating a desktop application with Kotlin and I'm trying to obfuscate the final output
I work on an application using JavaFx and Kotlin. I work with Gradle as a build tool and I'm searching how to obfuscate my jar in order to avoid reverse-enginneering on the jar. The generated jar is a fat jar (all library are inside the jar). I already tried using proguard in my gradle.build but everytime I run my build I get lot of "can't find referenced class" with native java library class such as Object, String, and so on.
Here is my current proguard task:
def jarNameWithoutExtension = jar.archiveName.with {
it.take(it.lastIndexOf(".")) }
def obfuscatedJarName = "${jarNameWithoutExtension}-release.jar"
def jarFileLocation = jar.archivePath.parent
def obfuscatedFilePath = Paths.get(jarFileLocation, obfuscatedJarName)
task obfuscate(type: ProGuardTask) {
configuration 'proguard.txt'
injars jar.archivePath
outjars obfuscatedFilePath.toString()
libraryjars files(configurations.compile.collect())
libraryjars "/usr/lib/jvm/java-11-oracle/lib/rt.jar"
doLast {
jar.archivePath.renameTo(Paths.get(jarFileLocation, "$jarNameWithoutExtension-original.jar").toFile())
obfuscatedFilePath.toFile().renameTo(jar.archivePath)
}
}
jar.finalizedBy(project.tasks.obfuscate)
The proguard.txt file is currently empty
An error example is "Warning: javafx.animation.Animation: can't find superclass or interface java.lang.Object"
I expect to have an obfuscated jar file produced when building my project, but all I've got is compilation error
I hope that somebody can help me with my problem
JShrinker is a jar obfuscation tool that provides a graphical user interface. If you're not limited to Pro Guard, it may solve your issue. It's very user friendly and saves you all of the configuration and head scratching that is nearly unavoidable with other programs.
i am very new to gradle, i was trying to build a java file which is dependent on other jar file. It is building properly but when i try to execute it, it is giving "NoClassDefinitionFoundError".
my build.gradle file is:
apply plugin : 'java'
jar {
manifest {
attributes 'Main-Class': 'Hey'
}
}
dependencies
{
compile files('lib/BuildBasicJavaProject.jar') ------line A
}
if i remove the above line A then it is not even building the project.
if i keep that line A then it is building properly and producing the jar file, but when i execute it using ,
java -jar jarfilename.jar
then it is giving me a NoClassDefinitionFoundError.
Where do i need to specify the dependents path while running the jar file??
May be its a basic doubt but i wasted 2 days already in it, i tried giving
1) absolute path of the dependency file
2) adding the following line,
runtime files('lib/BuildBasicJavaProject.jar')
But did not succeed.
Thanks in advance
First welcome to Gradle world.
Your Gradle scripts seems to be correct. When you have a dependency, one jar depends on another like in your case at compile time you define compile time dependency like you did. So if you need this jar to run it you need runtime dependency, in your case. But Gradle automatically put all your compile time dependencies to be runtime dependencies. So you do not need to specify them explicitly.
So why then your code does not working?
The classpath (-cp) option is ignored if using the -jar option. So you can not specify dependent jar using -cp when type jar.So you have to write If you are on Windows
java -cp myJar.jar;.\lib\BuildBasicJavaProject.jar Hey
or use (:) and slashes(/) for Linux.
Where Hey is the full-quallified name of your main class, which have to be defind in the Manifest.
So if your class Hey is in the package:com.alabala.dev and it's name is Hey it's full qualified name is com.alabala.dev.Hey. So you have to tell Gradle
mainClassName = "com.alabala.dev.Hey"
So now Gradle put it in the manifest and when you are trying to load this jar in the JVM, she will know that to start it, she have to execute com.alabala.dev.Hey.
What is cp and why you have to specify it? Said with simple word cp is classpath - directories and archives in which JVM searches when want to load something. So here there is nothing linekd with Gradle it is Java.
You'll want to specify dependency jar(s) as a part of classpath, when you are executing your jar.
Something along these these lines:
java -cp myJar.jar:./lib/BuildBasicJavaProject.jar my.package.MyMainClass
Bare in mind that classpath delimiters are different on different platforms (: is for *nix based systems).