Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,45 +9,55 @@ import org.jetbrains.dokka.DokkaBootstrapImpl
import org.jetbrains.dokka.DokkaConfiguration
import org.jetbrains.dokka.toCompactJsonString
import java.io.File
import java.lang.reflect.InvocationTargetException
import java.net.URLClassLoader
import java.util.concurrent.atomic.AtomicReference
import java.util.function.BiConsumer
import kotlin.reflect.KClass

internal fun DokkaBootstrap(classpath: Set<File>, bootstrapClass: KClass<out DokkaBootstrap>): DokkaBootstrap {
val runtimeClassLoader = URLClassLoader(
return DokkaBootstrapProxy(classpath, bootstrapClass)
}

private class DokkaBootstrapProxy(
classpath: Set<File>,
bootstrapClass: KClass<out DokkaBootstrap>
) : DokkaBootstrap {
private val runtimeClassLoader = URLClassLoader(
classpath.map { it.toURI().toURL() }.toTypedArray(),
ClassLoader.getSystemClassLoader().parent
)

val runtimeClassloaderBootstrapClass = runtimeClassLoader.loadClass(bootstrapClass.qualifiedName)
val runtimeClassloaderBootstrapInstance = runtimeClassloaderBootstrapClass.constructors.first().newInstance()
private val runtimeClassloaderBootstrapClass = runtimeClassLoader.loadClass(bootstrapClass.qualifiedName)
private val runtimeClassloaderBootstrapInstance =
runtimeClassloaderBootstrapClass.constructors.first().newInstance()

return object : DokkaBootstrap {
override fun configure(
serializedConfigurationJSON: String,
logger: BiConsumer<String, String>
) {
val configureMethod = runtimeClassloaderBootstrapClass.getMethod(
"configure",
String::class.java,
BiConsumer::class.java // Use java.util.function.BiConsumer from *your* loader
)
configureMethod.invoke(
runtimeClassloaderBootstrapInstance,
serializedConfigurationJSON,
logger
)
}
private fun invokeMethod(
name: String,
parameterTypes: Array<Class<*>>,
args: Array<Any?>
): Any? = try {
runtimeClassloaderBootstrapClass
.getMethod(name, *parameterTypes)
.invoke(runtimeClassloaderBootstrapInstance, *args)
} catch (e: InvocationTargetException) {
throw e.targetException
}

override fun generate() {
val generateMethod = runtimeClassloaderBootstrapClass.getMethod(
"generate",
)
generateMethod.invoke(
runtimeClassloaderBootstrapInstance
)
}
override fun configure(serializedConfigurationJSON: String, logger: BiConsumer<String, String>) {
invokeMethod(
name = "configure",
parameterTypes = arrayOf(String::class.java, BiConsumer::class.java),
args = arrayOf(serializedConfigurationJSON, logger)
)
}

override fun generate() {
invokeMethod(
name = "generate",
parameterTypes = emptyArray(),
args = emptyArray()
)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2014-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package org.jetbrains.dokka.gradle

import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.string.shouldContain
import org.jetbrains.dokka.gradle.internal.DokkaConstants.DOKKA_VERSION
import org.jetbrains.dokka.gradle.utils.*

class DokkaGeneratorFailureTest : FunSpec({
context("DokkaGenerator failure:") {
val project = gradleKtsProjectTest("dokka-generator-failure") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make this test more straightforward? Or even add one more with a custom exception/pre-generation check?
For example, if intersecting roots are allowed in the future, this case could be lost.
See the original test

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, nice idea!
I will add an additional test similar to the previous one.

It would still be nice to have a functional test for DGP, so that we really show the exception from checks or just failures here.

buildGradleKts = """
|plugins {
| kotlin("jvm") version embeddedKotlinVersion
| id("org.jetbrains.dokka") version "$DOKKA_VERSION"
|}
|
|dokka {
| dokkaSourceSets.configureEach {
| suppress = false // to enable documentation for `test` source set
| sourceRoots.from("src/shared/kotlin") // causes an error in Dokka generator checker
| }
|}
|
""".trimMargin()

createKotlinFile("src/main/kotlin/Main.kt", "class Main")
createKotlinFile("src/test/kotlin/Test.kt", "class Test")
createKotlinFile("src/shared/kotlin/Shared.kt", "class Shared")
}

test("expect failure message from checkers to be shown by default") {
project.runner
.addArguments(
":dokkaGenerateModuleHtml",
"--rerun",
)
.buildAndFail {
output shouldContain "Pre-generation validity check failed"
output shouldContain "Source sets 'java' and 'javaTest' have the common source roots"
}

project.runner
.addArguments(
":dokkaGeneratePublicationHtml",
"--rerun",
)
.buildAndFail {
output shouldContain "Pre-generation validity check failed"
output shouldContain "Source sets 'java' and 'javaTest' have the common source roots"
}
}
}
})
Loading