Skip to content

jaxrs-generator silently skips JAX-RS resources whose source uses Java 14+ syntax → BUILD SUCCESS but 404 at runtime #95

Description

@Syvlain

Summary

When a JAX-RS resource class in src/main/java uses Java 14+ syntax (switch expressions, multi-label case, record, pattern matching, text blocks), the unknow-server-maven plugin's JavaParser fails to parse the file, the file is silently skipped, and the build still succeeds. The resulting JAR boots fine but every request to that resource returns 404 because no Jaxrs_<path>.java was generated.

The only signal is a single [WARNING] Failed to parse <File>.java: … line buried in the generate-sources log — easy to miss in CI output. Maven's exit code is 0.

Versions

  • io.github.unknow0.server:unknow-server-maven 0.9.9
  • maven-compiler-plugin 3.13.0 with maven.compiler.source/target = 17
  • JDK 25 (Maven was invoked via JDK 25)
  • Reproduced on Linux 6.17, Maven 3.8.7

Minimal repro

Single-module Maven project. JAX-RS impl with Java 14+ syntax:

package com.example.bridge;

import java.util.Map;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.*;

@Path("/mcp")
@Produces(MediaType.APPLICATION_JSON)
public class BridgeServiceImpl {

    @POST
    @Path("/execute/{name}")
    @Consumes(MediaType.APPLICATION_JSON)
    public Response execute(@PathParam("name") String name, Map<String, Object> args) {
        // Switch expression — Java 14+
        return switch (name) {
            case "a", "b" -> Response.ok().build();
            default -> Response.status(Response.Status.NOT_FOUND).build();
        };
    }

    @GET
    @Path("/tools")
    public String listTools() {
        return "{\"tools\":[]}";
    }
}

mvn clean package -DskipTests output:

[INFO] --- unknow-server-maven:0.9.9:jaxrs-generator (jaxrs) @ example ---
[WARNING] Failed to parse BridgeServiceImpl.java: [(line 18,col 16) Switch expressions are not supported.
  Pay attention that this feature is supported starting from 'JAVA_12' language level.]
[INFO] --- unknow-server-maven:0.9.9:servlet-generator (server) @ example ---
servlets:	[Resource:/openapi.json]    ← no Jaxrs_mcp_* — silent skip
[INFO] BUILD SUCCESS

At runtime: curl http://localhost:8080/mcp/tools404. target/jaxrs-generator/resources/openapi.json is empty ("paths":{}).

Root cause

AbstractGeneratorMojo constructs JavaParser without setting a language level:

// AbstractGeneratorMojo.java:131
parser = new JavaParser(new ParserConfiguration().setStoreTokens(true).setSymbolResolver(javaSymbolSolver));

JavaParser's default ParserConfiguration language level is POPULAR (currently mapped to JAVA_11), so anything from Java 12 onward fails. The SrcWalker (called from process(TypeConsumer)) swallows the parse error and continues with the remaining types.

Suggested fixes

Any one of these would have caught the issue in my project:

  1. Set the language level on the ParserConfiguration — e.g. setLanguageLevel(LanguageLevel.JAVA_21) (or the highest released). Modern projects on JDK 21+ would be supported out of the box.
  2. Expose the language level as a plugin parameter so users can opt in:
    <configuration>
        <javaParserLanguageLevel>JAVA_21</javaParserLanguageLevel>
    </configuration>
  3. Fail the build on parse error, or at least surface it as an [ERROR] rather than [WARNING]. Silent skip of a JAX-RS class is much worse than a hard failure — the user can decide to downgrade to a warning if they intentionally have non-JAX-RS files that fail to parse.

(1) + (3) combined would be the most robust default: support modern syntax, and refuse to silently skip a class even if a future syntax breaks parsing.

Workaround documented for the meantime

For others hitting this, the workaround is to constrain JAX-RS resource sources to pre-Java-14 syntax (no switch expressions, no record, no multi-label case, no pattern matching, no text blocks). The compiled bytecode can still target any JDK; only the source files scanned by unknow-server-maven need to obey the restriction.

I've documented the trap and three related ones (@Path on interface vs impl, @Consumes at class level + GET → 415, - in @Path filename) in our team's onboarding rule. Happy to PR them as a KNOWN-ISSUES.md upstream if useful.

Thanks for the great plugin — the startup-time / image-size win over Spring Boot is real and we're shipping with it in production.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions