OpenCV with Java Gradle Project as fat jar - java

I am actually Trying to use OpenCV in Java based Gradle Project. Since, OpenCV needs native library and Jar File for execution. I am trying to wrap native library and Jar together using gradle, but I am facing errors in doing so.
When I try to run project, project is not able to find native library for opencv jar and giving me below error
Exception in thread "main" java.lang.UnsatisfiedLinkError: no opencv_java340 in java.library.path at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867) at java.lang.Runtime.loadLibrary0(Runtime.java:870) at java.lang.System.loadLibrary(System.java:1122) at Library.(Library.java:9)
Although, I know how to set native library manually in Gradle project but I am not sure how to do it via Gradle and wrap native library in fat jar. Here is my build.gradle
// Apply the java-library plugin to add support for Java Library
apply plugin: 'java-library'
// In this section you declare where to find the dependencies of your project
repositories {
// Use jcenter for resolving your dependencies.
// You can declare any Maven/Ivy/file repository here.
jcenter()
}
configurations {
// configuration that holds jars to include in the jar
openCVLibs
}
dependencies {
openCVLibs fileTree(dir: 'libs', include: '*.jar')
openCVLibs fileTree(dir: 'libs', include: '*.so')
configurations.compile.extendsFrom(configurations.openCVLibs)
}
jar {
from {
configurations.openCVLibs.collect { it.isDirectory() ? it : zipTree(it) }
}
manifest {
attributes('Implementation-Title': project.name,
'Implementation-Version': project.version)
}
}
have also included link of sample eclipse project
So Here is edit
Based on #kerry's comment I tried to crate mvn artifact following openCV Maven, but now I am facing following error while creating mvn build
[ERROR] Failed to execute goal
org.codehaus.mojo:properties-maven-plugin:1.0.0:read-project-properties
(set-arch-properties) on project opencv: Properties could not be
loaded from File: /media/nitish/8EE47633E4761E21/opencv-3.4.0/build/build.properties -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to
execute goal
org.codehaus.mojo:properties-maven-plugin:1.0.0:read-project-properties
(set-arch-properties) on project opencv: Properties could not be
loaded from File: /media/nitish/8EE47633E4761E21/opencv-3.4.0/build/build.properties
There is no build.properties file present in build folder. Since build folder is created by maven task only, so build.properties file should be created by maven only.

Following there is a working example of a build.gradle file. Make sure to read the comments and make changes when appropriate.
By running gradle fatJar you can create a working Java Jar of your application with OpenCV inside.
However, apart form including your OpenCV library in your Java Jar, you will need to load the OpenCV native file at the beginning of your code.
They are two ways to do that:
1) Load the file by providing the full path:
System.load("my/full/path/opencv.dll");
2) If your native file is located inside your Java Library Path:
System.loadLibrary("opencv");
Take notice that in the second case you only need to provide the name of your native file (without its extension).
The default Java Library Path depends on OS:
On Windows, it maps to PATH
On Linux, it maps to LD_LIBRARY_PATH
On OS X, it maps to DYLD_LIBRARY_PATH
If you want to set your own Java Library Path:
try {
System.setProperty("java.library.path","YOUR/PATH");
Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
fieldSysPath.setAccessible(true);
fieldSysPath.set(null, null);
} catch (Exception ex) {
System.out.println("Failed to set Java Library Path: " + ex.getMessage);
}
build.gradle
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'application'
mainClassName = "YourMainClass" // You Main Class name
repositories{
mavenCentral()
}
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"
exclude "build/libs/philipath/**"
}
with jar
}
artifacts {
archives fatJar
}
dependencies {
// Local libraries
compile fileTree('lib') // assuming there is a folder named 'lib' in your project root with your OpenCV jar inside
// other dependencies
}

Related

How to manage external dependencies of a Gradle Plugin

Gradle Version: 1.12/2.0 (restricted due to Org policies)
JDK: 1.8
I have created a custom gradle plugin that performs some installation using code that has been defined in another sub-project of our source-code. The build.gradle for the plugin is
dependencies {
compile project(path: ':installlib', configuration: 'libConfig')
compile project(path: ':tools', configuration: 'toolConfig')
}
jar {
from {
// LINE#1 source-code of plugin
sourceSets.main.output
zip64 = true
// LINE#2 dependencies
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
baseName = 'myCustomPlugin'
version = '1.0'
destinationDir = new File(project.libDir)
}
The above plugin is consumed as follows - consumer.gradle
buildscript {
repositories { flatDir name: 'libs', dirs: System.env.CODESOURCE + '/lib/')
dependencies {
classpath: ':myCustomPlugin:1.0'
}
}
apply plugin: 'java'
apply plugin: 'myCustomPlugin'
...
...
//rest of the items of this gradle
Case-A
If I run this, I hit > Plugin with id 'myCustomPlugin' not found.
NOTE: I have META-INF/gradle-plugins/myCustomPlugin.properties created correctly with implementation-class pointing to my plugin code and this works fine if I don't get into creating the fat/uber-jar business and just include the sourceSets.main.output statement in my jar task. But since our entire project depends on file based artifacts, I am attempting to create a fat/uber-jar and that's where I start running into these issues.
Case-B
If I move the LINE#2 above the LINE#1, which looks like -
from {
// LINE#2 dependencies
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
// LINE#1 source-code of plugin
sourceSets.main.output
zip64 = true
}
If I run this, I hit ClassNotFoundException for one of the classes coming from the project 'installlib'. I can see the *.class file in the uber jar created but even then the class loader complains about this class.
Could anyone provide some pointers on how to resolve this ? The uber/fat jar creation (or the way I am doing it) is not helping with the plugin-source-code and dependencies of the plugin.
If not a fat jar, could anyone provide some inputs on how to resolve the dependencies in the buildscript of the consuming gradle ?

Is there a way for Gradle to resolve dependencies using curl command? [duplicate]

I have tried to add my local .jar file dependency to my build.gradle file:
apply plugin: 'java'
sourceSets {
main {
java {
srcDir 'src/model'
}
}
}
dependencies {
runtime files('libs/mnist-tools.jar', 'libs/gson-2.2.4.jar')
runtime fileTree(dir: 'libs', include: '*.jar')
}
And you can see that I added the .jar files into the referencedLibraries folder here: https://github.com/WalnutiQ/wAlnut/tree/version-2.3.1/referencedLibraries
But the problem is that when I run the command: gradle build on the command line I get the following error:
error: package com.google.gson does not exist
import com.google.gson.Gson;
Here is my entire repo: https://github.com/WalnutiQ/wAlnut/tree/version-2.3.1
According to the documentation, use a relative path for a local jar dependency as follows.
Groovy syntax:
dependencies {
implementation files('libs/something_local.jar')
}
Kotlin syntax:
dependencies {
implementation(files("libs/something_local.jar"))
}
If you really need to take that .jar from a local directory,
Add next to your module gradle (Not the app gradle file):
repositories {
flatDir {
dirs("libs")
}
}
dependencies {
implementation("gson-2.2.4")
}
However, being a standard .jar in an actual maven repository, why don't you try this?
repositories {
mavenCentral()
}
dependencies {
implementation("com.google.code.gson:gson:2.2.4")
}
You could also do this which would include all JARs in the local repository. This way you wouldn't have to specify it every time.
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
The following works for me:
compile fileTree(dir: 'libs', include: '*.jar')
Refer to the Gradle Documentation.
You can try reusing your local Maven repository for Gradle:
Install the jar into your local Maven repository:
mvn install:install-file -Dfile=utility.jar -DgroupId=com.company -DartifactId=utility -Dversion=0.0.1 -Dpackaging=jar
Check that you have the jar installed into your ~/.m2/ local Maven repository
Enable your local Maven repository in your build.gradle file:
repositories {
mavenCentral()
mavenLocal()
}
dependencies {
implementation ("com.company:utility:0.0.1")
}
Now you should have the jar enabled for implementation in your project
A solution for those using Kotlin DSL
The solutions added so far are great for the OP, but can't be used with Kotlin DSL without first translating them. Here's an example of how I added a local .JAR to my build using Kotlin DSL:
dependencies {
compile(files("/path/to/file.jar"))
testCompile(files("/path/to/file.jar"))
testCompile("junit", "junit", "4.12")
}
Remember that if you're using Windows, your backslashes will have to be escaped:
...
compile(files("C:\\path\\to\\file.jar"))
...
And also remember that quotation marks have to be double quotes, not single quotes.
Edit for 2020:
Gradle updates have deprecated compile and testCompile in favor of implementation and testImplementation. So the above dependency block would look like this for current Gradle versions:
dependencies {
implementation(files("/path/to/file.jar"))
testImplementation(files("/path/to/file.jar"))
testImplementation("junit", "junit", "4.12")
}
The accepted answer is good, however, I would have needed various library configurations within my multi-project Gradle build to use the same 3rd-party Java library.
Adding '$rootProject.projectDir' to the 'dir' path element within my 'allprojects' closure meant each sub-project referenced the same 'libs' directory, and not a version local to that sub-project:
//gradle.build snippet
allprojects {
...
repositories {
//All sub-projects will now refer to the same 'libs' directory
flatDir {
dirs "$rootProject.projectDir/libs"
}
mavenCentral()
}
...
}
EDIT by Quizzie: changed "${rootProject.projectDir}" to "$rootProject.projectDir" (works in the newest Gradle version).
Shorter version:
dependencies {
implementation fileTree('lib')
}
The Question already has been answered in detail. I still want to add something that seems very surprising to me:
The "gradle dependencies" task does not list any file dependencies. Even though you might think so, as they have been specified in the "dependencies" block after all..
So don't rely on the output of this to check whether your referenced local lib files are working correctly.
A simple way to do this is
compile fileTree(include: ['*.jar'], dir: 'libs')
it will compile all the .jar files in your libs directory in App.
Some more ways to add local library files using Kotlin DSL (build.gradle.kts):
implementation(
files(
"libs/library-1.jar",
"libs/library-2.jar",
"$rootDir/foo/my-other-library.jar"
)
)
implementation(
fileTree("libs/") {
// You can add as many include or exclude calls as you want
include("*.jar")
include("another-library.aar") // Some Android libraries are in AAR format
exclude("bad-library.jar")
}
)
implementation(
fileTree(
"dir" to "libs/",
// Here, instead of repeating include or exclude, assign a list of paths
"include" to "*.jar",
"exclude" to listOf("bad-library-1.jar", "bad-library-2.jar")
)
)
The above code assumes that the library files are in libs/ directory of the module (by module I mean the directory where this build.gradle.kts is located).
You can use Ant patterns in includes and excludes as shown above.
See Gradle documentations for more information about file dependencies.
Thanks to this post for providing a helpful answer.
I couldn't get the suggestion above at https://stackoverflow.com/a/20956456/1019307 to work. This worked for me though. For a file secondstring-20030401.jar that I stored in a libs/ directory in the root of the project:
repositories {
mavenCentral()
// Not everything is available in a Maven/Gradle repository. Use a local 'libs/' directory for these.
flatDir {
dirs 'libs'
}
}
...
compile name: 'secondstring-20030401'
The best way to do it is to add this in your build.gradle file and hit the sync option
dependency{
compile files('path.jar')
}
The solution which worked for me is the usage of fileTree in build.gradle file.
Keep the .jar which need to add as dependency in libs folder. The give the below code in dependenices block in build.gradle:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
You can add jar doing:
For gradle just put following code in build.gradle:
dependencies {
...
compile fileTree(dir: 'lib', includes: ['suitetalk-*0.jar'])
...
}
and for maven just follow steps:
For Intellij:
File->project structure->modules->dependency tab-> click on + sign-> jar and dependency->select jars you want to import-> ok-> apply(if visible)->ok
Remember that if you got any java.lang.NoClassDefFoundError: Could not initialize class exception at runtime this means that dependencies in jar not installed for that you have to add all dependecies in parent project.
For Gradle version 7.4 with Groovy build file
repositories {
flatDir {
dirs 'libs'
}
}
dependencies {
implementation ':gson-2.2.4'
}
If you are on gradle 4.10 or newer:
implementation fileTree(dir: 'libs', includes: ['*.jar'])
Goto File -> Project Structure -> Modules -> app -> Dependencies Tab -> Click on +(button) -> Select File Dependency - > Select jar file in the lib folder
This steps will automatically add your dependency to gralde
Very Simple
Be careful if you are using continuous integration, you must add your libraries in the same path on your build server.
For this reason, I'd rather add jar to the local repository and, of course, do the same on the build server.
An other way:
Add library in the tree view. Right click on this one. Select menu "Add As Library".
A dialog appear, let you select module. OK and it's done.

Gradle - cannot load a Java Class even when packed within the jar

My gradle build file is
plugins {
// Apply the java plugin to add support for Java
id 'java'
// Apply the application plugin to add support for building a CLI application
id 'application'
}
apply plugin: 'java'
jar {
from configurations.runtime
manifest {
attributes(
'Created-By':'Gmack',
'Main-Class':'myapprunner.App',
'Class-Path':'mydaos-1.0.jar'
)
}
}
allprojects{
repositories {
jcenter()
}
}
subprojects {
version = '1.0'
apply plugin: 'java'
}
dependencies {
// This dependency is used by the application.
implementation 'com.google.guava:guava:27.1-jre'
// Use JUnit test framework
testImplementation 'junit:junit:4.12'
// Compile Project for dependency
compile project(':mydaos')
}
application {
// Define the main class for the application
mainClassName = 'myapprunner.App'
}
When I run the app using java -jar myapprunner.jar
I get a ClassNotFoundException
Caused by: java.lang.ClassNotFoundException: com.mydaos.Library
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 1 more
I can confirm that the jar has been packed. Not sure why this is not picking things up.
Any help would be appreciated.
Thanks,
Plugin java is being applied twice and com.mydaos.Library is likely being pulled in from compile project(':mydaos') (or 'Class-Path':'mydaos-1.0.jar'). Would assume the project does not build or the class path is wrong.
Dependency classes (projects/external jars) aren't packed inside your jar by default.
You are using the application plugin which bundles your classes, your dependencies and an execution script in a zip so you should use that. The plugin also adds a "run" task to your project to run your main class via gradle for development purposes. See the application plugin docs for more info
If you want to pack your dependencies inside your jar (known as an uber jar) see here. I suggest you stop using the application plugin if you do this
'Class-Path':'mydaos-1.0.jar'
This assumes that mydaos-1.0.jar is in the same folder you are running java -jar ... from which is likely not the case

gradle exclude external resource folder from all jars

Using gradle 5.4 with a project dependency from external folder in a netbeans project.
The external folder contains resources like images, xml and custom objects that can only be created by this netbeans project. These external assets are then used to create binary files that get packed into a separate jar by that netbeans project.
These same external resources are also used during runtime for development in the gradle project. While I need the resources for development in the gradle project, I do not need or want them to be included in any jars anywhere for any reason when using the task build command because only the binaries are needed for distribution.
How to exclude the external resources from any and all jar files in the gradle project but allow them to be used for the classPath so I can run the project?
Some code examples of failure.
apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'idea'
sourceSets {
main {
resources {
srcDir '../ExternalResourceFolder/assets'
}
}
}
jar {
exclude('../ExternalResourceFolder/assets/**')
}
dependencies {
runtimeOnly files('../ExternalResourceFolder/assets')
}
jar {
exclude('../ExternalResourceFolder/assets/**')
}
distributions {
main {
contents {
exclude '../ExternalResourceFolder/assets/**'
}
}
}
Tried many more things like adding to classPath and exclude but it would just be clutter to add them. Changing from sourceSet to dependency only moves the problem around from "build/lib" folder to "build/distributions" folder.
Had to exclude per file type in the end.
sourceSets {
main {
resources {
srcDir '.'
exclude ('**/*.j3odata','**/*.mesh','**/*.skeleton',\
'**/*.mesh.xml','**/*.skeleton.xml','**/*.scene',\
'**/*.material','**/*.obj','**/*.mtl','**/*.3ds',\
'**/*.dae','**/*.blend','**/*.blend*[0-9]','**/*.bin',\
'**/*.gltf')
}
}
}

Unable to build gradle project in eclipse?

After cleaning when i try to build gradle i get an error in the console saying:
package org.json does not exist import org.json.JSONObject;
cannot find symbol
symbol : class JSONObject
there are red marks in the java file at all places where jsonobject and json array exists.
I have put the folder web inf/lib that contains all the jar files inside the src/main/webapp directory that i have created.
currently the contents of my build.gradle file are:
/*
* This build file was auto generated by running the Gradle 'init' task
* by 'i2cdev001' at '14/11/18 3:11 PM' with Gradle 2.14.1
*
* This generated file contains a sample Java project to get you started.
* For more details take a look at the Java Quickstart chapter in the Gradle
* user guide available at https://docs.gradle.org/2.14.1/userguide/tutorial_java_projects.html
*/
// Apply the java plugin to add support for Java
apply plugin: 'java'
apply plugin: 'war'
// In this section you declare where to find the dependencies of your project
repositories {
// Use 'jcenter' for resolving your dependencies.
// You can declare any Maven/Ivy/file repository here.
jcenter()
}
// In this section you declare the dependencies for your production and test code
dependencies {
// The production code uses the SLF4J logging API at compile time
compile 'org.slf4j:slf4j-api:1.7.21'
// 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.12'
}
Note: Also in the project properties i am unable to see any jar files under the Web App Libraries in the java build path tab. I can see only access rules:no rules defined and native library locations:(none)
As your project is gradle project, Adding jar manually wont work.. You have to mention path where you have kept all your jar files in your build.gradle file.
Mention your jar file path in repository under flatDir {}:
repositories {
jcenter()
flatDir {
dirs 'libs'
}
}
Then you have to add which jar from that folder you have mentioned above (ie libs)
dependencies {
compile 'gson-0.1.0'
}

Categories

Resources