Gradle Run MainClass from external dependency - java

I have two gradle-configured projects, projectA and projectB. ProjectA is a spring boot project with two main classes, one run when running projectA directly, another run when running projectB (see gradle file below). ProjectA is exported as a JAR which is declared as a dependency of projectB. ProjectB specifies as its main class a class from projectA.jar:
//ProjectB's build.gradle
apply plugin: 'application'
mainClassName = 'com.projectA.api.MainClassToBeRunInProjectB'
/**
* `verify` task, `run` task to be exact
*/
task verify(dependsOn:run)
dependencies{
compile (group:'com.projectA.api',name:'api-ProjectA-jar',version:'1.0.0')
}
//Download artifacts
repositories {
mavenLocal()
maven {
url 'http://nexus.projectJarLocations.local/nexus/content/groups/public/'
}
mavenCentral()
}
When running the verify step in projectB, the build fails as follows:
acidnbass:projectB acidnbass$ gradle clean verify
> Task :run
Error: Could not find or load main class com.projectA.api.MainClassToBeRunInProjectB
FAILURE: Build failed with an exception.
Why can't I run the main class from projectA? Is there extra config needed to run a main class from an external source?

its possible by setting up a task like this:
task runApp(dependsOn: configurations.compileClasspath, type: JavaExec) {
group = "app"
classpath = sourceSets.test.runtimeClasspath
main = 'com.projectA.api.MainClassToBeRunInProjectB'
}
and by adding a dependency as an implementation
dependencies{
implementation('com.projectA.api:api-ProjectA-jar:1.0.0')
}

Related

Including Java library built with Gradle throws NoClassDefFoundError

I am writing a Java library and I would like to build the library with Gradle and then test it from a local test project.
I would prefer using Gradle 3.3 for my objective.
The library should be built for Java5 and higher.
So far my build.gradle looks like this:
plugins {
id 'jvm-component'
id 'java-lang'
}
repositories {
mavenCentral()
}
model {
components {
main(JvmLibrarySpec) {
sources {
java {
dependencies {
module 'commons-codec:commons-codec:1.10'
module 'org.apache.httpcomponents:httpcore:4.4.6'
module 'org.apache.httpcomponents:httpclient:4.5.3'
}
}
}
api {
exports 'io.simplepush'
}
targetPlatform 'java5'
}
}
}
The source code of the library is located in src/main/java/io/simplepush/Notification.java and depends on the dependencies stated in the build.gradle file.
Building the library with ./gradlew build works fine and generates build/jars/main/jar/main.jar.
However when I run a test project from IntelliJ (after including main.jar into the test project), I get the following runtime error:
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/http/HttpEntity.
It seems like the test project does not know about the runtime dependencies needed by my library.
I am not sure on what is the correct way to tell the test project about the dependencies of my library.
I do not want a fat jar which includes all dependencies.
Listing all dependencies in the test project itself is also not an option.
Preferably I want the library itself to tell the test project about which dependencies it needs.
The library jar which you have created does not contain any dependency information which the IDE/Gradle can then resolve to be able to compile/run the test project. I see that you are using the maven central repository so what you need to do is to publish your library to your local maven repository and in the test project just add a dependency information (no just plain jar file).
So in both library and test project build.gradle add a maven local repository config.
repositories {
mavenLocal()
mavenCentral()
}
And now you need to publish the library to local repository. As you are using the gradle 3.3 you can use the Maven Publishing.
So in the library build.gradle add a maven publishing information.
publishing {
publications {
maven(MavenPublication) {
groupId 'io.simplepush'
artifactId 'project1-sample'
version '1.1'
from components.java
}
}
}
Gradle “maven-publish” plugin makes this easy to publish to local repository automatically creating a PublishToMavenLocal task.
So you can just run
gradle publishToMavenLocal
Which will publish your library with all the dependency information into local maven repository.
And then you just need to add a library information to you test projects build.gradle
dependencies {
// other dependencies .....
module 'io.simplepush:project1-sample:1.1'
}
I solved it by changing several things.
Thanks to #Babl for pointing me in the right direction.
My new library build.gradle looks like this:
plugins {
id 'java'
id 'maven-publish'
}
sourceCompatibility = 1.5
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
compile 'commons-codec:commons-codec:1.10'
compile 'org.apache.httpcomponents:httpcore:4.4.6'
compile 'org.apache.httpcomponents:httpclient:4.5.3'
}
publishing {
publications {
maven(MavenPublication) {
groupId 'io.simplepush'
artifactId 'project1-sample'
version '1.1'
from components.java
}
}
}
Now I can push the library to the local maven repository with ./gradlew publishToMavenLocal.
The build.gradle of the test project uses the application plugin and defines a main class (which is Hello in my case). Then I can run ./gradlew installDist to generate an executable file (see Application plugin docs) which puts all dependencies in the classpath and runs just fine.
group 'com.test'
version '1.0-SNAPSHOT'
apply plugin: 'java'
apply plugin: 'application'
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
compile 'io.simplepush:project1-sample:1.1'
}
mainClassName = "Hello"
This specify what repositories to check to fetch the dependencies from
repositories {
mavenCentral()
}
Therefore, anything that is in the dependecies{} will be fetched from those above.
If the test project is not coupled with the library project, (#RaGe example) new test project needs to know where to take the dependency from - you need to publish it, using preferred method.
After that, your new test project needs to specify the library with the preferred configuration (compile...runtime etc) in the build.gradle dependencies{}
After that depending on IDE you need to refresh the classpath and download the dependency from the specified before repository, the transitive dependencies specified in the library dependency (in this case) will get fetched from test projects repositories{}
Library build.gradle
repositories {
mavenCentral()
}
dependencies {
module 'commons-codec:commons-codec:1.10'
module 'org.apache.httpcomponents:httpcore:4.4.6'
module 'org.apache.httpcomponents:httpclient:4.5.3'
}
test project build.gradle
repositories {
mavenCentral() repository to fetch transitives
mavenLocal() or any other repo that you published the library to
}
dependencies {
pref-conf librarygroup:name:version
}
You can use idea or eclipse plugin in gradle for gradle idea or gradle eclipseClasspath tasks to refresh it with your freshly added dependencies.
With this solution, you should not need to pack the transitive dependencies within the library,
PS. I am just confused after you said you want executable jar.

How do i fix my dependencies in my build.gradle file

I am new to gradle, i need to configure my build.gradle file . Am using selenium webdriver and i have list of .jar files. how do i include this jar files as dependencies in my build.gradle file?. i have this .jar in a folder called lib in my package. and i have
dependencies {
compile fileTree(dir: 'lib', includes: '*.jar')
}
but i keep having the error below:
FAILURE: Build failed with an exception.
Where:Build file '/home/ola/workspace/build.gradle' line: 20
What went wrong:
A problem occurred evaluating root project 'workspace'. Cannot cast object '*.jar' with class 'java.lang.String' to class 'java.lang.Iterable'
please can anyone point me to how to write dependencies for a webdriver project using gradle.This is the path to my lib folder: "/home/user/workspace/mainsite_automation/src/autoTest/lib/"
Thanks
You just need to specify the dependencies repository and the selenium webdriver dependencies so you will end up with a build.gradle similar to this:
apply plugin: 'java'
apply plugin: 'jetty'
repositories {
mavenCentral()
}
sourceSets {
selenium
}
dependencies {
seleniumCompile 'junit:junit:4.11'
seleniumCompile 'org.seleniumhq.selenium:selenium-java:2.30.0'
}
task jettyDaemon(type: org.gradle.api.plugins.jetty.JettyRun) {
daemon = true
}
task selenium(type: Test, dependsOn: jettyDaemon) {
testClassesDir = sourceSets.selenium.output.classesDir
classpath = sourceSets.selenium.runtimeClasspath
}
for Eclipse, you can add selenium dependencies to the classpath adding this to your build.gradle:
eclipse {
classpath {
plusConfigurations += configurations.seleniumCompile
}
}
then you can use grade clean selenium to rebuild your project.
Sources:
https://docs.gradle.org/current/userguide/artifact_dependencies_tutorial.html
http://www.dreamchain.com/gradle-selenium-webdriver-task/

Copy jar from dependent Project in Gradle?

I have to gradle projects core and main. They are in a flat project structure:
/
/core
/main
Both projects use the java plugin. The main project has a settings.gradpe file with the following content:
includeFlat "core"
The build.gradle of main is:
apply plugin: 'java'
apply plugin: 'eclipse'
...
dependencies {
compile (project(':core'))
}
When I execute the build task on the main project. The core project is build first and the generated core-1.0.jar is used as dependency for the compile task of main.
When I use the build task on main I want that the core-1.0.jar from the core project is copied into the lib folder of my main project.
How can I do that?

Gradle bootRepackage task in a project with multiple jars

I have a project using gradle and springboot. My project also produces an auxiliary jar of its test classes so that other projects can leverage them. This seems to send the springboot gradle plugin off the rails.
The docs on the plugin state:
The bootRepackage task depends on Gradle assemble task, and when executed, it tries to find all jar artifacts whose qualifier is empty (i.e. tests and sources jars are automatically skipped).
Due to the fact that bootRepackage finds 'all' created jar artifacts, the order of Gradle task execution is important.
What I'm seeing instead is that bootRepackage is just repackaging the most recently created jar, not all jars, as the documentation states. This jar happens to be my jar of test classes, which is obviously not what I want.
Looking through the config options, I can set bootRepackage.withJarTask to specify which jar-creating task to use. If I set that to "jar", bootRepackage will create the correct archive, but still chooses the name of the jar from my test task.
My minimal build script which demonstrates this is as follows.
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'spring-boot'
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.2.3.RELEASE")
}
}
repositories {
mavenCentral()
}
dependencies {
compile 'com.google.inject:guice:3.0' // random dependency
}
task testJar (type: Jar, dependsOn: testClasses) {
baseName = "test-${project.name}" // somehow springboot uses this name
from sourceSets.test.output
}
configurations {
testArtifacts
}
artifacts {
testArtifacts testJar
}
springBoot.backupSource = false
bootRepackage {
withJarTask jar
classifier = "boot"
}
Assuming my project is named foo running bootRepackage with this script, I get a jar named test-foo-boot.jar instead of foo-boot.jar. Am I doing something improperly, or does that withJarTask not do exactly what it should?

How to use Gradle to build a JAR that depends on another JAR

I have a Eclipse workspace with a declared workset configured to have several projects. Some are to generate JAR files and others are web applications that use those JAR files. In my architecture I have a JAR that will consist of domain core services and another one that depends on the first one that will consist of higher level services. Finally I will have some web applications that use those both JARs.
The first JAR project is build with Gradle, based on the following script
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'application'
repositories {
mavenLocal()
mavenCentral();
}
jar {
baseName = 'br.ufpr.unidades.dominio'
version = '0.1.0'
}
dependencies {
compile 'org.hibernate:hibernate-core:4.3.7.Final'
}
task wrapper(type: Wrapper) {
gradleVersion = '1.11'
}
As anyone can see, it´s a very simple build.gradle file and the build works fine with it. The expected JAR file is generated in the expected destination folder.
Now, here comes the build script for the second JAR:
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'application'
repositories {
mavenLocal()
mavenCentral()
}
jar {
baseName = 'br.ufpr.unidades.dominio.hibernate'
version = '0.1.0'
}
dependencies {
runtime fileTree(dir: '../dominio/build/libs', include: '*.jar')
compile 'org.hibernate:hibernate-core:4.3.7.Final'
}
task wrapper(type: Wrapper) {
gradleVersion = '1.11'
}
The second file is very similar to the first one, except it has a dependency on generated JAR:
runtime fileTree(dir: '../dominio/build/libs', include: '*.jar')
Eclipse doesn´t show any problems, but when I try to build the second JAR project I get many Class not found error messages, like the one below:
[sts] -----------------------------------------------------
[sts] Starting Gradle build for the following tasks:
[sts] build
[sts] -----------------------------------------------------
:compileJava
D:\Users\alex\Documents\Eclipse\workspace\unidades\dominio.hibernate\src\main\java\dominio\hibernate\HibernateCargoRepository.java:7: error: package unidades.dominio does not exist
import unidades.dominio.Cargo;
The message is clear: I´m importing a package that is not being found during the build, so the classes such a package has cannot be referenced in my code. Such a package is declared in the first and perfectly generated JAR file. It also is visible under Referenced Libraries item in the Eclipse project, so Gradle was able to find it to reference it in design time, but not to build the second JAR.
After all that, I suspect it´s a dependency management problem, but I can´t see which it is and how to fix it.
Thanks in advance!
Are You using classes from the jar under dominio/build/libs in the second project? If so, this should be a compile dependency. I'd also recommend setting a multimodule gradle project. Here are the docs.

Categories