OpenAPITools / OpenAPITools/openapi-generator

java-micronaut-server And generateControllerAsAbstract=true Results in "class not found" Errors

Open
#21,089 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Java
Stars
26.8k
Forks
7.7k
PR merge metrics
PR metrics pending

Description

java-micronaut-server And generateControllerAsAbstract=true Results in "class not found" Errors

I opted to not create a [BUG] issue, since the java-micronaut-server is still listed as a Beta version.

While working on a short article that leverages and OpenAPI specification to build services, I was able to successfully use Spring Boot and Quarkus. The final article of my series focused on Micronaut and I was excited to see that an OpenAPI generator exists for this framework.

By default, the 7.12.0 version of the generator ends up creating a DefaultController which is a class. I eventually discovered the generateControllerAsAbstract=true configuration option which did introduce the AbstractDefaultController however, with this change in place I started seeing "class not found" errors. What surprised me is that errors pointed to HttpStatusException and HttpStatus - both of which were in the class path and available in my local IntelliJ instance. If I were to switch back to generateControllerAsAbstract=false, the errors went away.

I also noticed that if I provided my own api, model and invoker packages, the AbstractDefaultController appeared to ignore these settings and created the class in the org.openapitools package.

Here is my build.gradle file:

plugins {
    id("io.micronaut.application") version "4.5.0"
    id("com.gradleup.shadow") version "8.3.6"
    id("io.micronaut.aot") version "4.5.0"
    id("org.openapi.generator") version '7.12.0'
}

openApiGenerate {
    generatorName = "java-micronaut-server"
    inputSpec = "$rootDir/src/main/resources/openapi.yaml"
    outputDir = "$buildDir/generated"
    //apiPackage = "quotes.micronaut.openapi.api"
    //modelPackage = "quotes.micronaut.openapi.model"
    //invokerPackage = "quotes.micronaut.openapi.invoker"
    configOptions = [
            dateLibrary: "java8",
            useJakartaEe: "true",
            useBeanValidation: "false",
            reactive: "false",
            generateControllerAsAbstract: "true",
    ]
}

version = "0.1"
group = "quotes.micronaut"

repositories {
    mavenCentral()
}

dependencies {
    annotationProcessor("io.micronaut:micronaut-http-validation")
    annotationProcessor("io.micronaut:micronaut-inject-java")
    annotationProcessor("io.micronaut.openapi:micronaut-openapi")
    annotationProcessor("io.micronaut.serde:micronaut-serde-processor")
    annotationProcessor("io.micronaut.validation:micronaut-validation-processor")
    annotationProcessor("org.projectlombok:lombok")

    implementation("io.micronaut:micronaut-http")
    implementation("io.micronaut.security:micronaut-security-annotations")
    implementation("io.micronaut.security:micronaut-security")
    implementation("io.micronaut.serde:micronaut-serde-jackson")
    implementation("io.micronaut.validation:micronaut-validation")

    compileOnly("io.micronaut:micronaut-http-server")
    compileOnly("io.micronaut.openapi:micronaut-openapi-annotations")
    compileOnly("org.projectlombok:lombok")

    runtimeOnly("ch.qos.logback:logback-classic")

    testImplementation("io.micronaut:micronaut-http-client")
}


application {
    mainClass = "quotes.micronaut.Application"
}
java {
    sourceCompatibility = JavaVersion.toVersion("17")
    targetCompatibility = JavaVersion.toVersion("17")
}

sourceSets {
    main {
        java {
            srcDirs += "$buildDir/generated/src/main/java"
        }
    }
}

compileJava.dependsOn tasks.openApiGenerate
graalvmNative.toolchainDetection = false

micronaut {
    runtime("netty")
    testRuntime("junit5")
    processing {
        incremental(true)
        annotations("quotes.micronaut.*")
    }
    aot {
        // Please review carefully the optimizations enabled below
        // Check https://micronaut-projects.github.io/micronaut-aot/latest/guide/ for more details
        optimizeServiceLoading = false
        convertYamlToJava = false
        precomputeOperations = true
        cacheEnvironment = true
        optimizeClassLoading = true
        deduceEnvironment = true
        optimizeNetty = true
        replaceLogbackXml = true
    }
}

If interested, here's the OpenAPI Specification that I have been using for my articles:

openapi: 3.0.0
info:
  title: Motivational Quotes API
  description: An API that provides motivational quotes.
  version: 1.0.0
servers:
  - url: https://api.example.com
    description: Production server
paths:
  /quotes:
    get:
      summary: Get all motivational quotes
      operationId: getAllQuotes
      responses:
        '200':
          description: A list of motivational quotes
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Quote'
  /quotes/random:
    get:
      summary: Get a random motivational quote
      operationId: getRandomQuote
      responses:
        '200':
          description: A random motivational quote
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Quote'
  /quotes/{id}:
    get:
      summary: Get a motivational quote by ID
      operationId: getQuoteById
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: A motivational quote
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Quote'
        '404':
          description: Quote not found
components:
  schemas:
    Quote:
      type: object
      required:
        - id
        - quote
      properties:
        id:
          type: integer
        quote:
          type: string

I opted to go a different direction for the article, but I wanted to log this ticket, in case it provides value for someone else in the future.

Have a really great day!

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the issue with the provided build.gradle configuration, the java-micronaut-server generator, and the supplied openapi.yaml. Inspect the generated AbstractDefaultController and its package imports, then verify compilation with generateControllerAsAbstract=true and custom api, model, and invoker packages. Done means generation no longer produces class-not-found errors and respects those package settings.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, openapi
Domain
api, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.