I'm developing a gradle plugin alongside with a project:
plugin_consumer
|
+ build.gradle
+ src/
plugin
|
+ build.gradle
+ libs/
+ src/
All jars are moved to plugin/libs after built, and plugin consumer module uses plugin like so:
buildscript {
repositories {
// ...
}
dependencies {
classpath fileTree(dir:'../plugin/libs', include: ['*.jar'])
}
}
apply plugin: 'my.custom.plugin'
I tested and this setup worked fine, however the plugin .jar is being built without dependencies, and as soon as I add some dependencies to the project the consumer buildscript started crashing because of NoClassDefFoundError exceptions. The problem is when I build a fat jar instead the script no longer finds plugin:
// from plugin/build.gradle
// Configurations to build jar with dependencies
configurations {
jar.archiveName = 'plugin.jar'
}
jar {
archiveName = 'plugin.jar'
baseName = project.name + '-all'
from { configurations.compile.collect {
println it
it.isDirectory() ? it : zipTree(it)
} }
}
Running commands on plugin_consumer project throws error:
> Failed to apply plugin [id 'my.custom.plugin']
> Plugin with id 'my.custom.plugin' not found.
I haven't identified the problem, but have found a solution. Somehow the jar instruction to package all of the sources have messed up the plugin jar file. The following configurations have worked on plugin side instead:
//...
jar {
from {
configurations.compileWithDependencies.collect { it.isDirectory() ? it : zipTree(it) }
}
}
configurations {
compileWithDependencies
}
dependencies {
compile gradleApi()
compileWithDependencies 'my.dependency1'
compileWithDependencies 'my.dependency1'
testCompile 'test.dependency'
configurations.compile.extendsFrom(configurations.compileWithDependencies)
}
From the looks of it I would guess that gradleApi() dependencies should not be compiled into the plugin jar.
Related
I am building a jar file using gradle. I have local jar files as dependencies. Those jars have additional local dependencies stored in the same directory. I used the following build.gradle file
plugins { id 'application' }
repositories {
flatDir{ dirs 'lib'
}
dependencies {
implementation name: 'localjar1'
implementation name: 'localjar2'
}
application { mainClass = 'mypackage.MyApp' }
jar {
from { configurations.runtimeClasspath.collect {it.isDirectory ? : zipTree(it) } }
manifest { attributes 'Main-Class': 'mypackage.MyApp' }
}
I built the jar using gradle jar, but when I try to run the jar:
java -jar myapp\build\libs\myapp.jar
I get the following error:
Unable to initialize main class mypackage.MyApp
Caused by java.lang.NoClassDefFoundError: com/localpackage/SomeClass
How do bring that dependency in correctly?
I also tried to include the entire local library as a dependency
implementation fileTree(dir: 'lib', include: '*jar')
But when I do this I get the error: java.lang.ClassNotFoundException: mypackage.MyApp
What else should I try?
** Note: I can run the application using gradle run
I'm trying to build a jar for a custom gradle plugin to be used by other gradle projects. I'm using java to write the plugin. I'm having a problem including dependencies in my jar. If I build the jar using the below build.gradle
plugins {
id 'groovy'
}
repositories{
mavenCentral()
}
dependencies {
compile gradleApi()
compile localGroovy()
compile 'com.google.guava:guava:27.0-jre'
testCompile 'junit:junit:4.12'
//compile 'org.apache.commons:commons-lang3:3.8.1'
}
group = 'com.mine'
version = '1.0'
I get a NoClassDefFound exception for guava classes when applying the plugin on a project. If I include a task to create a jar with dependencies like below in the build.gradle
jar {
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it)}
}
}
It says Plugin with Id 'my-plugin' not found. How do I include dependencies in a gradle plugin jar?
Your plugin project should be configured as a standalone Plugin project and then published to a maven repository, which will make dependencies resolution work; there is good documentation about writing custom plugin here, specially the following part : using Gradle plugin development plugin
There is also a good example of writing/publishing/consuming a custom Plugin in the Gradle examples here : https://github.com/gradle/gradle/tree/master/subprojects/docs/src/samples/plugins (see the two subprojects publishing and consuming )
And here is a working example with a plugin that has dependency on external library (commons-lang for example):
Plugin project
build.gradle
plugins {
id 'java-gradle-plugin'
id 'groovy'
id 'maven-publish'
}
group 'org.gradle.sample.plugin'
version '0.1'
// pugin metadata configuration
gradlePlugin {
plugins {
myplugin {
id = "org.gradle.sample.plugin.myplugin"
implementationClass = "org.gradle.sample.plugin.MyPlugin"
}
}
}
// publish to local maven repo for testing
publishing {
repositories {
maven {
url "../repos/maven-repo"
}
}
}
// repo for dependences resolution
repositories{
jcenter()
}
// dependencies of this plugin
dependencies {
compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.8.1'
}
Plugin implementation : src/main/groovy/org/gradle/sample/plugin/MyPLugin.groovy
package org.gradle.sample.plugin
import org.apache.commons.lang3.StringUtils
import org.gradle.api.Plugin
import org.gradle.api.Project
class MyPlugin implements Plugin<Project> {
#Override
void apply(final Project project) {
println "Applying custom plugin... "
project.tasks.create('testPlugin'){
doLast{
println " custom plugin task executing."
println "Result: " + StringUtils.capitalize("stringtotest")
}
}
}
}
Build and publish this plugin ./gradlew publish : the plugin jar and "plugin marker artefacts" will be published to local maven repo in ../repos/maven-repo
Consumer project
build.gradle
plugins {
id 'java'
// import/apply your custom plugin
id 'org.gradle.sample.plugin.myplugin' version '0.1'
}
group 'org.gradle.sample.plugin'
version '0.1'
repositories{
maven {
url "../repos/maven-repo"
}
jcenter()
}
To test the plugin, try to execute the plugin task testPlugin
> Task :testPlugin
custom plugin task executing.
Result: Stringtotest
Sorry to add this as an answer but I don't have enough points to comment (yes it is a bit late in coming but I found this in a search and it came so close, maybe this will help someone else).
The answer by #M.Ricciuti is correct, just missing one file, namely a settings.gradle in the referencing project (not the plugin) directory:
pluginManagement {
repositories {
maven {
url '../repos/maven-repo'
}
gradlePluginPortal()
ivy {
url '../repos/ivy-repo'
}
}
}
Many thanks, I have tried many things that didn't work before finding this, even the examples by gradle didn't work (or more likely I didn't run them correctly). Anyway I merged what I saw in the answers with M. Ricciuti's answer and saw that file in the sample.
My complete project is at https://github.com/reddierocket/sampleGradlePlugin
The readme has instructions to run it. (Note I did not include the wrapper but I am using gradle version 5.3.1.)
After much research, I can't seem to get to the root of a problem I am having in generating a runnable Scala jar file using Gradle. I'm overriding the 'jar' Gradle task to create a jar file (dependencies included) that executes starting from my main class file. However, whenever I run it, regardless of what I use for a Main-Class attribute, the console throws a "Could not find or load main class" error. Here's what I have so far:
build.gradle
buildscript {
repositories {
mavenCentral()
}
}
apply plugin: 'java'
apply plugin: 'scala'
apply plugin: 'application'
repositories {
mavenCentral()
// some other repos
}
version = '1.0'
sourceCompatibility = 1.8
targetCompatibility = 1.8
mainClassName = "com.test.Main"
dependencies {
// my dependencies
}
jar {
zip64 = true
manifest {
attributes "Main-Class": "$mainClassName"
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
src/main/scala/com/test/Main.scala
package com.test
object Main {
def main(args: Array[String]): Unit = {
print("Hello world");
}
}
In fact, when I run "java tf test.jar", it shows "com/test/Main.class" in the root of the jar! Am I missing some important class path info or something? I'm running Java 1.8 on macOS Sierra using Gradle 3.5. Any help is appreciated. Thanks!
I had a similar problem and it turns out that my META-INF folder inside my jar file contains a few RSA, SF, and DSA files.
Once I excluded them, it worked!
here is how to based on your jar declaration
jar {
zip64 = true
manifest {
attributes "Main-Class": "$mainClassName"
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it)
}
exclude ('META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA')
}
You can use the Shadow Jar Plugin instead of your own jar definition.
Benefits of Shadow
Shadowing a project output has 2 major use cases:
Creating an executable JAR distribution
Bundling and relocating common dependencies in libraries to avoid classpath conflicts
Basic setup:
shadowJar {
baseName = 'your-app'
classifier = 'all'
version = version
configurations = [project.configurations.compile]
}
jar {
manifest {
attributes 'Main-Class': 'com.test.Main'
}
}
You can use the new syntax of Gradle Plugins:
plugins {
id 'java'
id 'scala'
id 'application'
}
I'm pretty new to gradle and java at all..
I have a project which uses sqlite and it runs fine through intellij idea but I can't run it from the terminal, it throws an exception:
java.lang.ClassNotFoundException: org.sqlite.JDBC
I've tried to get process which intellij idea spawns when it runs the project:
/usr/lib/jvm/java-7-openjdk-amd64/bin/java -agentlib:jdwp=transport=dt_socket,server=n,suspend=y,address=42986 -Dfile.encoding=UTF-8 -cp /home/user/my_project/target/classes/main:/home/user/my_project/target/resources/main:/home/user/.gradle/caches/modules-2/files-2.1/org.xerial/sqlite-jdbc/3.7.2/7a3d67f00508d3881650579f7f228c61bfc1b196/sqlite-jdbc-3.7.2.jar Main
As I see here idea specifies classpath which is the solution but how can I run my .jar file of the project without specifying classpath? I mean can gradle generate manifest automatically (because it retrieves sqlite-jdbc from maven org.xerial repository successfully) and put valid classpath there?
I want to run it successffully from the terminal.
UPD: I can't it run from the terminal only by gradle run command but I can't run the project by java -jar myproject.jar.
Here is my build.gradle:
apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'idea'
apply plugin: 'application'
group = 'myproject'
version = '0.3'
description = """my project description"""
buildDir = "target"
mainClassName = "Main"
repositories {
maven { url "http://repo.maven.apache.org/maven2" }
}
dependencies {
testCompile group: 'junit', name: 'junit', version:'3.8.1'
compile 'org.xerial:sqlite-jdbc:3.7.2'
}
jar {
manifest.attributes("Main-Class": "Main")
}
/* Overwriting distribution tasks: */
task distZip(type:Zip, overwrite:true) {
archiveName = "$project.name-$version" + '.zip'
from "target/libs"
}
task distTar(type:Tar, overwrite:true) {
archiveName = "$project.name-$version" + '.tar'
from "target/libs"
}
Java source code which throws an exception:
try {
Class.forName("org.sqlite.JDBC");
this.connection = DriverManager.getConnection(databaseName);
} catch (Exception e) {
e.printStackTrace();
}
I've fixed this issue by adding sqlite in the classpath of distribution jar file of the project by modifying my jar section by this:
task copyDependenciesToTarget(type: Copy) {
println 'Copying dependencies to target...'
configurations.compile.collect().each { compileDependency ->
copy {
with from (compileDependency.getPath()) {
include '*'
}
into 'target/libs/libs'
}
}
}
build.dependsOn(copyDependenciesToTarget)
jar {
manifest.attributes(
"Main-Class": "Main",
"Class-Path": configurations.compile.collect { 'libs/' + it.getName()}.join(' ')
)
}
Now gradle downloads dependencies and copies them to libs/ directory.
How to create Java Gradle project from command line?
It should create standard maven folder layout like on the picture below.
UPDATE:
.1. From http://www.gradle.org/docs/current/userguide/tutorial_java_projects.html
I need to create file build.gradle with 2 lines
apply plugin: 'java'
apply plugin: 'eclipse'
.2. Add to build.gradle task below, than execute gradle create-dirs
task "create-dirs" << {
sourceSets*.java.srcDirs*.each { it.mkdirs() }
sourceSets*.resources.srcDirs*.each { it.mkdirs() }
}
.3. Then run gradle eclipse (or corresponding string to other IDE plugin configured)
So is there way to do it in one command?
To create a Java project: create a new project directory, jump into it and execute
gradle init --type java-library
Source folders and a Gradle build file (including a wrapper) will be build.
The gradle guys are doing their best to solve all (y)our problems ;-).
They recently (since 1.9) added a new feature (incubating): the "build init" plugin.
See: build init plugin documentation
Finally after comparing all solution, I think starting from build.gradle file can be convenient.
Gradle distribution has samples folder with a lot of examples, and there is gradle init --type basic comand see Chapter 47. Build Init Plugin. But they all needs some editing.
You can use template below as well, then run gradle initSourceFolders eclipse
/*
* Nodeclipse/Enide build.gradle template for basic Java project
* https://github.com/Nodeclipse/nodeclipse-1/blob/master/org.nodeclipse.enide.editors.gradle/docs/java/basic/build.gradle
* Initially asked on
* http://stackoverflow.com/questions/14017364/how-to-create-java-gradle-project
* Usage
* 1. create folder (or general Eclipse project) and put this file inside
* 2. run `gradle initSourceFolders eclipse` or `gradle initSourceFolders idea`
* #author Paul Verest;
* based on `gradle init --type basic`, that does not create source folders
*/
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
task initSourceFolders { // add << before { to prevent executing during configuration phase
sourceSets*.java.srcDirs*.each { it.mkdirs() }
sourceSets*.resources.srcDirs*.each { it.mkdirs() }
}
task wrapper(type: Wrapper) {
gradleVersion = '1.11'
}
// In this section you declare where to find the dependencies of your project
repositories {
// Use Maven Central for resolving your dependencies.
// You can declare any Maven/Ivy/file repository here.
mavenCentral()
}
// In this section you declare the dependencies for your production and test code
dependencies {
//compile fileTree(dir: 'libs', include: '*.jar')
// The production code uses the SLF4J logging API at compile time
//compile 'org.slf4j:slf4j-api:1.7.5'
// Declare the dependency for your favourite test framework you want to use in your tests.
// TestNG is also supported by the Gradle Test task. Just change the
// testCompile dependency to testCompile 'org.testng:testng:6.8.1' and add
// 'test.useTestNG()' to your build script.
testCompile "junit:junit:4.11"
}
The result is like below.
That can be used without any Gradle plugin for Eclipse,
or with (Enide) Gradle for Eclipse, Jetty, Android alternative to Gradle Integration for Eclipse
Unfortunately you cannot do it in one command. There is an open issue for the very feature.
Currently you'll have to do it by hand. If you need to do it often, you can create a custom gradle plugin, or just prepare your own project skeleton and copy it when needed.
EDIT
The JIRA issue mentioned above has been resolved, as of May 1, 2013, and fixed in 1.7-rc-1. The documentation on the Build Init Plugin is available, although it indicates that this feature is still in the "incubating" lifecycle.
Here is what it worked for me.. I wanted to create a hello world java application with gradle with the following requirements.
The application has external jar dependencies
Create a runnable fat jar with all dependent classes copied to the jar
Create a runnable jar with all dependent libraries copied to a directory "dependencies" and add the classpath in the manifest.
Here is the solution :
Install the latest gradle ( check gradle --version . I used gradle 6.6.1)
Create a folder and open a terminal
Execute gradle init --type java-application
Add the required data in the command line
Import the project into an IDE (IntelliJ or Eclipse)
Edit the build.gradle file with the following tasks.
Runnable fat Jar
task fatJar(type: Jar) {
clean
println("Creating fat jar")
manifest {
attributes 'Main-Class': 'com.abc.gradle.hello.App'
}
archiveName "${runnableJar}"
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
} with jar
println("Fat jar is created")
}
Copy Dependencies
task copyDepends(type: Copy) {
from configurations.default
into "${dependsDir}"
}
Create jar with classpath dependecies in manifest
task createJar(type: Jar) {
println("Cleaning...")
clean
manifest {
attributes('Main-Class': 'com.abc.gradle.hello.App',
'Class-Path': configurations.default.collect { 'dependencies/' +
it.getName() }.join(' ')
)
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
} with jar
println "${outputJar} created"
}
Here is the complete build.gradle
plugins {
id 'java'
id 'application'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.slf4j:slf4j-api:1.7.30'
implementation 'ch.qos.logback:logback-classic:1.2.3'
implementation 'ch.qos.logback:logback-core:1.2.3'
testImplementation 'junit:junit:4.13'
}
def outputJar = "${buildDir}/libs/${rootProject.name}.jar"
def dependsDir = "${buildDir}/libs/dependencies/"
def runnableJar = "${rootProject.name}_fat.jar";
//Create runnable fat jar
task fatJar(type: Jar) {
clean
println("Creating fat jar")
manifest {
attributes 'Main-Class': 'com.abc.gradle.hello.App'
}
archiveName "${runnableJar}"
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
} with jar
println("Fat jar is created")
}
//Copy dependent libraries to directory.
task copyDepends(type: Copy) {
from configurations.default
into "${dependsDir}"
}
//Create runnable jar with dependencies
task createJar(type: Jar) {
println("Cleaning...")
clean
manifest {
attributes('Main-Class': 'com.abc.gradle.hello.App',
'Class-Path': configurations.default.collect { 'dependencies/' +
it.getName() }.join(' ')
)
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
} with jar
println "${outputJar} created"
}
Gradle build commands
Create fat jar : gradle fatJar
Copy dependencies : gradle copyDepends
Create runnable jar with dependencies : gradle createJar
More details can be read here : https://jafarmlp.medium.com/a-simple-java-project-with-gradle-2c323ae0e43d
If you are using Eclipse, for an existing project (which has a build.gradle file) you can simply type gradle eclipse which will create all the Eclipse files and folders for this project.
It takes care of all the dependencies for you and adds them to the project resource path in Eclipse as well.
I could handle it using a groovy method in build.gradle to create all source folders for java, resources and test. Then I set it to run before gradle eclipse task.
eclipseClasspath.doFirst {
initSourceFolders()
}
def initSourceFolders() {
sourceSets*.java.srcDirs*.each { it.mkdirs() }
sourceSets*.resources.srcDirs*.each { it.mkdirs() }
}
Now we can setup a new gradle Java EE project to eclipse with only one command. I put this example at GitHub
I just tried with with Eclipse Neon.1 and Gradle:
------------------------------------------------------------
Gradle 3.2.1
------------------------------------------------------------
Build time: 2016-11-22 15:19:54 UTC
Revision: 83b485b914fd4f335ad0e66af9d14aad458d2cc5
Groovy: 2.4.7
Ant: Apache Ant(TM) version 1.9.6 compiled on June 29 2015
JVM: 1.8.0_112 (Oracle Corporation 25.112-b15)
OS: Windows 10 10.0 amd64
On windows 10 with Java Version:
C:\FDriveKambiz\repo\gradle-gen-project>java -version
java version "1.8.0_112"
Java(TM) SE Runtime Environment (build 1.8.0_112-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.112-b15, mixed mode)
And it failed miserably as you can see in Eclipse.
But sailed like a soaring eagle in Intellij...I dont know Intellij, and a huge fan of eclipse, but common dudes, this means NO ONE teste Neon.1 for the simplest of use cases...to import a gradle project.
That is not good enough.
I am switching to Intellij for gradle projects: