IntelliJ, Android and Gradle - intellij-idea

I am trying to get my existing Android Project working with gradle and IntelliJ 12.
Previously I had it working with maven but that didn't seem to be so flexible as gradle, and from what I think I got to know is that I need less subfolders.
My Android project is divided into a clean java library (:core) and the actual Application (:android). These two projects are both in my main project folder.
~-+MainProject
|--+core
| L--build.gradle
|--+android
| L--build.gradle
|--build.gradle
L--settings.gradle
I think the ideal solution to get gradle work with this is to treat the (:core) and (:android) project as nested projects, meaning I can simply be with my cmd in MainProject source folder to start the gradle tasks.
However I came up with different problems:
Gradle dependencies are only included in the core project
that means neither in the instrumentatetionTest nor in the main project files are any
directories correctly set as source / test directories
IntelliJ doesn't resolve any classes that I added as dependencies in gradle (AndroidSDK, junit, mockito, those from the :core project)
tried to use the plugin 'idea' but either I used it wrong or it didn't solve the problem
I get duplicate dependency Error for building the APK
must have something to do with junit:4.11 and mockito-core:1.9.5 that I added
what I tried:
deleting the dependencys -> build fails cause some classes of course could'nt be resolved
changing to junit:4.5+ as suggesed in some other thread -> no change at all
Here are the *.gradle configuartions
MainProject:
-- settings.gradle
include ':core', ':android'
-- build.gradle
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.6.+'
}
}
subprojects {
repositories {
mavenLocal()
maven { url "http://repo.maven.apache.org/maven2" }
}
}
:core
-- build.gradle
apply plugin: 'java'
dependencies {
testCompile 'junit:junit:4.11'
testCompile 'org.mockito:mockito-core:1.9.5'
}
:android
apply plugin: 'android'
repositories {
mavenCentral()
}
dependencies {
compile project(":core")
compile 'com.google.android:android:4.1.1.4'
instrumentTestCompile 'junit:junit:4.11'
instrumentTestCompile 'org.mockito:mockito-core:1.9.5'
instrumentTestCompile 'com.google.dexmaker:dexmaker:1.0'
instrumentTestCompile 'com.google.dexmaker:dexmaker-mockito:1.0'
instrumentTestCompile 'com.jayway.android.robotium:robotium-solo:3.6'
}
/* ... androidSettings
I hope someone could help me with that
MFG Dornathal

Alright, so you've got the right idea, but there are a few changes you still need.
Your root build.gradle file should be as follows:
subprojects {
repositories {
mavenCentral()
}
}
You only need to include mavenLocal() if you are using a locally installed repo. Most people don't, and nothing in your project indicates that you need one.
mavenCentral() can be used to replace to maven URL you were using.
We only need to modify the buildscript for the android project, so we should localize that to the android project's build.gradle.
Your settings.gradle and your build.gradle for the core project are good.
Your build.gradle for the android project however, needs some changes:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.6.+'
}
}
apply plugin: 'android'
dependencies {
compile project(":core")
instrumentTestCompile 'com.jayway.android.robotium:robotium-solo:3.6'
}
By including the android plugin, we link directly to the installed SDK. This means we no longer need to include the android dependency: compile 'com.google.android:android:4.1.1.4'.
We don't need to include junit. It's provided by the SDK, so we'll just use that. One thing to note is that the SDK only includes JUnit 3.
We don't need to include mockito and dexmaker unless we actually use it for the android tests. If it's only being used for the tests on the java library, we don't need it here.
To answer your questions:
I'm not sure what you're asking here. It might help if you should your project structure including the directories in which you have files and such.
Your hunch is correct. Hamcrest, which provides matchers for tests, made a breaking change to their API between versions 1.1 and 1.3. JUnit 4.11 has a dependency on Hamcrest 1.3. Mockito 1.9.5 however, depends on Hamcrest 1.1. So when both are included, the 1.3 overrides the 1.1 & Mockito no longer works. Reverting to JUnit 4.5 is also a problem. Junit 4.5 includes the Hamcrest 1.1 jar as a file rather than as a dependency in the POM. So this will cause issues when we have 2 versions of the same file. JUnit 4.10 is the way you want to go here. This has the dependency on Hamcrest 1.1 and includes it in the POM instead of as a file. Win win! I've had issues with this too, and the best way for me to figure it out was to just look at the POM files on Maven Central and see what they tell me.
One final note. Intellij 12 cannot handle Gradle Multi-project builds. You need to switch to Android Studio or Intellij 13 for that.

Related

Can't add kotlinx to a fresh Kotlin/JS project

Trying to figure out what I'm doing wrong. I created a small video of exactly what I'm doing in IntelliJ on Windows.
https://www.youtube.com/watch?v=nIH_55Zbxus&feature=youtu.be
And I'll describe it here in text.
Create a new project
Tick the Gradle > Kotlin/JS for browser template and untick everything else
Add implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8' to the dependencies block in the build.gradle.
Sync the gradle files
Attempt to use something from the kotlinx.coroutines namespace
Hopefully its just a silly thing I'm missing. I expected to just have to add the coroutines library to be able to actually import it. It looks like the library is listed in the project structure for the main module so I'm not sure what else might be wrong. Here is a repo of the project too.
plugins {
id 'org.jetbrains.kotlin.js' version '1.3.72'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-js"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8'
testImplementation "org.jetbrains.kotlin:kotlin-test-js"
}
kotlin.target.browser { }
You should add kotlinx-coroutines-core-js dependency. See the documentation: https://github.com/Kotlin/kotlinx.coroutines#js

How can I import JAXB into a Java 11 IntelliJ (Gradle) project?

I have been using JAXB in a Java project using JDK 8.
Having migrated to JDK 11, the JAXB package name is no longer recognized.
I have also not found a way to add JAXB as a dependency in gradle.
How can I import JAXB into my project?
You need to include JAXB API and choose from one of the JAXB implementations because JAXB is is no more included by default in the JDK 11. You need to add some dependencies to your build.gradle.
So first:
compile group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.1'
and if you decide to use for example MOXy, then something like:
compile group: 'org.eclipse.persistence', name: 'org.eclipse.persistence.moxy',
version: '2.7.3'
See also this great explanation
This example using MOXy also requires jaxb.properties file containing information about JAXBContextFactory (see here chapter 2.1):
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Advantage of this seems to be:
Because you do not need to change any application code, you can easily switch between different JAXB implementations.
I had a build issue in my android flutter project and I spent quite a few hours hunting on this issue. I understood that Java 11 does not support certain JAR files out of the box and hence we had to include some dependency. But it was not straightforward. I nailed this down to a certain version issue in JAXB library. Finally, here is my working solution for android/build.gradle file.
I added a few repositories (like google, mavenCentral) and also the version of jaxb-api of 2.3.0 is the one that worked. I remember 2.3.1 did not work at that time... but when I tried now it works. Its strange. Evidently, I am not an expert in this area. I was just thankful that It worked out finally... I am presenting the android/build.gradle for whatever salt its worth. Hope this helps someone.
buildscript {
ext.kotlin_version = '1.3.50'
repositories {
google()
mavenCentral()
maven {
url = uri("https://repo1.maven.org/maven2/")
}
jcenter()
}
dependencies {
classpath "javax.xml.bind:jaxb-api:2.3.0"
classpath 'jakarta.xml.bind:jakarta.xml.bind-api:2.3.2'
classpath 'org.glassfish.jaxb:jaxb-runtime:2.3.2'
classpath 'com.android.tools.build:gradle:4.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()
mavenCentral()
maven {
url = uri("https://repo1.maven.org/maven2/")
}
jcenter()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}

How come that an Android app can be built without repositories in buildscript?

I am trying to understand what repositories does in buildscript. I have read quite a few posts explaining it, but I still feel that I have not grasped the concept. Here is the project build.gradle:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
// repositories {
// jcenter()
// maven {
// url 'https://maven.google.com/'
// name 'Google'
// }
// }
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
}
}
allprojects {
repositories {
jcenter()
maven {
url "https://jitpack.io"
}
google()
}
}
You can see that I have commented out repositories in buildscript. The app is built perfectly, and published without any problems. Could anyone shed some light on this? Maybe an example showing repositories in buildscript is required will help me understand it finally.
After trial and error, Android Studio provides the plugins or at least sources of the plugins itself while compiling and building even if the repositories block was commented out. This is most probably due to the fact of it's high integration with Gradle. However when building from the command line using gradlew assembleDebug or something similar, the Gradle wrapper will throw the following error:
"Cannot resolve external dependency
com.android.tools.build:gradle:3.0.1 because no repositories are
defined."
As to further explain the concepts for clarity, the repositories under buildscript defines the sources of downloading the plugins used in compiling your Gradle project. For example the Android Gradle Plugin is downloaded by defining the repo that contains it (Google maven in this case) and adding the dependency com.android.tools.build:gradle:3.0.1 for the buildscript. Hence by doing that, you'll be able to add the plugin with apply plugin: 'com.android.application' inside your app module build.gradle file. This is not yet related to your code libraries, this is just related to the build system in order to compile the project Projects by using plugins which have tools and extra tasks to compile them properly.
If you realize below the buildscript block, there is the allprojects block which states the repositories used in order to handle project dependencies. Meaning the libraries that your are using in your app (which are also inside the dependencies block in app build.gradle file) are retrieved from there and in this case they are from JCenter, JitPack.io and Google Maven.

Proper structure for Gradle multi-module builds with IntelliJ IDEA

I have a Kotlin project which is comprised of three modules:
Core < Service < Web
The structure is:
build.gradle
core/
build.gradle
service/
build.gradle
web/
build.gradle
The structure for the root build.gradle file is:
buildscript {
ext.kotlin_version = '1.1.60'
repositories {
mavenCentral()
jcenter()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
subprojects {
apply plugin: 'kotlin'
apply plugin: 'jacoco'
compileKotlin {
kotlinOptions.jvmTarget = '1.8'
}
repositories {
mavenCentral()
jcenter()
}
}
The individual build files look like (for core):
dependencies {
// Kotlin
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
...
}
And for service (note the only difference is the project dependency):
dependencies {
compile project (':core')
// Kotlin
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
...
}
There are a few optimizations I'd like to make, but I'm still learning Gradle, and can't find the right way to reorganize things. The problems I have are:
I can't build service or web individually, as they complain about not being able to find their dependent sub-projects. (Via a gradle build in the service/ directory, for example.)
How can I define the Kotlin stdlib-jre8 dependency at the root level, so it's not duplicated in my three build files?
How can my subproject/buildscript tasks of the root buildfile use the same repository definitions, so that I don't have to define mavenCentral()/jcenter() twice?
Basically this build structure that I have was cobbled together through some experimentation/web resources, and happens to mostly work, but I'd like some guidance on doing it the right way, such that (1) it follows good Gradle practices, and (2) still works well via auto-import into IDEA.
If you want to run a build on a module you can do by running: gradle :web:build
In the same way that you are adding repositories in the subprojects clause, you can add the dependencies block in there. Make sure that only the shared dependencies are in there. For instance, compile project(':core') should only be in the relevant project. It's ok to have multiple dependency blocks. That said, it's usually more of a headache to use the subproject clause. Because, if dependencies change for one of the modules you are forced to update that for all of them
Regarding the repository definitions, they are very different. The one in the buildscript block is used by Gradle itself in order to find plugins and other 'pre-build' requirements. The one on the submodules is used to find the dependencies of the source code in the given module. As mentioned on the previous point, it's easier to manage when placed on the respective module build scripts.
Update:
If you want to keep the same version for all modules, the variables defined on ext in the buildscript should be able to be accessed from the submodules too: ext.kotlin_version = '1.1.60' and if you have multiple ones you can add them like:
ext {
kotlin_version = '1.1.60'
junit_version = '4.12'
}
Also, if you want to share code between modules, you can always extract it to gradle file and load it where needed using: apply file: "$rootDir/path/to/script.gradle"
Regarding #3, I'll give you a practical example.
Google has its own maven repository that contains all the dependencies for an android module. If you have a project that contains both a server-side module and android module you may not need the server-side one to look up dependencies on the Gradle artefact repository (artefact is the name of the jar dependency).
As for the buildscript repositories, in your case you are only loading one classpath (pre-build) dependency which is located on mavenCentral() so you may be ok removing jcenter() here.

Using autosuggest on dependency jars that are downloaded by Gradle

I'm pretty new to Gradle and IntelliJ and I'm trying to understand how it works [cos that's what my project uses]. I created a simple java project in Intellij IDEA with a HelloWorld class and manually added the gradle.build file along with the necessary dependencies as follows:
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'application'
mainClassName = 'main.java.test.HelloWorld'
dependencies {
compile 'joda-time:joda-time:2.2'
}
repositories {
mavenLocal()
mavenCentral()
}
jar {
baseName = 'gradle-test'
manifest {
attributes 'Main-Class': 'main.java.test.HelloWorld'
}
}
task wrapper(type: Wrapper) {
gradleVersion = '2.2'
}
While I specified the joda-time dependency, my IntelliJ project is unaware of this library and therefore I can't use of any of the autosuggest features of IntelliJ for the joda-time library.
Could someone give me information on how I can get IntelliJ to automatically start recognizing the downloaded jars and allow me to use the auto-suggest features?
In other words,
where are the dependency jars downloaded ?
How can I have these jars to automatically be included in the
class path of the project ? [Is it ok to do so ? If not, what
would be your recommendation ?]
Thanks !
I used Peter's suggestion to run gradle idea and imported the project into IntelliJ and I was able to start using the auto-suggestion features in IntelliJ.
Thanks