Kotlin / dokka

API documentation engine for Kotlin
https://kotl.in/dokka
Apache License 2.0
3.43k stars 407 forks source link

dokkaHtml fails: java.lang.NoSuchMethodError: 'void com.fasterxml.jackson.databind.type.TypeFactory.<init>(com.fasterxml.jackson.databind.util.LRUMap)' #3472

Open Javaru opened 8 months ago

Javaru commented 8 months ago

Describe the bug Dokka dokkaHtml gradle task fails when project includes Jackson BOM version 2.16.0 or higher. (Build is successful with v2.15.3 or lower). The root cause of the failure is: Caused by: java.lang.NoSuchMethodError: 'void com.fasterxml.jackson.databind.type.TypeFactory.<init>(com.fasterxml.jackson.databind.util.LRUMap)' Full stacktrace is below.

Expected behaviour The build should be successful (and is with Jackson v2.15.3 or lower).

Screenshots Gradle build failure when run with --stacktrace option:

FAILURE: Build completed with 2 failures.

1: Task failed with an exception.
-----------
* What went wrong:
Execution failed for task ':redacted-project-name:dokkaHtml'.
> 'void com.fasterxml.jackson.databind.type.TypeFactory.<init>(com.fasterxml.jackson.databind.util.LRUMap)'

* Try:
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.

* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':redacted-project-name:dokkaHtml'.
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.lambda$executeIfValid$1(ExecuteActionsTaskExecuter.java:142)
    at org.gradle.internal.Try$Failure.ifSuccessfulOrElse(Try.java:282)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:140)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:128)
    at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:77)
    at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
    at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51)
    at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
    at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)
    at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
    at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
    at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
    at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
    at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
    at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
    at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
    at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
    at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
    at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
    at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
    at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
    at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:69)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:327)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:314)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:307)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:293)
    at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:420)
    at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:342)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
    at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
Caused by: java.lang.NoSuchMethodError: 'void com.fasterxml.jackson.databind.type.TypeFactory.<init>(com.fasterxml.jackson.databind.util.LRUMap)'
    at org.jetbrains.dokka.base.templating.PluginTypeFactory.<init>(jsonMapperForPlugins.kt:59)
    at org.jetbrains.dokka.base.templating.JsonMapperForPluginsKt.<clinit>(jsonMapperForPlugins.kt:27)
    at org.jetbrains.dokka.base.renderers.html.SourcesetDependencyAppender$invoke$1.invoke(htmlPreprocessors.kt:157)
    at org.jetbrains.dokka.base.renderers.html.SourcesetDependencyAppender.invoke(htmlPreprocessors.kt:164)
    at org.jetbrains.dokka.base.renderers.DefaultRenderer.render(DefaultRenderer.kt:226)
    at org.jetbrains.dokka.base.renderers.html.HtmlRenderer.render(HtmlRenderer.kt:895)
    at org.jetbrains.dokka.base.generation.SingleModuleGeneration.render(SingleModuleGeneration.kt:88)
    at org.jetbrains.dokka.base.generation.SingleModuleGeneration.generate(SingleModuleGeneration.kt:54)
    at org.jetbrains.dokka.DokkaGenerator$generate$1.invoke(DokkaGenerator.kt:34)
    at org.jetbrains.dokka.DokkaGenerator$generate$1.invoke(DokkaGenerator.kt:21)
    at org.jetbrains.dokka.DokkaGeneratorKt.timed(DokkaGenerator.kt:82)
    at org.jetbrains.dokka.DokkaGeneratorKt.access$timed(DokkaGenerator.kt:1)
    at org.jetbrains.dokka.DokkaGenerator.generate(DokkaGenerator.kt:27)
    at org.jetbrains.dokka.DokkaBootstrapImpl.generate(DokkaBootstrapImpl.kt:67)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.jetbrains.dokka.gradle.DelegatedInvocationHandler.invoke(automagicTypedProxy.kt:44)
    at jdk.proxy13/jdk.proxy13.$Proxy191.generate(Unknown Source)
    at org.jetbrains.dokka.gradle.AbstractDokkaTask$generateDocumentation$1$1.run(AbstractDokkaTask.kt:217)

==============================================================================

2: Task failed with an exception.
-----------
* What went wrong:
java.lang.StackOverflowError (no error message)

* Try:
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.

* Exception is:
java.lang.StackOverflowError
    at org.gradle.execution.plan.FinalizerGroup.isCanCancel(FinalizerGroup.java:153)
    at org.gradle.execution.plan.CompositeNodeGroup.isCanCancel(CompositeNodeGroup.java:101)
    at org.gradle.execution.plan.Node.isCanCancel(Node.java:232)
    at org.gradle.execution.plan.FinalizerGroup.isCanCancel(FinalizerGroup.java:155)
    at org.gradle.execution.plan.CompositeNodeGroup.isCanCancel(CompositeNodeGroup.java:101)
    at org.gradle.execution.plan.Node.isCanCancel(Node.java:232)
    at org.gradle.execution.plan.FinalizerGroup.isCanCancel(FinalizerGroup.java:155)
    at org.gradle.execution.plan.CompositeNodeGroup.isCanCancel(CompositeNodeGroup.java:101)
    at org.gradle.execution.plan.Node.isCanCancel(Node.java:232)
    at org.gradle.execution.plan.FinalizerGroup.isCanCancel(FinalizerGroup.java:155)
        < SNIP >
    at org.gradle.execution.plan.CompositeNodeGroup.isCanCancel(CompositeNodeGroup.java:101)
    at org.gradle.execution.plan.Node.isCanCancel(Node.java:232)
    at org.gradle.execution.plan.FinalizerGroup.isCanCancel(FinalizerGroup.java:155)

==============================================================================

* Get more help at https://help.gradle.org

BUILD FAILED in 24s

To Reproduce In a project that has Jackson v2.16.0 or later BOM declared, run the dokkaHtml task, or a task that subsequently runs it such as publishToMavenLocal. I've attached a minimalist.zip gradle project that reproduces the issue. If you change the Jackson BOM to v2.15.3 or earlier, the build is successful.

Dokka configuration Also see attached minimalist.zip gradle project that reproduces the issue.

plugins {
    val kotlinVersion = "1.9.22"
    kotlin("jvm") version kotlinVersion
    kotlin("plugin.spring") version kotlinVersion
    id("org.jetbrains.dokka") version "1.9.10"
    java
    // . . .
}
// . . .
    val dokkaJavadocJar by tasks.register<Jar>("dokkaJavadocJar") {
        dependsOn(tasks.dokkaJavadoc)
        from(tasks.dokkaJavadoc.flatMap { it.outputDirectory })
        archiveClassifier.set("javadoc")
    }

    val dokkaHtmlJar by tasks.register<Jar>("dokkaHtmlJar") {
        dependsOn(tasks.dokkaHtml)
        from(tasks.dokkaHtml.flatMap { it.outputDirectory })
        archiveClassifier.set("html-doc")
    }
// . . .
    publishing {
        publications {
            create<MavenPublication>("mavenJava") {
                from(components["java"])
                artifact(dokkaJavadocJar)
                artifact(dokkaHtmlJar)
                pom {
                    // . . .
                }
            }
        }
        repositories {
            // . . .
        }
    }    

Installation

Additional context None minimalist.zip example project

whyoleg commented 8 months ago

Hey! I've checked the project that you attached. And here what I could say:

  1. Dokka is currently built with old Jackson version because of compatibility with Gradle (more info here). And looks like all Jackson versions up to 2.15.3 are compatible with version used in Dokka, but 2.16.1 is not - that's why using Dokka with Jackson 2.16.1 is not possible right now.
  2. As far as I understand BOMs are managed by io.spring.dependency-management plugin in your example. As I see by using imports { mavenBom(...) } it will enforce ALL configurations in a project to use this version (not only runtime but also created by other Gradle plugins, like Dokka).

Here is a possible workaround of how to override Jackson version for Dokka, until it doesn't support latest Jackson out of the box (you need to put it near dependencyManagement/dependencies block):

configurations.matching { it.name.startsWith("dokka") }.configureEach {
    resolutionStrategy.eachDependency {
        if (requested.group.startsWith("com.fasterxml.jackson")) {
            useVersion("2.15.3")
        }
    }
}

Hope this helps!

While we are here, could you please tell us: why do you need to publish both HTML and Javadoc artifacts produced by Dokka?

Javaru commented 8 months ago

@whyoleg Thank you for the reply. Your workaround works beautifully. I did not think of doing something like that. (Likely because my Gradle skills are still those of an intermediate user and not a power user.) So thank you for gong the extra mile and providing that workaround. It is very much appreciated.

I'll leave it to your discretion if you want to close this ticket or keep it open, based on the project's needs.

could you please tell us: why do you need to publish both HTML and Javadoc artifacts produced by Dokka?

Basically it's a traditional state. We have both legacy Java project with new development done in Kotlin, and new projects that are 100% Kotlin. Our old school Java developers are just familiar with the Javadoc format after using it for anywhere form 10 to 25 years and prefer it; especially for the legacy projects that are 99% Java. But we are working on transitioning to the Dokka HTML based documentation. So for now, we publish both so folks can evaluate and/or use the Dokka HTML format while still having the traditional Javadoc format available.

Prodigio commented 2 months ago

Hey! I've checked the project that you attached. And here what I could say:

1. Dokka is currently built with old Jackson version because of compatibility with Gradle (more info [here](https://github.com/Kotlin/dokka/issues/3194#issuecomment-1929382630)). And looks like all Jackson versions up to 2.15.3 are compatible with version used in Dokka, but 2.16.1 is not - that's why using Dokka with Jackson 2.16.1 is not possible right now.

2. As far as I understand BOMs are managed by `io.spring.dependency-management` plugin in your example. As I see by using `imports { mavenBom(...) }` it will enforce ALL configurations in a project to use this version (not only runtime but also created by other Gradle plugins, like Dokka).

Here is a possible workaround of how to override Jackson version for Dokka, until it doesn't support latest Jackson out of the box (you need to put it near dependencyManagement/dependencies block):

configurations.matching { it.name.startsWith("dokka") }.configureEach {
    resolutionStrategy.eachDependency {
        if (requested.group.startsWith("com.fasterxml.jackson")) {
            useVersion("2.15.3")
        }
    }
}

Hope this helps!

While we are here, could you please tell us: why do you need to publish both HTML and Javadoc artifacts produced by Dokka?

I tried this approach and did fixed the first exception reported by issue creator. But now I cannot run my jacocoToCobertura task anymore, because of this exception:

> net.razvan.JacocoToCoberturaException: Loading Jacoco report error: `(was java.io.FileNotFoundException) C:\Users\<user>\.gradle\daemon\8.8\report.dtd (The system cannot find the file specified)
   at [row,col {unknown-source}]: [1,124]`

I guess I somehow force the dependency version 2.15.3 to all other dependencies, not just Dokka? I'm not an expert in Gradle yet.

Any hints on this? Thanks in advance!