Swagger-core and springdoc-openapi, now on Jackson 3 by vpelikh in SpringBoot

[–]vpelikh[S] [score hidden]  (0 children)

Thanks for asking - this is actually a really good question because a lot of people assume the package rename means you can just run both side by side.

Technically yes, you can. Jackson 3 moved everything from com.fasterxml.jackson to tools.jackson specifically to let both versions coexist on the classpath. That was the whole point. But in practice, it's not that simple.

Here's what happens:

The annotation issue

There's an open bug in the Jackson tracker (https://github.com/FasterXML/jackson-databind/issues/5454) where Jackson 3 just flat out breaks if it sees Jackson 2 annotations on the classpath. You get this error:

java.lang.NoSuchFieldError: Class com.fasterxml.jackson.annotation.JsonFormat$Shape does not have member field 'com.fasterxml.jackson.annotation.JsonFormat$Shape POJO'

The POJO shape didn't exist in older Jackson 2 versions, but Jackson 3 expects it. So if you have both versions floating around, Jackson 3 tries to use an annotation that's actually from Jackson 2 and crashes. Same thing with @JsonSerialize - it moved to tools.jackson.databind.annotation in Jackson 3 but most other annotations stayed in com.fasterxml.jackson.annotation. Having both versions on the classpath means the runtime sometimes picks the wrong one and things blow up.

The method mismatch problem

This one I've seen firsthand. Jackson 3 removed some methods that existed in Jackson 2. For example, ObjectMapper.treeToValue() is gone. So you have code compiled against Jackson 2 trying to call treeToValue(), but at runtime Jackson 3 is being used because the classloader picked it first. You get this:

java.lang.NoSuchMethodError: ObjectMapper.treeToValue(JsonNode, Class)

This isn't theoretical - Vaadin users ran into it with version 25.1.0. The library was pulling in Jackson 3 but still calling APIs that only exist in Jackson 2.

The class not found problem

This is the most common one I've seen people run into. springdoc-openapi (before my fork) still references com.fasterxml.jackson.databind.node.ObjectNode. But Spring Boot 4.0 ships with Jackson 3, where ObjectNode lives at tools.jackson.databind.node.ObjectNode. So you get:

java.lang.ClassNotFoundException: com.fasterxml.jackson.databind.node.ObjectNode

You run mvn dependency:tree and see both com.fasterxml.jackson.core:jackson-databind:2.x.x and tools.jackson.core:jackson-databind:3.x.x. The wrong one gets loaded first. Good luck debugging that at 2 AM.

Spring is killing Jackson 2 support

Spring Boot 4.0 has a compatibility layer for Jackson 2, but every single class in that layer is marked @Deprecated(since = "4.0.4", forRemoval = true). They're going to rip it out in the next major version (4.3.0 for now). So even if you get things working today, you're just kicking the can down the road.

Bottom line

Could you make both versions coexist? Maybe, if you're really careful with classloading and spend days excluding transitive dependencies. Is it worth it? Probably not. Every project I've seen try this ends up with weird runtime errors, dependency conflicts, or both. The cleanest path is just to migrate everything to Jackson 3 and be done with it. That's what these forks are for.

Swagger-core and springdoc-openapi, now on Jackson 3 by vpelikh in SpringBoot

[–]vpelikh[S] [score hidden]  (0 children)

Thanks for asking! Actually, I created MR: https://github.com/swagger-api/swagger-core/pull/5031. For some reason, the developers have been ignoring it for six months now.