ScaCap / spring-auto-restdocs

Spring Auto REST Docs is an extension to Spring REST Docs
https://scacap.github.io/spring-auto-restdocs/
Apache License 2.0
310 stars 86 forks source link

Auto Rest Doc 2.0.10 java.lang.NoClassDefFoundError #410

Closed dekar91 closed 4 years ago

dekar91 commented 4 years ago

HI! I user Dpring Boot and Junit5. I've configured my project closer to kotlin-mvc example:

build.gradle:

buildscript {
    ext {
        kotlinVersion = "1.4.0"
        springAutoRestDocsVersion = "2.0.10-SNAPSHOT"
        springRestDocsVersion = "2.0.4.RELEASE"
        springBootVersion = "2.3.0.RELEASE"
        dokkaPluginVersion = "0.10.1"
    }

    repositories {

        jcenter()
        mavenLocal()
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion"
        classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlinVersion"
        classpath "org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion"
        classpath "org.asciidoctor:asciidoctor-gradle-plugin:1.5.9.2"
        classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokkaPluginVersion"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
    }
}
plugins {
    id 'org.asciidoctor.jvm.base' version '3.2.0'
    id 'org.asciidoctor.jvm.convert' version '3.2.0'

    id 'org.liquibase.gradle' version '2.0.4'
    id 'org.springframework.boot' version '2.4.0-M1'
    id 'io.spring.dependency-management' version '1.0.9.RELEASE'
    id 'java'
}

apply plugin: "org.jetbrains.dokka"

sourceCompatibility = '13'

configurations {

    compileOnly {
        extendsFrom annotationProcessor
    }

}

repositories {
    mavenCentral()
    maven { url 'https://repo.spring.io/milestone' }
    maven { url 'https://repo.spring.io/snapshot' }

    maven {
        url "https://oss.sonatype.org/content/repositories/snapshots"
    }

    maven { url 'https://dl.bintray.com/kotlin/dokka' }
    maven { url 'https://jitpack.io' }

}

configurations {
    dokkaFatJar
}

ext {
    set('springCloudVersion', "2020.0.0-SNAPSHOT")
}

apply plugin: 'kotlin'

dependencies {

    implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.11.+"

    // Documentation
    implementation "io.springfox:springfox-boot-starter:3.0.0"
    testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
    implementation "com.fasterxml.jackson.module:jackson-module-kotlin"
    implementation "capital.scalable:spring-auto-restdocs-core:$springAutoRestDocsVersion"
    dokkaFatJar "org.jetbrains.dokka:dokka-gradle-plugin:0.9.16"
    dokkaFatJar "capital.scalable:spring-auto-restdocs-dokka-json:$springAutoRestDocsVersion"

    dokkaRuntime "capital.scalable:spring-auto-restdocs-dokka-json:$springAutoRestDocsVersion"
    dokkaRuntime "org.jetbrains.dokka:dokka-fatjar:0.10.1"

    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-validation'

    runtimeOnly 'org.postgresql:postgresql'
    annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'

    implementation 'org.springframework.boot:spring-boot-starter-security'
    testImplementation 'io.projectreactor:reactor-test'
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"

    // Tests
    testImplementation("org.springframework.boot:spring-boot-starter-test") {
        exclude(module: "commons-logging")
    }
    testImplementation "com.jayway.jsonpath:json-path-assert"
    testImplementation "org.springframework.restdocs:spring-restdocs-core:$springRestDocsVersion"
    testImplementation "org.springframework.restdocs:spring-restdocs-mockmvc:$springRestDocsVersion"
    dokkaRuntime "capital.scalable:spring-auto-restdocs-dokka-json:$springAutoRestDocsVersion"

    testImplementation 'org.springframework.security:spring-security-test'

}

ext {
    javadocJsonDir = file("$buildDir/generated-javadoc-json")
}

test {
    systemProperty 'org.springframework.restdocs.outputDir', snippetsDir

    systemProperty "org.springframework.restdocs.javadocJsonDir", javadocJsonDir

    dependsOn dokka
}

test {
    outputs.dir snippetsDir
}

bootJar {
    dependsOn asciidoctor
    from("${asciidoctor.outputDir}/") {
        into 'static/docs'
    }
}

test {
    useJUnitPlatform()
}
compileKotlin {
    kotlinOptions {
        jvmTarget = "1.8"
    }
}
compileTestKotlin {
    kotlinOptions {
        jvmTarget = "1.8"
    }
}

task repackDokka(type: Jar) {
    destinationDir = file("$buildDir/dokka-repack")
    baseName = "dokkaFatJarRepack"
    from configurations.dokkaFatJar.collect { zipTree(it) }
}

dokka {
    dependsOn repackDokka

    outputFormat = "auto-restdocs-json"
    outputDirectory = javadocJsonDir
    configuration {
        includeNonPublic = true
        reportUndocumented = false
    }
}
@ExtendWith(RestDocumentationExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class ApiControllerTest {
// Autowires

    public void setUp() throws Exception {
        this.mockMvc = MockMvcBuilders
                .webAppContextSetup(context)
                .addFilters(springSecurityFilterChain)
                .alwaysDo(prepareJackson(objectMapper, new TypeMapping())) // custom
                .alwaysDo(commonDocumentation())
                .apply(documentationConfiguration(restDocumentation)
                        .uris()
                        .withScheme("http")
                        .withHost("localhost")
                        .withPort(8080)
                        .and().snippets()
                        .withDefaults(curlRequest(), httpRequest(), httpResponse(),
                                requestFields(), responseFields(), pathParameters(),
                                requestParameters(), description(), methodAndPath(),
                                section(), links(), embedded(), authorization(DEFAULT_AUTHORIZATION),
                                modelAttribute(requestMappingHandlerAdapter.getArgumentResolvers())))
                .build();
    }

// Tests

}

But should I try to run tests I get an error:

org/junit/rules/TestRule
java.lang.NoClassDefFoundError: org/junit/rules/TestRule
    at java.base/java.lang.ClassLoader.defineClass1(Native Method)
    at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)
    at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:151)
    at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:821)
    at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:719)
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:642)
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:600)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
    at java.base/java.lang.Class.getDeclaredFields0(Native Method)
    at java.base/java.lang.Class.privateGetDeclaredFields(Class.java:3062)
    at java.base/java.lang.Class.getDeclaredFields(Class.java:2249)
    at org.junit.platform.commons.util.ReflectionUtils.getDeclaredFields(ReflectionUtils.java:1392)
    at org.junit.platform.commons.util.ReflectionUtils.findAllFieldsInHierarchy(ReflectionUtils.java:1150)
    at org.junit.platform.commons.util.ReflectionUtils.findFields(ReflectionUtils.java:1138)
    at org.junit.platform.commons.util.AnnotationUtils.findAnnotatedFields(AnnotationUtils.java:371)
    at org.junit.platform.commons.util.AnnotationUtils.findAnnotatedFields(AnnotationUtils.java:348)
    at org.junit.jupiter.engine.descriptor.ExtensionUtils.registerExtensionsFromFields(ExtensionUtils.java:99)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.prepare(ClassBasedTestDescriptor.java:148)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.prepare(ClassBasedTestDescriptor.java:78)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$1(NodeTestTask.java:107)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:107)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:75)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1507)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
    at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211)
    at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
    at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
    at com.sun.proxy.$Proxy2.stop(Unknown Source)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:132)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
    at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:413)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
    at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
    at java.base/java.lang.Thread.run(Thread.java:830)
Caused by: java.lang.ClassNotFoundException: org.junit.rules.TestRule
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:602)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)

How could I fix it?

fbenz commented 4 years ago

How are you setting the restDocumentation field? In the Kotlin WebMVC example project it's done via a JUnit 4 rule:

    @get:Rule
    val restDocumentation = JUnitRestDocumentation()

However, a JUnit 4 rule does not work in a JUnit 5 test. The exception is reporting that a JUnit 4 rule is used somewhere.

We use the following pattern for JUnit 5. It's provided via the extension

    @BeforeEach
    fun setUp(restDocumentation: RestDocumentationContextProvider) {
...
        mockMvc = MockMvcBuilders
...
            .apply<StandaloneMockMvcBuilder>(
                MockMvcRestDocumentation.documentationConfiguration(restDocumentation)

I also don't think that you need @AutoConfigureMockMvc if you create it yourself in the setUp method.

dekar91 commented 4 years ago

Seems i made the same. Removing @AutoConfigureMockMvc does not change anything. I pushed my test project here https://github.com/dekar91/autorest_test I've removed liquibase and all that does not make sense to make project readable.

fbenz commented 4 years ago

You are using the JUnit 4 test rule JUnitRestDocumentation: https://github.com/dekar91/autorest_test/blob/master/src/test/java/com/example/analyzer/ApiControllerTest.java#L54 So removing this line and changing setUp to setUp(restDocumentation: RestDocumentationContextProvider) should fix it.

dekar91 commented 4 years ago

How it does work. Thanks!