Execute commons-math Java class from a gradle task - java

I need to execute from a gradle task classes included on a jar file.
For instance I would like to create a gradle task able to execute the class FastMath(http://commons.apache.org/proper/commons-math/download_math.cgi).
The current build.gradle script is the following:
apply plugin: 'java'
repositories {
mavenCentral()
}
dependencies {
compile files('/pathToJars/commons-math3-3.6.1.jar')
}
task t1 {
doLast {
println FastMath.abs(3)
}
}
I get this error message:
What went wrong:
Execution failed for task ':t1'.
Could not get unknown property 'FastMath' for task ':t1' of type org.gradle.api.DefaultTask.
I understand I am missing the class import, for instance adding the following statement but I do not know how or where:
import org.apache.commons.math3.util.FastMath;
I am wondering what I am doing wrong or how the script has to be configured. Any suggestion will be appreciated.
EDIT 1: The code that actually works is the following:
apply plugin:'java'
import org.apache.commons.math3.util.FastMath;
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.apache.commons:commons-math3:3.6.1'
}
}
task t1 {
doLast {
println FastMath.abs(3)
}
}

Well, you have multiple issues in your buildscript.
If you use mavenCentral() as repository, use the dependencies from there, you will gain transitive dependency resolution and automatic conflict resolution and you do not have to keep the libs in your VCS or wherever, so compile files('/pathToJars/commons-math3-3.6.1.jar') should actually be compile 'org.apache.commons:commons-math3:3.6.1'.
As you correctly noted, you either have to use fully-qualified class names or imports, so either, replace println FastMath.abs(3) by println org.apache.commons.math3.util.FastMath.abs(3), or add import org.apache.commons.math3.util.FastMath anywhere before. Typically this is done top-most in a file, just like for Java too.
Even if you would do both, it would not work, because you add the dependency to the compile classpath of your actual project. Instead you need it in the classpath of your buildscript, so you need to move the dependencies block inside a buildscript block and if you followed advice 1, then of course also the repositories block. You also need classpath instead of compile in the dependency declaration.

Related

Gradle dependency platform in parent module

I have a gradle project with a lot of subprojects and I want a BOM file to apply to all the subprojects.
I tried to put this in some subproject and it works fine:
dependencies{
implementation enforcedPlatform('group:bom-artifact:version')
}
But when I put it a parent gradle.build, or wrap it like:
allprojects {
dependencies {
implementation enforcedPlatform('group:bom-artifact:version')
}
}
It ends with error:
> Could not find method implementation() for arguments [DefaultExternalModuleDependency{group='group', name='bom-artifact', version='version', configuration='default'}] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.
Can't figure out what's wrong. How to fix this? Or is there a better way to apply one BOM to all subprojects and manage it from one place?
I don't think the issue is the platform itself here
The message you're getting usually appears if you have not (yet) applied the Java plugin.
Gradle's configuration scopes like implementation, api and compileOnly are initialized as part of the Java plugin's init phase.
So depending on the structure of your subproject you might have one or more subprojects that don't use the Java plugin that does not recorgnize the scope. I'm not quite sure about the execution order between subprojects, this might play also play a role.
A simple solution would be to apply the plugin also into the allprojects closure, like
allprojects {
apply plugin: 'java'
dependencies {
implementation enforcedPlatform('group:bom-artifact:version')
}
}

javax.inject does not exists

To investigate troubles with javax.inject I have created minimalistic Gradle project in IntelliJ IDEA.
It contains Main.java only:
import javax.inject.Scope;
public class Main {
public static void main(String[] args) {}
}
build.gradle
buildscript {
repositories {
mavenCentral()
}
}
apply plugin: 'java'
dependencies {
compileOnly 'javax.annotation:jsr250-api:1.0'
}
and settings.gradle
rootProject.name = 'test'
Building the project I got
Error:(1, 20) java: package javax.inject does not exist
What's wrong with javax, why it doesn't exists??
Hmm, it seems the problem is not specifically with javax. Tried to add different dependencies from mavenCentral, no one works. Like Gradle does not load external libraries at all.
Solved
The problem was with repositories - it must be outside of buildscript.
Just bring the javax.inject dependency
implementation 'javax.inject:javax.inject:1'
Compile only dependencies are distinctly different than regular “compile” dependencies. They are not included on the runtime classpath and are non-transitive, meaning they are not included in dependent projects. This is true when using Gradle project dependencies and also when publishing to Maven or Ivy repositories. In the latter case, compile only dependencies are simply omitted from published metadata.
see https://docs.gradle.org/current/userguide/artifact_dependencies_tutorial.html

intellij build jar artifact containing gradle dependencies

I basically want to do something simple - or atleast i think it should be pretty simple.
My goal is to create an Intellij gradle project, add some dependencies to the module using gradle and add some java source code to it.
Then I just want to have an option to somehow compile the whole thing into 1 jar, containing all grade dependencies and being able to execute using "java -jar"
However it turned out that this is not as easy is i had thought.
I just created a new gradle project from intellij and added a Main class.
I´ll give you an overview over my files:
settings.gradle:
rootProject.name = 'gradleTestNewJar'
build.gradle:
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'application'
sourceCompatibility = 1.6
version = '1.0'
repositories {
mavenCentral()
}
mainClassName = "com.randomPackage.StarterClass"
dependencies {
compile 'org.seleniumhq.selenium:selenium-java:2.46.0'
testCompile group: 'junit', name: 'junit', version: '4.11'
}
main class:
package com.randomPackage;
import com.gargoylesoftware.htmlunit.BrowserVersion;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
public class StarterClass {
public static void main(String[] args){
System.out.println("test");
WebDriver driver = new HtmlUnitDriver(BrowserVersion.FIREFOX_38);
driver.quit();
}
}
The main method of "MyStart" is executed when running from Intellij via debug.
So it works, when all dependencies get loaded correctly.
NOTE: I use Intellij Community Edition if this makes any difference.
What i tried:
1. I tried to just use "gradlew clean build".
This created a jar, but without libs.
But I didn´t expect it to be as easy as this.
2. I tried to build an artifact of the module as suggested here:
http://blog.jetbrains.com/idea/2010/08/quickly-create-jar-artifact/
I tried it with extracted and not extracted dependencies.
In both cases the dependencies were added into the jar, but they were added to the root of the jar.
When i tried to run the jar file via "java -jar", it complained:
"Exception in thread "main" java.lang.NoClassDefFoundError: org/openqa/selenium/WebDriver
..."
OK, so it couldn´t load the dependencies.
NOTE: I thought that the dependencies were not added to the classpath, but i am not sure about this. However, i would expect Intellij to add dependencies to the classpath( or declare in the manifest file)
3. I also tried to use the gradle application plugin.
However this creates a zip/tar which contains a execute script and a bin folder which was not my intention.
So i started googling for hours and hours but i cann´t find a solution to my problem.
Come on this cannot be so hard - it is just so basic.
I am sure some genius can help me out and point me to my - probably stupid - failure.
My current solution is as follows:
I use gradle to build a jar containing all libs, I do this witha custom task called fatJar.
Here is a part from my build.gradle
apply plugin: 'java'
jar {
manifest {
attributes("Manifest-Version": "1.0",
"Main-Class": "com.randomPackage.MainClass");
}
}
task fatJar(type: Jar) {
manifest.from jar.manifest
classifier = 'all'
from {
configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) }
} {
exclude "META-INF/*.SF"
exclude "META-INF/*.DSA"
exclude "META-INF/*.RSA"
}
with jar
}
Then I just execute "gradle fatJar" on the command line and get a perfect jar.

How do I correctly output META-INF when libraries use SPIs using gradle?

I am attempting to make a test application using Gradle and Java that uses several libraries that use the Java Service Provider interface. I think this means that I need to modify META-INF but I am not really sure how to do this.
The error that I get is An SPI class of type org.apache.lucene.codecs.codec with nameLucene50does not exist. You need to add the corresponding JAR file supporting this SPI to your classpath. The current classpath supports the following names [ SimpleText]
I think that I need to get the SPI information into META-INF but I am not sure how to do this with Gradle.
Specifically, I am trying to use Lucene and Hadoop jars in the following build file:
apply plugin: 'java'
sourceCompatibility = 1.8
version = '1.0'
repositories {
mavenCentral()
}
dependencies {
compile group:'org.apache.lucene', name:'lucene-core', version:'5.0.0'
compile group:'org.apache.lucene', name:'lucene-queryparser', version:'5.0.0'
compile group:'org.apache.lucene', name:'lucene-analyzers-common', version:'5.0.0'
compile group:'org.apache.lucene', name:'lucene-facet', version:'5.0.0'
compile group:'org.apache.lucene', name:'lucene-codecs', version:'5.0.0'
compile group:'org.apache.hadoop', name:'hadoop-hdfs', version:'2.6.0'
compile group:'org.apache.hadoop', name:'hadoop-core', version:'1.2.1'
compile group:'org.apache.hadoop', name:'hadoop-common', version:'2.6.0'
}
jar
{
from {configurations.compile.collect {it.isDirectory() ?it:zipTree(it) }}
manifest
{
attributes 'Main-Class': 'LuceneTest'
}
}
Both the lucene-core and lucene-codecs libraries provide org.apache.lucene.codecs.Codec implementations, so they both have a META-INF/services/org.apache.lucene.codecs.Codec service file. When you merge all your dependencies, both files are added to the jar file, but Lucene only sees the lucene-codecs one. You could merge the service files manually in the jar task, as in this post, which basically finds all the service files and combines them. The easier solution is probably to use something like the Gradle Shadow plugin.
If you add this to build.gradle, using the shadowJar task instead of the jar task should do what you want.
buildscript {
repositories { jcenter() }
dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.1'
}
}
apply plugin: 'com.github.johnrengelman.shadow'
shadowJar {
mergeServiceFiles()
}

Use Java class in Gradle build script

I have a Gradle build script which has to instantiate a Java class in a Task and call a method on the created object. Currently, I have the following:
apply plugin: 'java'
dependencies {
compile files("libs/some.library.jar")
}
task A << {
def obj = new some.library.TestClass()
obj.doSomething()
}
The problem is that the class some.library.TestClass() is not found. I read this article about how to use Groovy classes in Gradle, but I need my Java class to come from an external JAR file. How can I add a jar to the build source? It seems that the dependencies block doesnt do what I expect it to do. Can anyone give me a hint in the right direction?
The dependency compile files("libs/some.library.jar") is added as a project dependency not as the script dependency itself. What You need to do is to add this dependency in script's classpath scope.
apply plugin: 'java'
buildscript {
dependencies {
classpath files("libs/some.library.jar")
}
}
task A << {
def obj = new some.library.TestClass()
obj.doSomething()
}
Now it should work.

Categories