Confused about dependencies in local respository(gradle) - java

I trying to compile and package up my java application but I am facing issues when trying to specify my local repository in which I have my jars that will be used as dependencies. I have stored all the jars I need for my application in '/home/test/lib'. What I have as my build.gradle file is as follows:
apply plugin:'application'
apply plugin:'java'
apply plugin:'idea'
def repositoryPath = '/home/test/lib'
repositories {
repositoryPath
}
dependencies {
"org.springframework:spring-orm:3.0.2.RELEASE"
"org.springframework:spring-context-support:3.0.2.RELEASE"
'commons-dbcp:commons-dbcp:1.4'
'org.apache.ibatis:ibatis-sqlmap:2.3.4.726'
'commons-dbutils:commons-dbutils:1.3'
'joda-time:joda-time:1.6'
'commons-lang:commons-lang:2.5'
'com.google.collections:google-collections:1.0'
}
jar {
baseName = 'testJar'
}
mainClassName = "com.some.test.testRunner"
When I run gradle build, I am getting "package * does not exist" errors.
My assumption is that gradle is not finding the requisite external jars in my lib folder. Can somebody point out what I may be doing wrong here.
Thanks

some remarks about your build file. I assume you have a flat directory in '/home/test/lib' that contains your third party libs? If this is the case you can use a flatDir repository, that is declared with the following syntax:
def repositoryPath = '/home/test/lib'
repositories {
flatDir {
dirs repositoryPath
}
}
If /home/test/lib is a ivy repository, you can do:
repositories {
ivy {
url repositoryPath
}
}
This is explained in detail in the Gradle user guide.
in your 'dependencies' section you missed to declare the scope of your dependencies (compile, runtime, etc):
dependencies {
compile "org.springframework:spring-orm:3.0.2.RELEASE"
compile "org.springframework:spring-context-support:3.0.2.RELEASE"
compile 'commons-dbcp:commons-dbcp:1.4'
compile 'org.apache.ibatis:ibatis-sqlmap:2.3.4.726'
compile 'commons-dbutils:commons-dbutils:1.3'
compile 'joda-time:joda-time:1.6'
compile 'commons-lang:commons-lang:2.5'
compile 'com.google.collections:google-collections:1.0'
}
if you use a flatdir repository, the group of your dependency definition is often omitted:
dependencies {
compile ":spring-orm:3.0.2.RELEASE"
...
}
Have a look at the gradle user guide for detailed information about dependency handling with gradle: http://gradle.org/docs/current/userguide/userguide_single.html#artifact_dependencies_tutorial
regards,
René

Related

How to make Gradle flatDir read nested folders?

I'm using the Gradle local flatDir repository in the following way:
repositories {
flatDir {
dirs 'D:/path/to/local/directory'
}
}
but it only searches for the first layer of files. I wonder if there is an option of telling Gradle to locate the dependencies all over the repository, so I would be able to organize my jars by groups and still make Gradle read them all without specifying the groups.
Have you considered using the Maven directory conventions instead of flatDir?
Eg store jars like
myLocalRepo/com/foo/bar/1.0/bar-1.0.jar
myLocalRepo/com/foo/baz/2.0/baz-2.0.jar
Then in build.gradle
repositories {
maven {
uri file('myLocalRepo')
}
}
dependencies {
compile 'com.foo:bar:1.0'
compile 'com.foo:baz:2.0'
}

Gradle custom plugin jar with dependencies

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

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.

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

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()
}

Categories