Using your own Java library in another project? - java

So despite developing with Java for quite a while, I've only just decided to give making my own library a go. I've created it, and have a second project within Intellij Idea, but I don't know how to use said library in the second project. This is what I have so far:
In my library, build.gradle is:
apply plugin: 'java-library'
version = '0.0.1'
repositories {
jcenter()
}
jar {
manifest {
attributes(
'Implementation-Title': project.name,
'Implementation-Version': project.title
)
}
}
dependencies {
api 'org.apache.commons:commons-math3:3.6.1'
implementation 'com.google.guava:guava:23.0'
testImplementation 'junit:junit:4.12'
}
I guess what my question is, is how do I implement my library into the second project so that I can use it (and test it properly) in the second project? I've tried to search the net to find the answer to this and cannot seem to get an explanation that makes sense to me.
I have a multi-project in the same window of Intellij Idea.

I find the official guide very meaningful about how to build a custom library.You can follow that way : Building Java Libraries.
To look for the testing part with JUnit, you can follow that rules.

Related

Replace android.support.v4.util.ArraySet with androidx.collection.ArraySet in Maven library

I have a 3rd party library that depends on:
import android.support.v4.util.ArraySet;
And I want to use the latest Android libraries in the rest of my project:
import androidx.collection.ArraySet;
However, since I'm getting the library via Maven, I can't seem to force it to replace the v4 dependency for the androidx one and have it refer to the right class.
I've already tried:
implementation 'androidx.collection:collection:1.1.0'
implementation('some-library:v1') {
exclude group: 'com.android.support', module: 'support-v4'
}
And:
configurations.all {
resolutionStrategy.dependencySubstitution {
substitute module('com.android.support:support-v4') with module('androidx.collection:collection:1.1.0')
}
}
I've even tried a few more things including the force=true for the dependencies I want.
However I'm still getting:
java.lang.NoClassDefFoundError: Failed resolution of: Landroid/support/v4/util/ArraySet;
How can I tell Gradle to resolve the imports for android.support.v4.util.ArraySet to androidx.collection.ArraySet when I don't have access to the source code?
As per the Migrate to AndroidX guide:
android.enableJetifier=true
The Android plugin automatically migrates existing third-party libraries to use AndroidX by rewriting their binaries.
So this rewriting of Maven dependencies is exactly what Jetifier does for you. Make sure you've added the android.enableJetifier=true to your gradle.properties file to enable Jetifier.

IntelliJ IDEA Gradle project not recognizing/locating Antlr generated sources

I'm using Antlr in a simple Kotlin/Gradle project, and while my Gradle build is generating Antlr sources, they are not available for importing into the project.
As you can see (on the left), the classes (Lexer/Parser, etc.) are being generated. I have also configured this generated-src/antlr/main directory as a Source Root. Most questions I see list this as a solution, but I've already done it.
The issue persists after multiple rebuilds (both in IDEA and on the CLI), and following all the usual "Invalidate Cache and Restart" issues.
Further, the import issue is listed in the Gradle build on the CLI so it doesn't seem isolated to IDEA.
What am I missing here?
Here's the build.gradle file produced by IDEA when I was creating the project initially, and which IDEA is using for project/workspace synchronization.
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.2.50'
}
group 'com.craigotis'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
apply plugin: 'antlr'
dependencies {
antlr "org.antlr:antlr4:4.5"
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
testCompile group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.2.0'
}
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
Try adding this to your build.gradle:
sourceSets {
main.java.srcDirs += "${project.buildDir}/generated-src/antlr/main"
}
generateGrammarSource {
arguments += ["-visitor", "-package", "com.craigotis.sprint.core.antlr"]
outputDirectory = file("${project.buildDir}/generated-src/antlr/main/com/craigotis/sprint/core/antlr")
}
compileKotlin.dependsOn generateGrammarSource
Shouldn't it locate the compiled classes and not the sources? Do you see the antlr generated classes in the target directory?
Try this: first build the project without referencing or using any ANTLR generated classes, and only after the build is successful, then add the code that references them.
(In other words, what I think that happens, is that your ANTLR sources are compiled after the code that references them. They never have a chance to compile because build fails before)
Also if this is really the case, you can solve it also by splitting into two artifacts and make sure the ANTLR one is built before the one with the code that uses it
Try to add generated sources in idea module like this post from Daniel Dekany here:
apply plugin: "idea"
...
sourceSets.main.java.srcDir new File(buildDir, 'generated/javacc')
idea {
module {
// Marks the already(!) added srcDir as "generated"
generatedSourceDirs += file('build/generated/javacc')
}
}

Gradle - Error Could not find method implementation() for arguments [com.android.support:appcompat-v7:26.0.0]

I am trying to open existing android project in android studio and it gradle cannot build the app without the error
Error android studio keeps on throwing
Error:(74, 1) A problem occurred evaluating project ':app'.
> Could not find method implementation() for arguments
[com.android.support:appcompat-v7:26.0.0] on object of type
org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.
My Code in build.gradle Which can help to understand my issue
My dependencies
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
// google & support
implementation "com.android.support:appcompat-v7:$supportVersion"
implementation "com.android.support:cardview-v7:$supportVersion"
implementation "com.android.support:recyclerview-v7:$supportVersion"
implementation "com.android.support:design:$supportVersion"
implementation "com.android.support:palette-v7:$supportVersion"
implementation "com.android.support:customtabs:$supportVersion"
implementation "com.android.support:support-v4:$supportVersion"
implementation 'com.google.android.exoplayer:exoplayer:r2.0.4'
// utils
implementation 'com.github.bumptech.glide:glide:4.0.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.0.0'
implementation 'com.koushikdutta.ion:ion:2.1.7'
implementation 'com.github.Commit451:bypasses:1.0.4'
implementation 'com.jakewharton:butterknife:8.8.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.0'
implementation 'com.drewnoakes:metadata-extractor:2.9.1'
implementation "com.orhanobut:hawk:2.0.1"
}
Please help to solve the issue
Make sure you're adding these dependencies in android/app/build.gradle, not android/build.gradle.
Replace compile with implementation.
compile was recently deprecated and replaced by implementation or api
Make sure your Gradle version is 3.*.* or higher before using "implementation".
Open the project level Gradle file under dependencies:
dependencies{
classpath 'com.android.tools.build:gradle:3.1.2'
}
Open the 'gradle-wrapper.properties' file and set the distributionUrl:
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
or latest version.
Sync the project. I Hope this solves your problem.
You need to use at least Gradle 3.4 or newer to be able to use implementation. It is not recommended to keep using the deprecated compile since this can result in slower build times. For more details see the official android developer guide:
When your module configures an implementation dependency, it's letting Gradle know that the module does not want to leak the dependency to other modules at compile time. That is, the dependency is available to other modules only at runtime.
Using this dependency configuration instead of api or compile can result in significant build time improvements because it reduces the amount of projects that the build system needs to recompile. For example, if an implementation dependency changes its API, Gradle recompiles only that dependency and the modules that directly depend on it. Most app and test modules should use this configuration.
https://developer.android.com/studio/build/gradle-plugin-3-0-0-migration.html#new_configurations
Update: compile will be removed by end of 2018, so make sure that you use only implementation now:
Warning:Configuration 'compile' is obsolete and has been replaced with
'implementation'. It will be removed at the end of 2018
change apply plugin: 'java'
to apply plugin: 'java-library'
java-library-plugin
For me I put my dependencies in the wrong spot.
buildscript {
dependencies {
//Don't put dependencies here.
}
}
dependencies {
//Put them here
}
Solved this by adding my dependancies in the app folder
Go to app < Gradle Scripts < gradle.build(Module: app) and add the depandancies in that file and not the global build.gradle file
So ridiculous, but I still wanna share my experience in case of that someone falls into the situation like me.
Please check if you changed: compileSdkVersion --> implementationSdkVersion by mistake
I moved implementation to module-level build.gradle from root-level build.gradle. It solves the issue.
Your Code
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
Replace it By
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
Replace your implementation with classpath. That should work.
As mentioned here, https://stackoverflow.com/a/50941562/2186220, use gradle plugin version 3 or higher while using 'implementation'.
Also, use the google() repository in buildscript.
buildscript {
repositories {
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.2'
}
}
These changes should solve the issue.
As suggested in official docs you need add these :
buildscript {
repositories {
// Gradle 4.1 and higher include support for Google's Maven repo using
// the google() method. And you need to include this repo to download
// Android Gradle plugin 3.0.0 or higher.
google()
...
}
dependencies {
classpath 'com.android.tools.build:gradle:4.2.0'
}
}
adding these remove my error. Also use implementation instead of compile.
In my case it was because I used Implementation instead of implementation.
For me the problem was that I wrote:
android {
compileSdk 31
…
Instead of:
android {
compileSdkVersion 31
So make sure your build.gradle is correct.
If implementation is not defined, you are writing on a wrong file. On Unity 2019+ the correct file is main template grandle and not some of the others.

Creating Java library - add Gradle dependency for testing, but don't include it in compiled library (or make it overridable)

I have an Android project and I plan to make one of its components a library. This will be a Java library (jar), as the android dependencies are not needed there.
The problem is that this library depends on RxJava. But I would like it to be dependent on the RxJava version which the library client will use, no to be explicitly provided by me in the library's build.gradle.
I thought that maybe Gradle Default dependencies would be the way to go, but it doesn't provide the RxJava dependency at all and the library module doesn't build.
My build.gradle:
apply plugin: 'java'
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
configurations.all {
pluginTool {
defaultDependencies { dependencies ->
dependencies.add(this.project.dependencies.create("io.reactivex:rxjava:1.1.0"))
}
}
}
sourceCompatibility = "1.7"
targetCompatibility = "1.7"
The problem is that this library depends on RxJava. But I would like it to be dependent on the RxJava version which the library client will use, no to be explicitly provided by me in the library's build.gradle.
I don't know if that's possible because that's not the way dependencies work. Maven Transitive Dependencies explains this issue a little.
For example, you made a library and used a given version of RxJava, say, vn. It implictly means that your lib uses some features of vn that are not present in vn-1 and hopefully won't be deprecated in vn+1 and later. If a lib client were able to choose any RxJava version, it could arbitrarily pick vn-1 and your code would not work. You have a hard dependency on vn and anyone who uses your library should be aware of it.
There's no problem in providing an explicit dependency in your lib's build.gradle. In fact, listing the dependencies will help Gradle resolve the dependency graph, handle conflicts and everything. Here's a bit of what Gradle does: https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.ResolutionStrategy.html
Finally, even if you find a way to achieve the dependency delegation to the lib client, the application can crash during runtime.

Gradle provided dependencies with Intellij

I'm trying to build a Bukkit plugin. The plugin also uses exp4j. The final result needs to have the exp4j code included in the released jar but not have the Bukkit code included.
I followed the advice of this answer to copy the dependencies in and used this answer to declare Bukkit as provided. My build.gradle now looks like this:
apply plugin: 'java'
apply plugin: 'idea'
configurations {
provided
}
sourceSets {
main.compileClasspath += configurations.provided
test.compileClasspath += configurations.provided
test.runtimeClasspath += configurations.provided
}
dependencies {
provided "org.bukkit:bukkit:1.8.8-R0.1-SNAPSHOT"
compile "net.objecthunter:exp4j:0.4.5"
}
jar {
// copy the dependencies across
from {
configurations.compile.collect {
it.isDirectory() ? it : zipTree(it)
}
}
}
This works great and I can build and run the project happily using Gradle from the command line. The trouble is that Intellij (or maybe it's the Gradle idea plugin) doesn't recognise the provided dependencies, thus, importing anything from Bukkit causes it to incorrectly report an error.
How can I get the provided dependencies to play nicely with idea?
Other things I've tried:
I've also tried declaring the provided scope like this:
configurations {
provided
compile.extendsFrom provided
}
But this causes the provided dependencies to be copied into the final jar. I've also tried the plugins as recommended by this answer, but both cause Bukkit to be copied into the created jar. I've further tried declaring Bukkit to be runtime scope instead provided, but that simply caused lots of compile errors (but interestingly Intellij did have Bukkit listed as a dependency)
I have trouble believing that this has not been asked before, but I've searched and cannot find a full solution. I'm new to Gradle, so apologies if this is a super simple thing to do.
In Gradle 2.12 and later, there is a configuration called compileOnly that has the provided semantics you are looking for.
More about this configuration on the Gradle blog post on the subject.
Before 2.12, you can use the nebula.provided-base plugin to create a provided configuration with all the correct semantics.
See Gradle issue here.
There isn't a provided configuration in gradle, though there really should be one. The most reasonable workaround currently seems to be, to create your own configuration:
configurations {
provided
}
and then:
sourceSets {
main {
compileClasspath += configurations.provided
}
}
The problem with extendsFrom is that the provided dependency will end up being bundled in your distribution anyway unless if you add another explicit exclude, defeating the whole point of provided.
Edit: To tell idea to use the provided dependencies, you could apply the 'idea' plugin and then:
idea {
module {
scopes.PROVIDED.plus += [ configurations.provided ]
}
}
see more here.
I did find a very hacky solution. But it's so bad I feel bad posting it here :P
Declare the provided dependencies as runtime dependencies
Regenerate the idea files: gradle cleanIdea idea
Idea should now recognise the dependences
Change the provided dependencies back to provided
Go into the project settings and convert all the dependencies with runtime scope to Intellij's provided scope
Stuff works :) (Just don't ever regenerate the idea files)
Obvious problems, anyone using your project has to do the same hack. And every time you regenerate the idea files, the same thing will have to be repeated.

Categories