How to add Realm's Classpath to Gradle's Javadoc Classpath Variable - android

I am trying to use Gradle to generate a Javadoc for my Android Library Project. Right now I have included Android's Source Classpath to Gradle's Classpath variable that Gradle uses to generate the Javadoc.
task generateJavadoc(type: Javadoc) {
source = android.sourceSets.main.java.srcDirs
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
destinationDir = reporting.file("api-docs")
}
But when I run the task it gives an error that it cannot find the symbol #Ignore which is an annotation provided by Realm.
symbol: class Ignore
location: class TreatmentPlan
/Documents/Repo/calendar_android/calendar/src/main/java/com/company/calendar/Calendar.java:49: error: cannot find symbol
#Ignore
^
I am assuming that since I have not included Realm's Classpath inside my Gradle task, that gradle doesn't know how to generate a javadoc for the annotation.
How can I include Realm's classpath in my gradle task?

Related

Cannot publish library due to javadoc task errors

I have a library I'm trying to publish using the bintray plugin's bintrayUpload task. When the script runs the javadoc task, it is filled with many errors, because the javadoc task evidently cannot read references to classes in dependencies of my library module. For example:
error: package androidx.preference does not exist
import androidx.preference.Preference;
When I run gradlew javadoc, it completes without errors. I'm not sure exactly how the bintrayUpload task operates. Is it calling that same javadoc task that I am? And either way, how do I configure it to be able to see the classes of my dependencies from androidx?
In my top level build.gradle:
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.0'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4'
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
}
}
In my library module's build.gradle:
apply from: '../bintray-setup.gradle'

Android gradle runtimeClasspath equivalent

The gradle java plugin has a FileCollection property which contains the runtime classes - sourcesets.main.runtimeClasspath.
Is there an equivalent within the com.android.application plugin?
What I've found is that the destinationDir property of applicationVariants can be appended to the javaCompile.classpath property, which will result in a FileCollection which contains the dependency classpaths and the compiled classes.
My use case is trying to run a java executable post-compile:
afterEvaluate {
android.applicationVariants.each { variant ->
variant.javaCompile.doLast {
javaexec {
classpath += variant.javaCompile.classpath
classpath += files(variant.javaCompile.destinationDir)
main = 'com.mydomain.Main'
}
}
}
}
Tested on Android Studio 2.1.1 running 'com.android.tools.build:gradle:2.1.0' and gradle 2.10.
Reference: http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Shrinking-Resources

How to generate javadoc for android library when it has dependencies which are also aar libraries?

I have android library project which depends on other android library projects. I need to generate javadoc for library but it fails because gradle puts to javadoc classpath path to .aar locations but javadoc expects .jar files.
simplified gradle file:
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
configurations {
javadocDeps
}
defaultConfig {
minSdkVersion 7
targetSdkVersion 23
versionCode 1
versionName "0.1.0"
}
}
dependencies {
compile 'com.android.support:support-v4:23.2.0'
compile 'com.android.support:appcompat-v7:23.2.0'
compile 'com.nineoldandroids:library:2.4.0'
compile 'com.annimon:stream:1.0.7'
javadocDeps 'com.android.support:support-annotations:23.2.0'
javadocDeps 'com.nineoldandroids:library:2.4.0'
javadocDeps 'com.android.support:support-v4:23.2.0'
}
task sourcesJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
classifier = 'sources'
}
task javadoc(type: Javadoc, dependsOn: explodeAars) {
source = android.sourceSets.main.java.srcDirs
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
classpath += configurations.javadocDeps
}
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}
artifacts {
archives javadocJar
archives sourcesJar
}
3 solutions possible:
1) somehow to add to the classpath path classes.jar from every aar library it depends build/intermidiates/exploded-aar/library/version/jars/classes.jar
I don't know how to include these paths in javadoc task.
2) manually unpack classes.jar from aar file and add them to classpath of javadoc task
3) very dirty hack - hardcoded paths to library - but I think this is so WRONG.
How to achieve 1 or 2 with gradle dsl?
I managed to automate the solution of Guillaume Perrot by extracting the classes.jar contained in each AAR file, and adding it to the classpath of the javadoc task.
It seems to work for AAR dependencies and AAR modules on Android Studio 2.3 and Gradle 3.3
import java.nio.file.Files
import java.nio.file.Paths
import java.io.FileOutputStream
import java.util.zip.ZipFile
task javadoc(type: Javadoc) {
source = android.sourceSets.main.java.srcDirs
classpath += configurations.compile
classpath += configurations.provided
afterEvaluate {
// Wait after evaluation to add the android classpath
// to avoid "buildToolsVersion is not specified" error
classpath += files(android.getBootClasspath())
// Process AAR dependencies
def aarDependencies = classpath.filter { it.name.endsWith('.aar') }
classpath -= aarDependencies
aarDependencies.each { aar ->
// Extract classes.jar from the AAR dependency, and add it to the javadoc classpath
def outputPath = "$buildDir/tmp/aarJar/${aar.name.replace('.aar', '.jar')}"
classpath += files(outputPath)
// Use a task so the actual extraction only happens before the javadoc task is run
dependsOn task(name: "extract ${aar.name}").doLast {
extractEntry(aar, 'classes.jar', outputPath)
}
}
}
}
// Utility method to extract only one entry in a zip file
private def extractEntry(archive, entryPath, outputPath) {
if (!archive.exists()) {
throw new GradleException("archive $archive not found")
}
def zip = new ZipFile(archive)
zip.entries().each {
if (it.name == entryPath) {
def path = Paths.get(outputPath)
if (!Files.exists(path)) {
Files.createDirectories(path.getParent())
Files.copy(zip.getInputStream(it), path)
}
}
}
zip.close()
}
The solution from #rve is now broken on Android Studio 2.3 / Gradle 3.3 as the exploded-aar no longer exists (with no alternative inside the build directory).
If the aar you depend on is not a module in your project, you will need first to extract the classes.jar before referencing it in the classpath (basically re-create intermediates/exploded-aar manually).
If the aar you depend on is just another module in your project you can also make your javadoc task depends on the compile task of that module and reference the intermediates/classes/release of that module (if you make javadoc depends on assembleRelease for example). An example of that workaround: https://github.com/Microsoft/mobile-center-sdk-android/pull/345/files
I really wish someone comes up with a better solution though.
This only works for Android Studio older than 2.3 and/or Gradle older than 3.3
To add the JARs from the AARs you can add the following doFirst to the javadoc task:
task javadoc(type: Javadoc) {
source = android.sourceSets.main.java.srcDirs
}
.doFirst {
classpath += fileTree(dir: "$buildDir/intermediates/exploded-aar/", include:"**/classes.jar")
}
It will add all .jar files from all the AARs to the javadoc classpath. (option 1 from your proposed solutions)
This is how I solved this issue, using zipTree. Configuration: Gradle 4.10, Gradle Plugin: 3.3.2, Android Studio: 3.4.
task javadoc(type: Javadoc) {
doFirst {
configurations.implementation
.filter { it.name.endsWith('.aar') }
.each { aar ->
copy {
from zipTree(aar)
include "**/classes.jar"
into "$buildDir/tmp/aarsToJars/${aar.name.replace('.aar', '')}/"
}
}
}
configurations.implementation.setCanBeResolved(true)
source = android.sourceSets.main.java.srcDirs
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
classpath += configurations.implementation
classpath += fileTree(dir: "$buildDir/tmp/aarsToJars/")
destinationDir = file("${project.buildDir}/outputs/javadoc/")
failOnError false
exclude '**/BuildConfig.java'
exclude '**/R.java'
}
I am running the new Android Studio 3.0-beta7, and tried to use #nicopico's answer, but it failed with a number of different errors, so here's an adaptation of it that doesn't rely on the non-existent java.nio utilities.
task javadoc(type: Javadoc) {
failOnError false
source = android.sourceSets.main.java.srcDirs
// Also add the generated R class to avoid errors...
// TODO: debug is hard-coded
source += "$buildDir/generated/source/r/debug/"
// ... but exclude the R classes from the docs
excludes += "**/R.java"
// TODO: "compile" is deprecated in Gradle 4.1,
// but "implementation" and "api" are not resolvable :(
classpath += configurations.compile
afterEvaluate {
// Wait after evaluation to add the android classpath
// to avoid "buildToolsVersion is not specified" error
classpath += files(android.getBootClasspath())
// Process AAR dependencies
def aarDependencies = classpath.filter { it.name.endsWith('.aar') }
classpath -= aarDependencies
aarDependencies.each { aar ->
System.out.println("Adding classpath for aar: " + aar.name)
// Extract classes.jar from the AAR dependency, and add it to the javadoc classpath
def outputPath = "$buildDir/tmp/exploded-aar/${aar.name.replace('.aar', '.jar')}"
classpath += files(outputPath)
// Use a task so the actual extraction only happens before the javadoc task is run
dependsOn task(name: "extract ${aar.name}").doLast {
extractEntry(aar, 'classes.jar', outputPath)
}
}
}
}
// Utility method to extract only one entry in a zip file
private def extractEntry(archive, entryPath, outputPath) {
if (!archive.exists()) {
throw new GradleException("archive $archive not found")
}
def zip = new java.util.zip.ZipFile(archive)
zip.entries().each {
if (it.name == entryPath) {
def path = new File(outputPath)
if (!path.exists()) {
path.getParentFile().mkdirs()
// Surely there's a simpler is->os utility except
// the one in java.nio.Files? Ah well...
def buf = new byte[1024]
def is = zip.getInputStream(it)
def os = new FileOutputStream(path)
def len
while ((len = is.read(buf)) != -1) {
os.write(buf, 0, len)
}
os.close()
}
}
}
zip.close()
}
It bothers me that we need all this code to produce a freaking javadoc for a library, but at least I got this working. However, I do need to find a workaround for configuration.api and configuration.implementation not being resolvable.
All of the solutions listed here are out of date if you are developing an Android app/library using Kotlin. To generate javadocs as well as documentation in several other formats, use KDoc and Dokka:
https://kotlinlang.org/docs/kotlin-doc.html
https://kotlin.github.io/dokka/1.5.0/
https://github.com/Kotlin/dokka
I posted a solution for this problem at Android AAR depending on AAR fails with javadoc generation. I think Johann comment that the listed solutions are out of date is probably correct, but mike192 solution looks pretty good, although I think it might have a problem handling androidx dependencies. I haven't tried KDoc and Dokka yet, but in looking at the documentation, that looks promising. Hopefully it works for android java libraries. The android studio's built-in javadoc tool (2021.2.1) has issues handling that module type; hence the need to build a custom javadoc task to work around those issues.

Aggregate Javadoc for Android project with multiple library modules

I've gone through almost entire Internet in search of a way how to aggregate Javadocs in the project consisting of separate library modules into single Javadoc.
There is a plugin that apparently allows to do that:
https://github.com/nebula-plugins/gradle-aggregate-javadocs-plugin
However, if I run the command specified by the plugin Gradle finds the task and executes it but no output directory is generated.
Any help how to build single Javadoc from multiple modules much appreciated.
I managed to get it working some time ago, apologies for a late response. The solution for aggregatable Javadoc creation is the following:
In each of the subprojects maintained within the project create a task generating the Javadoc:
android.libraryVariants.all { variant ->
task("generate${variant.name.capitalize()}Javadoc", type: Javadoc) {
destinationDir = project.file("$project.projectDir/javadoc/$project.PROJECT_NAME") //Project name in the Project's gradle.properties
title = "A title of my project - $project.PROJECT_VERSION_NAME" //Project version name in the Project's gradle.properties
description "Generates Javadoc for $variant.name."
source = variant.javaCompile.source
ext.androidJar ="${android.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar"
classpath = files(variant.javaCompile.classpath.files) + files(ext.androidJar) + project.files(android.getBootClasspath().join(File.pathSeparator))
options {
memberLevel = org.gradle.external.javadoc.JavadocMemberLevel.PUBLIC //change the modifier according to your needs
links "http://docs.oracle.com/javase/8/docs/api/"
linksOffline "http://d.android.com/reference", "${android.sdkDirectory}/docs/reference"
}
exclude '**/BuildConfig.java'
exclude '**/R.java'
}
task("bundle${variant.name.capitalize()}Javadoc", type: Jar) {
baseName = "Compass API - ($version)"
description "Bundles Javadoc into zip for $variant.name."
classifier = "javadoc"
from tasks["generate${variant.name.capitalize()}Javadoc"]
}
}
The configuration above adds a Javadoc generation task for each buildVariant of your subproject. At this point you can you can generate Javadoc for each module separately by typing
gradle :myRootProject:mySubproject:generateDebugJavadoc
gradle :myRootProject:mySubproject:generateReleaseJavadoc
gradle :myRootProject:mySubproject:generateMyFancyFlavourDebugJavadoc
gradle :myRootProject:mySubproject:generateMyFancyFlavourReleaseJavadoc
If you use JRE 8 the following configuration disables errors raised by doclint during the Javadoc build (explanation in greater detail here)
if (JavaVersion.current().isJava8Compatible()) {
tasks.withType(Javadoc) {
// disable the crazy super-strict doclint tool in Java 8
//noinspection SpellCheckingInspection
options.addStringOption('Xdoclint:none', '-quiet')
}
}
To aggregate Javadocs of each submodules into a single one create a Plugin in to build.gradle which will add a task to the submodule a partial Javadoc generation of which you are interested in:
class JavadocAggregationPlugin implements Plugin<Project> {
static final String AGGREGATE_JAVADOCS_TASK_NAME = 'aggregateJavadocs'
#Override
void apply(Project project) {
Project rootProject = project.rootProject
rootProject.gradle.projectsEvaluated {
Set<Project> librarySubprojects = getLibraryProjects(rootProject)
if (!librarySubprojects.isEmpty()) {
rootProject.task(AGGREGATE_JAVADOCS_TASK_NAME, type: Javadoc) {
description = 'Aggregates Javadoc API documentation of all subprojects.'
group = JavaBasePlugin.DOCUMENTATION_GROUP
dependsOn librarySubprojects.generateReleaseJavadoc //please note that generateReleaseJavadoc is the name of the separate Javadoc generation task in each library module
source librarySubprojects.generateReleaseJavadoc.source
destinationDir rootProject.file("$rootProject.buildDir/docs/javadoc") //Javadoc destination directory
classpath = rootProject.files(librarySubprojects.generateReleaseJavadoc.classpath)
}
}
}
}
private Set<Project> getLibraryProjects(Project rootProject) {
rootProject.subprojects.findAll { subproject -> subproject.plugins.findPlugin("com.android.library") } //In this case every library module is selected
}
}
Finally, include your plugin to the gradle configuration in the Project's build.gradle below your plugin definition.
apply plugin: JavadocAggregationPlugin
By doing this and rebuilding gradle's configuration you should be able to create aggregated Javadoc in specified directory by typing the following command via cli:
gradle aggregateJavadocs
Hope that helps somehow.
Helpful link: Android Gradle DSL

Gradle 'demo' project refresh failed: Could not fetch model of type 'IdeaProject' using Gradle installation

I'm trying to use new gradle android build system on my multiproject. I've library project and demo project that depends on it. I've problems with dependencies block.
Gradle 'demo' project refresh failed:
Could not fetch model of type 'IdeaProject' using Gradle installation '/Users/lia/Worktable/gradle/tools/external/gradle/gradle-1.6'.
Build file '/Users/lia/Worktable/screen-tester-android/demo/build.gradle' line: 43
A problem occurred evaluating project ':demo'.
A problem occurred evaluating project ':demo'.
No signature of method: org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.compile() is applicable for argument types: (org.gradle.api.internal.project.DefaultProject_Decorated) values: [project ':screentester']
Possible solutions: module(java.lang.Object)
Using gradle 1.6
Settings.gradle
include ':demo', ':screentester'
demo build.gradle dependencies block
dependencies {
classpath 'com.android.tools.build:gradle:0.5.+'
compile project(':screentester')
}
Is that dependencies block in buildscript? I think you are mixing the classpath of the build and the dependencies of your project. It should look something like:
// this is to configure the code running the build, ie where to find the plugin
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.5.+'
}
}
// now we configure the project itself
dependencies {
compile project(':screentester')
}

Categories

Resources