I am new to Dagger2 and I am trying to use it in my Kotlin project (1.1.51). I followed a few tutorials and all is good.
I have these in my gradle file and I am using Android Studio 3.01, I have to use gradle-3.3
apply plugin: 'kotlin'
apply plugin: 'kotlin-allopen'
apply plugin: 'kotlin-kapt'
compile 'com.google.dagger:dagger:2.11'
kapt 'com.google.dagger:dagger-compiler:2.11'
kapt {
generateStubs = true
}
I can successfully run my project and Dagger2 seems to be working. The only annoying issue is that the Dagger created classes always come up as red on the import list. e.g DaggerMainComponent.
import com.burfdevelopment.hack24.Dagger.MainComponent
import com.burfdevelopment.hack24.Dagger.MainModule
import com.burfdevelopment.hack24.Dagger.DaggerMainComponent
So if do a code tidy which removes unused imports it always removes it even though its being used. If I click on the DaggerMainComponent, it does go to the generated class.
I think that there's an issue with the configured folders in Android Studio. In particular, in your build.gradle file you should have something like this (I used it in my IntelliJ Idea projects, but it should work also in Android Studio):
// Configure Dagger generated files
ideaModule.module.generatedSourceDirs += file("$buildDir/generated/source/kapt/main")
In this way, you are telling your IDE to mark as "generated sources", the source files under that folder (which is where Kapt puts generated files like your DaggerMainComponent)
Related
Problem
I have a setup of various distinct repos/projects (i.e. app1, app2, app3) that all depend on shared functionality in my base package.
The projects also use various other third-party dependencies (i.e. app1 and app3 use spring, all of them use kotlinx-serialization).
I want to synchronise the versions of all third-party dependencies, so that any project using my base package uses the same version of every third-party dependency. However, I don't want to introduce new dependencies to projects that do not use them (i.e. app2 does not use spring)
Solution attempts
For libraries, I have been able to solve this with the help of a gradle platform, which does exactly what I want - I specify the versions in my base package, then add the platform as a dependency to my projects and can then simply add dependencies by name (i.e. implementation("org.springframework.boot:some-package")) without having to specify a version number, because it uses the provided value from my platform.
However, for plugins, I have not been able to do this. Many libraries come with plugins and naturally the plugin should be at the same version as the library. I have tried various approaches, including writing a standalone plugin, but none have worked.
Current best idea
I added implementation("org.springframework.boot:spring-boot-gradle-plugin:3.0.2") to the dependencies of my standalone plugin. Then, I added the following code to my standalone plugin:
class BasePlugin : Plugin<Project> {
override fun apply(target: Project) {
target.plugins.apply("org.springframework.boot")
}
}
This works and applies the plugin to my main project at the correct version. However, there are 2 major problems with this:
a) Now every project applies the spring plugin, including app2 (which does not use spring).
b) I have many plugins to manage and no idea how to get the long implementation-string for most of them. I found the "org.springframework.boot:spring-boot-gradle-plugin:3.0.2" by looking up the plugin-id on https://plugins.gradle.org/ and then looking at the legacy plugin application section, which sounds like I am on the wrong track.
I just want to manage the versions of plugins and libraries of multiple projects/repos in a central place - this feels like a fairly basic use case - why is this so hard?
There are some great and detailed answers about dependency management, but unfortunately none worked to perform cross-project version management for plugins.
It seems that there is no gradle functionality to do this, but I got it working with a bit of a workaround. Here is my (working) approach, in hope that it helps someone else with this:
Create a Standalone gradle Plugin
In the build.gradle.kts of the plugin, include the maven coordinates (not its ID) of every other plugin whose version you want to manage in any of your projects in the dependency block with the api keyword. i.e. api("org.springframework:spring-web:6.0.2")
In the main projects, remove every other plugin from the plugins block, so that your custom standalone plugin is the only one remaining.
Create a file (i.e. a plugins.json or whatever you want) in the project root directory of all main projects and in there supply the plugin IDs of the plugins that you actually intend to use in that project. Just the IDs, no version numbers, i.e. "org.springframework.boot" for Spring's plugin. (Keep in mind that for plugins declared as kotlin("abc") you will have to add the prefix "org.jetbrains.com.", as the kotlin method is just syntactic sugar for that)
In your plugin source code, in the overriden apply method, look for. a file named plugins.json (or whatever you chose) in the project.buildFile.parent directory (which will be the directory of the project using this plugin, NOT of the plugin itself). From this file, read the plugin IDs
for every pluginID in the file, call project.plugins.apply(id)
How/Why it works:
The main project build.gradle.kts is executed, looks at the plugin block and applies your standalone plugin (which is the only one), which calls its apply method.
This plugin then applies other plugins based on their ID from the file.
Normally, this will throw an error because these plugins are not found, but because we defined them as dependencies with the api keyword in our standalone plugin, they are now available on the classpath and in exactly the version of that import statement.
Hope it helps someone!
I use version numbers in a gradle.properties file for this purpose. Since the introduction of Gradle version catalogs, my approach is probably a bit out of date, but I'll share it here anyway. It's based on the fact that plugin versions can be managed in settings.gradle.kts by reading values from the properties file.
In gradle.properties:
springBootVersion=3.0.2
In settings.gradle.kts:
pluginManagement {
val springBootVersion: String by settings
plugins {
id("org.springframework.boot") version springBootVersion
}
}
And finally in build.gradle.kts:
plugins {
id("org.springframework.boot")
}
dependencies {
val springBootVersion: String by project
implementation(platform("org.springframework.boot:spring-boot-dependencies:$springBootVersion"))
}
Notice that the plugin version is omitted in the build script because it is already specified in the settings file.
And note also that the method for accessing the property in the settings script is slightly different from that in the build script.
a) Now every project applies the spring plugin, including app2 (which does not use spring).
It is indeed better to avoid applying too many plugins - and that's why Gradle encourages reacting to plugins.
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.*
import org.springframework.boot.gradle.plugin.SpringBootPlugin
class BasePlugin : Plugin<Project> {
override fun apply(target: Project) {
// don't apply
//target.plugins.apply("org.springframework.boot")
// instead, react!
target.plugins.withType<SpringBootPlugin>().configureEach {
// this configuration will only trigger if the project applies both
// BasePlugin *and* the Spring Boot pluging
}
// you can also react based on the plugin ID
target.pluginManager.withPlugin("org.springframework.boot") {
}
}
}
Using the class is convenient if you want to access the plugin, or the plugin's extension, in a typesafe manner.
You can find the Plugin's class by
looking in the source code for the class that implements Plugin<Project>,
in the plugin's build config for the implementationClass,
or in the published plugin JAR - in the META-INF/gradle-plugins directory there will be a file that has the implementationClass.
This doesn't help your version alignment problem - but I thought it was worth mentioning!
b) I have many plugins to manage and no idea how to get the long implementation-string for most of them. I found the "org.springframework.boot:spring-boot-gradle-plugin:3.0.2" by looking up the plugin-id on https://plugins.gradle.org/ and then looking at the legacy plugin application section, which sounds like I am on the wrong track.
You're on the right track with the "long implementation string" as you call it. I'll refer to those as the 'Maven coordinates' of the plugin.
Gradle Plugin Maven Coordinates
The plugin id of the Kotlin JVM plugin is org.jetbrains.kotlin.jvm, but the Maven coordinates are org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0 .
The 'legacy' part refers to how the plugins are applied, using the apply(plugin = "...") syntax. The new way uses the plugin {} block, but under the hood, both methods still use the Maven coordinates of the plugin.
If you add those Maven coordinates (with versions) to your Java Platform, then you can import the platform into your project. But where?
Defining plugin versions
There are a lot of ways to define plugins, so I'll only describe one, and coincidentally it will be compatible with defining the version using a Java Platform.
If you're familiar with buildSrc convention plugins, you'll know that they can apply plugins, but they can't define versions.
// ./buildSrc/src/main/kotlin/kotlin-jvm-convention.gradle.kts
plugins {
kotlin("jvm") version "1.8.0" // error: pre-compiled script plugins can't set plugin versions!
}
Instead, plugin versions must be defined in the build config for buildSrc
// ./buildSrc/build.gradle.kts
plugins {
`kotlin-dsl`
}
dependencies {
// the Maven coordinates of the Kotlin JVM plugin - including the version
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0")
}
This looks a lot more traditional, and so I hope the next step is clean: use your Java Platform!
Applying a Java Platform to buildSrc
// ./buildSrc/build.gradle.kts
plugins {
`kotlin-dsl`
}
dependencies {
// import your Java Platform
implementation(platform("my.group:my-platform:1.2.3"))
// no version necessary - it will be supplied by my.group:my-platform
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin")
}
Note that this same method will also apply if your projects an 'included build' instead of buildSrc.
Once the plugin versions are defined in ./buildSrc/build.gradle.kts, you can use them throughout your project (whether in convention plugins, or in subprojects), they will be aligned.
// ./subproject-alpha/build.gradle.kts
plugins {
kotlin("jvm") // no version here - it's defined in buildSrc/build.gradle.kts
}
I'm following Googles instructions on how to implement "Google ML Kit" into my application. It says
Before you begin
In your project-level build.gradle file, make sure to include Google's Maven repository in both your buildscript and allprojects sections.
Add the dependencies for the ML Kit Android libraries to your module's app-level gradle file, which is usually app/build.gradle:
dependencies {
// If you want to use the base sdk
implementation 'com.google.mlkit:pose-detection:17.0.1-beta6'
// If you want to use the accurate sdk
implementation 'com.google.mlkit:pose-detection-accurate:17.0.1-beta6'
}
However I need to use ML-Kit in a library outside my app. It's basically a java library that gets used from within my app. It also has a gradle file. However when I add the dependency there, I cannot import any ml-kit classes.
Here is the gradle file of my java library:
apply plugin: 'java-library'
dependencies {
api 'com.annimon:stream:1.2.2'
api 'org.javatuples:javatuples:1.2'
api 'com.google.guava:guava:30.1.1-jre'
// JSON
implementation 'org.json:json:20210307'
implementation 'androidx.annotation:annotation:1.2.0'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.4'
implementation 'com.google.mlkit:pose-detection:17.0.1-beta6'
}
sourceCompatibility = "8"
targetCompatibility = "8"
gradle sync is still successful, but upon importing any class inside any other class of my java library, I get an import error:
import com.google.mlkit.vision.pose.defaults.PoseDetectorOptions;
--> cannot resolve symbol mlkit
Any idea what I could do about that?
Meanwhile I found the problem: The above gradle file belongs to a pure java library that is integrated into android later. ML-Kit apparantly cannot be used in Java projects. It only works if I integrate ML-Kit in pure android gradle projects
I'm trying to create a multiproject using Kotlin/native and gradle in IDEA that consists of:
A backend subproject library. I want to use this library in frontend Kotlin app and also produce a native DLL that can be later used in other software. I doubt I'll need any platform specific behavior -- the most I'll interact with the system is read, write and watch a file for changes.
A frontend jvm app in Kotlin using this library as required dependency. To be more precise I'm going to write a glfw app in Kotlin that will use this lib, but that's a detail you don't have to bother with.
I want to be able to:
build DLL on it's own
build an app that depends on library and rebuilds if needed when the lib changed.
I made a hyperlink trip over gradle docs, JetBrains examples and repos but I don't quite understand how to make a multiproject like that. Can someone provide a minimal working example of such a Hello World project?
Right now this works for me in the initial stage of the project:
Use gradle init with basic type and kotlin DSL to generate a wrapper project
Add 2 modules with New > Module > Gradle > Kotlin/Multiplatform and Kotlin/JVM. That should add include("...") entries to root settings.gradle.kts At this point those modules will be empty with a single build.gradle.kts scripts
Root build.gradle.kts can be deleted - both library and app use their own
In the Multiplatform library setup at least one target for example like that:
// rootProject/library/build.gradle.kts
// ...
kotlin {
jvm() // used by jvm app
sourceSets { /*...*/ }
}
Now there should be no gradle errors and IDEA will detect the project properly - refresh gradle configuration (CTRL+SHIFT+O)
Create source directories for each module (because the modules rn): IDEA should hint the names of corresponding source sets (src/<target>/<kotlin|resources> etc.)
So now just to link the app and library together in the the app's buildscript add the implementation(project(":library")) dependency
Of course don't forget to configure the library target for example using linuxX64("native") { binaries { sharedLib {/*...*/ } } } block in kotlin plugin when trying to generate a DLL
Now it should mostly work. The structure of a project I'm working on rn looks like that:
Upon reading the README file of barcode_scan plugin I encountered the instruction
This plugin is written in Kotlin. Therefore, you need to add Kotlin
support to your project. See installing the Kotlin plugin.
The link only provides information about creating Kotlin project in Android Studio. How does one add Kotlin support for a flutter project? Is it even necessary?
EDIT: Since I already have an existing flutter package, I am looking for ways to add Kotlin support to that project
You simply have to add a single file in Kotlin format (example under android>main>java>your packagename>test.kt and it will automatically upgrade. Can be an empty file. Add it using android studio. answer reference: https://github.com/mintware-de/flutter_barcode_reader/issues/121
Doing it manually:
Check if you need to do this:
https://github.com/flutter/flutter/wiki/Upgrading-pre-1.12-Android-projects
Next create a new flutter project for reference and call it myapp.
Next, from myapp/android/build.gradle copy:
ext.kotlin_version = '1.3.50'
and
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
Next, from myapp/android/app/build.gradle copy:
apply plugin: 'kotlin-android'
and
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
and
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
Next, create the path according to you package path and copy the file myapp/android/app/src/main/kotlin/com/example/myapp/MainActivity.kt
Next, in the file MainActivity.kt replace 'package com.example.myapp' with your package.
Next, if MainActivity.java is an empty class then just delete it under ../android/app/src/main/java/..
but if it is not then you will need change the class and its body to kotlin, copy it and only then delete it.
tl;dr: I cannot configure IntelliJ to generate the java files in the same directory as gradle
I have a small project which uses the immutables annotation processor.
It works as expected in the gradle command line build, but I cannot get IntelliJ to output the generated files to the same directory.
The full project is available on GitLab
Gradle config:
I use the folowing gradle plugins:
gradle-idea plugin which handles the idea configuration
gradle-apt-plugin which provides the apt configuration and handles the compile-class path and idea config related to annotation processing (if also the idea plugin is applied)
relevant parts of the build-script (link to the full listing):
apply plugin: 'java'
apply plugin: "net.ltgt.apt"
apply plugin: 'idea'
dependencies {
def immutablesVersion = '2.3.9'
compileOnly "org.immutables:value:$immutablesVersion:annotations"
compileOnly "org.immutables:encode:$immutablesVersion"
apt "org.immutables:value:$immutablesVersion"
}
when I start ./gradlew build everything is as expected:
The source file DataEncoding.java is processed an the generated java-file DataEncodingEnabled.java ends up in
/build/generated/source/apt/main under the expected package com.tmtron.immutables.data
and the generated file is also compiled to a .class file
In IntelliJ I activate the annotation processing as suggested by the gradle-apt-plugin docs:
Then I execute ./gradlew clean to make sure, that the previous files are gone and then I click Build - Build Project in IntelliJ.
The annotation processor is executed, but the problem is that the generated java file ends up in the wrong location:
It is in: /build/generated/source/apt/main/build/generated/source/apt/main/com.tmtron.immutables.data
the bold part is redundant.
What am I doing wrong and how can I set it up correctly, so that IntelliJ and gradle generate the files in the same directory?
Notes:
I have of course already tried to just leave the "Production sources dir" in the IntelliJ annotation configuration empty, but his does not work: then it automatically uses "generated" and I also end up with a wrong path.
IntelliJ version 2016.3.4
Now https://github.com/tbroyer/gradle-apt-plugin states:
The goal of this plugin was to eventually no longer be needed, being superseded by built-in features. This is becoming a reality with Gradle 5.2 and IntelliJ IDEA 2019.1.
So:
dependencies {
compile("com.google.dagger:dagger:2.18")
annotationProcessor("com.google.dagger:dagger-compiler:2.18")
compileOnly("com.google.auto.factory:auto-factory:1.0-beta6")
annotationProcessor("com.google.auto.factory:auto-factory:1.0-beta6")
compileOnly("org.immutables:value-annotations:2.7.1")
annotationProcessor("org.immutables:value:2.7.1")
}
compileOnly is necessary if you use annotations, compile if you use classes, annotationProcessor introduced in Gradle 4.6.
To enable processing specific compile task:
compileJava {
options.annotationProcessorPath = configurations.annotationProcessor
}
To disable:
compileTestJava {
options.compilerArgs += '-proc:none'
}
UPDATE 2.2019
since Gradle 5.2 there is an easy way to do it - see gavenkoas answer
UPDATE 5.2018
The easiest way, I know of is to use the apt-idea plugin
Just activate the plugin in the build.gradle file:
plugins {
id 'java'
id 'net.ltgt.apt-idea' version "0.15"
}
and then add the annotation processors to the annotationProcessor configuration:
final DAGGER_VER = '2.16'
dependencies {
implementation "com.google.dagger:dagger:${DAGGER_VER}"
annotationProcessor"com.google.dagger:dagger-compiler:${DAGGER_VER}"
}
Test-project on GitHub: ex.dagger
(using IntelliJ 2018.1.4, Gradle 4.7)
ORIG ANSWER
There's a simple workaround using the parent-dir which works fine in IntelliJ 2016.3.4
Production sources directory: ../main
Test sources directory: ../test
Now gradle and IntelliJ will generate the code to the same directories.
Fixed in GitLab project V0.0.2
see also: apt-gradle-plugin issue#35
Hey there everyone I had the same issue and found a clean way of solving this issue.
I am using two libraries that require annotation processing (Lombok and MapStruct).
Also my IntelliJ is 2019.1 (update yours in case it's older) and Gradle 5.2.1.
First let's configure IntelliJ:
Disable Annotaion Processing in Settings, since we're going to delegate everything to Gradle:
Delegeate IDE actions to Gradle:
Last step is to configure your dependencies correctly in Gradle.
Dependencies section in Gradle:
Now you can execute the Build and Run from both command line and IDE.
Cheers!
2019.2.x
Disable annotation processor of intellij
add, build directory in your gradle build.gradle file
then run your gradle task to generate build file classes, example gradle compileJava
File -> project structure -> Modules -> Main Folder || remove exclude and add as source
And project should find all annotation and generated source file. Hope it helps.