Swagger Core 3
When upgrading to Swagger Core 3, refer to the Swagger Core 3.0 Migration Guide for the breaking changes, including the move from Jackson 2 to Jackson 3.
The io.arconia.rewrite.openapi.swagger.UpgradeSwaggerCore_3 recipe automates most of the changes introduced in Swagger Core 3.x. You can use it to update your project to the latest Swagger Core 3.x release.
Prerequisites
Swagger Core 3 supports only the jakarta namespace. The recipe migrates a project only when its code uses none of the javax REST, Servlet, Bean Validation, or JAXB APIs and it doesn’t declare the javax variant of the Swagger REST artifacts (swagger-jaxrs2, swagger-jaxrs2-servlet-initializer, and swagger-jaxrs2-servlet-initializer-v2). Otherwise, it leaves the project unchanged, so it is never left half migrated. In a multi-module build, each module is checked on its own.
If your project still uses the javax namespace, migrate it to Jakarta EE first, then run this recipe.
What the Recipe Changes
The recipe will:
-
Replace the retired Swagger Core artifacts with their 3.x counterparts:
swagger-annotations-jakarta,swagger-models-jakarta,swagger-core-jakarta, andswagger-integration-jakartadrop the-jakartasuffix,swagger-jaxrs2-jakartabecomesswagger-rest, and bothswagger-jaxrs2-servlet-initializer-v2-jakartaand its deprecated predecessorswagger-jaxrs2-servlet-initializer-jakartabecomeswagger-rest-servlet-initializer. -
Upgrade all
io.swagger.core.v3dependencies, the Swagger Gradle plugin, and the Swagger Maven plugin to the 3.x release line, replacing the retiredswagger-maven-plugin-jakartawithswagger-maven-plugin. -
Remove the
swagger-java17-supportdependency, which is no longer published. -
Declare the
commons-lang3dependency when your code uses it, since Swagger Core no longer brings it in transitively. -
Upgrade the Jakarta REST API to 4.0 and the Jakarta Servlet API to 6.1, as required by Jakarta EE 11.
-
Upgrade Jersey to 4.x, which implements Jakarta REST 4.0, and replace
jersey-media-json-jacksonwithjersey-media-json-jackson3, so that your resources keep serializing JSON through Jackson 3. -
Move the REST integration from the
io.swagger.v3.jaxrs2packages toio.swagger.v3.rest, and rename theJaxrs-prefixed types to theirRestcounterparts (for example,JaxrsOpenApiContextBuilderbecomesRestOpenApiContextBuilder). The recipe updates these names in Java code, in string literals (such as a scanner class passed toSwaggerConfiguration), in XML files (such as the servlet declarations inweb.xml), inmodule-info.java, and in theMETA-INF/servicesdescriptor of a customOpenAPIExtension. -
Change the
ObjectMapperProcessorimplementations to return the mapper they receive, and remove the deprecatedprocessYamlObjectMappermethod, which Swagger Core no longer calls. -
Migrate the project to Jackson 3, moving the Jackson dependencies and imports from
com.fasterxml.jacksontotools.jackson. The Jackson annotations keep theircom.fasterxml.jackson.annotationpackage.
See its entry in the Recipe Catalog for the full list of recipes this upgrade applies, each with its options and a before/after example.
Manual Follow-Up
Some changes need a decision or can’t be made safely by a recipe:
-
Mapper defaults. Swagger Core 3 builds its mappers from the Jackson 3 defaults, which change the generated output. For example,
java.time.Monthvalues are written as numbers, an accessor such asgetURL()produces aURLproperty instead ofurl, and a constructor parameter whose name matches no getter or field becomes an extrawriteOnlyschema property. Compare the generated OpenAPI document with the previous one. To restore most of the Jackson 2 behavior, callObjectMapperFactory.setJackson2Compatibility(true)at startup, before the first mapper is used. -
Mappers configured in place. Jackson 3 mappers are immutable. An
ObjectMapperProcessormethod that configured the mapper it received, such as withmapper.enable(…), must now return a new one built withmapper.rebuild(). -
Mappers created outside Swagger Core. A mapper that isn’t built by
ObjectMapperFactorydrops properties such as$reffrom the Swagger models. Serialize and deserialize them withJson.mapper(),Json31.mapper(), orObjectMapperFactory.buildStrictGenericObjectMapper(). -
SwaggerAnnotationIntrospectorsubclasses. Like their Jackson 3 counterparts, thehasRequiredMarker,findPropertyDescription,findSubtypes, andfindTypeNamemethods take aMapperConfig<?>first parameter. Update the overrides and keep@Overrideon them: without it, an override with the old signature still compiles but is never called. -
Cached mappers. A component that keeps the result of
Json.mapper()orYaml.mapper()from startup doesn’t see customizers registered later withObjectMapperFactory.addCustomizer(…). Get the mapper when you use it instead. -
Configuration files. Class names in Swagger configuration files, such as a
scannerClassorreaderClassinopenapi-configuration.yaml, are not updated. -
Jersey JSON support. If your Jersey application didn’t use
jersey-media-json-jacksonbefore, addorg.glassfish.jersey.media:jersey-media-json-jackson3so that your resources can read and write JSON. -
Libraries built for Swagger Core 2. A third-party library compiled against Swagger Core 2.x needs a release compatible with Swagger Core 3. This includes a library that brings in the
javaxvariant of the Swagger REST artifacts, such asswagger-jaxrs2: upgrade the library or exclude the artifact.
After running the recipe, check that the resolved runtime classpath contains only Swagger Core 3.x artifacts.
Run the Recipe
You can apply this recipe with any OpenRewrite-compatible tool. The tabs below show three of them: the Arconia CLI, the OpenRewrite Gradle plugin, and the OpenRewrite Maven plugin. See Running Recipes for a comparison of when to pick each one.
-
Arconia CLI
-
Gradle
-
Maven
arconia rewrite run --recipe-name io.arconia.rewrite.openapi.swagger.UpgradeSwaggerCore_3
First, create an init.gradle file in your project root with the following content.
initscript {
repositories {
gradlePluginPortal()
}
dependencies {
classpath("org.openrewrite:plugin:latest.release")
}
}
rootProject {
plugins.apply(org.openrewrite.gradle.RewritePlugin)
dependencies {
rewrite("io.arconia.migrations:rewrite-openapi:latest.release")
}
// Remove when project repositories are disabled
afterEvaluate {
if (repositories.isEmpty()) {
repositories {
mavenCentral()
}
}
}
configurations.named("rewrite") {
canBeConsumed = false
}
}
Then, run the following command.
./gradlew rewriteRun \
--init-script init.gradle \
--no-parallel \
-DactiveRecipe=io.arconia.rewrite.openapi.swagger.UpgradeSwaggerCore_3
You can remove the init.gradle file afterwards.
./mvnw -U org.openrewrite.maven:rewrite-maven-plugin:run \
-Drewrite.recipeArtifactCoordinates=io.arconia.migrations:rewrite-openapi:LATEST \
-Drewrite.activeRecipes=io.arconia.rewrite.openapi.swagger.UpgradeSwaggerCore_3