Skip to main content

Migrates from Jackson 2.x to Jackson 3.x

org.openrewrite.java.jackson.UpgradeJackson_2_3

Migrate applications to the latest Jackson 3.x release. This recipe handles package changes (`com.fasterxml.jackson` -> `tools.jackson`), dependency updates, core class renames, exception renames, and method renames (e.g., `JsonGenerator.writeObject()` -> `writePOJO()`, `JsonParser.getCurrentValue()` -> `currentValue()`).

Tags​

Recipe source​

GitHub: jackson-2-3.yml, Issue Tracker, Code Genome Project

Info

This recipe is composed of more than one recipe. If you want to customize the set of recipes this is composed of, you can find and copy the GitHub source for the recipe from the link above.

This recipe is available under the Apache License Version 2.0.

Definition​

Used by​

This recipe is used as part of the following composite recipes:

Examples​

Example 1​

Jackson3DependenciesTest#jacksonAnnotations

Before​
pom.xml
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>example</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.19.0</version>
</dependency>
</dependencies>
</project>
After​
pom.xml
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>example</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.21</version>
</dependency>
</dependencies>
</project>

Example 2​

Jackson3MethodRenamesTest#jsonGeneratorWriteObject

Before​
import com.fasterxml.jackson.core.JsonGenerator;

class Test {
void test(JsonGenerator gen, Object value) throws Exception {
gen.writeObject(value);
}
}
After​
import tools.jackson.core.JsonGenerator;

class Test {
void test(JsonGenerator gen, Object value) throws Exception {
gen.writePOJO(value);
}
}

Example 3​

Jackson3TypeChangesTest#jsonFactory

Before​
import com.fasterxml.jackson.core.JsonFactory;

class Test {
JsonFactory factory = new JsonFactory();
}
After​
import tools.jackson.core.json.JsonFactory;

class Test {
JsonFactory factory = JsonFactory.builder()
.build();
}

Example 4​

LombokJacksonizedConfigTest#addJacksonVersionToLombokConfig

Unchanged​
import lombok.Builder;
import lombok.Value;
import lombok.extern.jackson.Jacksonized;

@Value
@Builder
@Jacksonized
class MyDto {
String name;
int age;
}

Example 5​

RemoveThrowsIOExceptionFromJacksonOverridesTest#removeThrowsIOExceptionFromSerializer

Before​
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;

class MySerializer extends JsonSerializer<String> {
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeString(value.toUpperCase());
}
}
After​
import tools.jackson.core.JsonGenerator;
import tools.jackson.databind.SerializationContext;
import tools.jackson.databind.ValueSerializer;

class MySerializer extends ValueSerializer<String> {
@Override
public void serialize(String value, JsonGenerator gen, SerializationContext provider) {
gen.writeString(value.toUpperCase());
}
}

Example 6​

RenameJsonTokenFieldNameTest#renameFieldNameToPropertyName

Before​
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;

class Test {
void parse(JsonParser parser) {
if (parser.currentToken() == JsonToken.FIELD_NAME) {
System.out.println("It's a field");
}
}
}
After​
import tools.jackson.core.JsonParser;
import tools.jackson.core.JsonToken;

class Test {
void parse(JsonParser parser) {
if (parser.currentToken() == JsonToken.PROPERTY_NAME) {
System.out.println("It's a field");
}
}
}

Example 7​

ReorderStreamWriteExceptionArgumentsTest#reorderStringAndGenerator

Before​
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonGenerator;

class Test {
void example(JsonGenerator gen) {
throw new JsonGenerationException("message", gen);
}
}
After​
import tools.jackson.core.JsonGenerator;
import tools.jackson.core.exc.StreamWriteException;

class Test {
void example(JsonGenerator gen) {
throw new StreamWriteException(gen, "message");
}
}

Example 8​

StdDeserializerNullConstructorTest#stdDeserializerThisNullPattern

Before​
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import java.io.IOException;

class MyDeserializer extends StdDeserializer<String> {
public MyDeserializer() {
this(null);
}

public MyDeserializer(Class<?> vc) {
super(vc);
}

@Override
public String deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException {
return p.getValueAsString();
}
}
After​
import tools.jackson.core.JsonParser;
import tools.jackson.databind.DeserializationContext;
import tools.jackson.databind.deser.std.StdDeserializer;

class MyDeserializer extends StdDeserializer<String> {
public MyDeserializer() {
this(String.class);
}

public MyDeserializer(Class<?> vc) {
super(vc);
}

@Override
public String deserialize(JsonParser p, DeserializationContext ctxt) {
return p.getValueAsString();
}
}

Example 9​

TypeFactoryDefaultInstanceTest#typeFactoryDefaultInstanceRenamed

Before​
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.type.TypeFactory;

class Test {
JavaType getType() {
return TypeFactory.defaultInstance().constructType(String.class);
}
}
After​
import tools.jackson.databind.JavaType;
import tools.jackson.databind.type.TypeFactory;

class Test {
JavaType getType() {
return TypeFactory.createDefaultInstance().constructType(String.class);
}
}

Example 10​

UpgradeJackson_2_3Test#jacksonUpgradeToVersion3

Before​
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonFactoryBuilder;
import com.fasterxml.jackson.databind.ObjectMapper;

class Test {
public String foo(@JsonProperty("foo") String foo) {
return foo;
}

static void helloJackson() {
Object[] input = new Object[] { "one", "two" };
JsonFactory factory = new JsonFactoryBuilder().build();
}
}
After​
import com.fasterxml.jackson.annotation.JsonProperty;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.core.json.JsonFactory;

class Test {
public String foo(@JsonProperty("foo") String foo) {
return foo;
}

static void helloJackson() {
Object[] input = new Object[] { "one", "two" };
JsonFactory factory = JsonFactory.builder().build();
}
}
Unchanged​
pom.xml
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>example</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.19.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.19.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.19.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-parameter-names</artifactId>
<version>2.19.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
<version>2.19.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.19.0</version>
</dependency>
</dependencies>
</project>

Example 11​

Jackson3DependenciesTest#jacksonAnnotations

Before​
pom.xml
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>example</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.19.0</version>
</dependency>
</dependencies>
</project>
After​
pom.xml
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>example</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.21</version>
</dependency>
</dependencies>
</project>

Example 12​

Jackson3MethodRenamesTest#jsonGeneratorWriteObject

Before​
import com.fasterxml.jackson.core.JsonGenerator;

class Test {
void test(JsonGenerator gen, Object value) throws Exception {
gen.writeObject(value);
}
}
After​
import tools.jackson.core.JsonGenerator;

class Test {
void test(JsonGenerator gen, Object value) throws Exception {
gen.writePOJO(value);
}
}

Example 13​

Jackson3TypeChangesTest#jsonFactory

Before​
import com.fasterxml.jackson.core.JsonFactory;

class Test {
JsonFactory factory = new JsonFactory();
}
After​
import tools.jackson.core.json.JsonFactory;

class Test {
JsonFactory factory = JsonFactory.builder()
.build();
}

Example 14​

LombokJacksonizedConfigTest#addJacksonVersionToLombokConfig

Unchanged​
import lombok.Builder;
import lombok.Value;
import lombok.extern.jackson.Jacksonized;

@Value
@Builder
@Jacksonized
class MyDto {
String name;
int age;
}

Example 15​

RemoveThrowsIOExceptionFromJacksonOverridesTest#removeThrowsIOExceptionFromSerializer

Before​
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;

class MySerializer extends JsonSerializer<String> {
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeString(value.toUpperCase());
}
}
After​
import tools.jackson.core.JsonGenerator;
import tools.jackson.databind.SerializationContext;
import tools.jackson.databind.ValueSerializer;

class MySerializer extends ValueSerializer<String> {
@Override
public void serialize(String value, JsonGenerator gen, SerializationContext provider) {
gen.writeString(value.toUpperCase());
}
}

Example 16​

RenameJsonTokenFieldNameTest#renameFieldNameToPropertyName

Before​
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;

class Test {
void parse(JsonParser parser) {
if (parser.currentToken() == JsonToken.FIELD_NAME) {
System.out.println("It's a field");
}
}
}
After​
import tools.jackson.core.JsonParser;
import tools.jackson.core.JsonToken;

class Test {
void parse(JsonParser parser) {
if (parser.currentToken() == JsonToken.PROPERTY_NAME) {
System.out.println("It's a field");
}
}
}

Example 17​

ReorderStreamWriteExceptionArgumentsTest#reorderStringAndGenerator

Before​
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonGenerator;

class Test {
void example(JsonGenerator gen) {
throw new JsonGenerationException("message", gen);
}
}
After​
import tools.jackson.core.JsonGenerator;
import tools.jackson.core.exc.StreamWriteException;

class Test {
void example(JsonGenerator gen) {
throw new StreamWriteException(gen, "message");
}
}

Example 18​

StdDeserializerNullConstructorTest#stdDeserializerThisNullPattern

Before​
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import java.io.IOException;

class MyDeserializer extends StdDeserializer<String> {
public MyDeserializer() {
this(null);
}

public MyDeserializer(Class<?> vc) {
super(vc);
}

@Override
public String deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException {
return p.getValueAsString();
}
}
After​
import tools.jackson.core.JsonParser;
import tools.jackson.databind.DeserializationContext;
import tools.jackson.databind.deser.std.StdDeserializer;

class MyDeserializer extends StdDeserializer<String> {
public MyDeserializer() {
this(String.class);
}

public MyDeserializer(Class<?> vc) {
super(vc);
}

@Override
public String deserialize(JsonParser p, DeserializationContext ctxt) {
return p.getValueAsString();
}
}

Example 19​

TypeFactoryDefaultInstanceTest#typeFactoryDefaultInstanceRenamed

Before​
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.type.TypeFactory;

class Test {
JavaType getType() {
return TypeFactory.defaultInstance().constructType(String.class);
}
}
After​
import tools.jackson.databind.JavaType;
import tools.jackson.databind.type.TypeFactory;

class Test {
JavaType getType() {
return TypeFactory.createDefaultInstance().constructType(String.class);
}
}

Example 20​

UpgradeJackson_2_3Test#jacksonUpgradeToVersion3

Before​
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonFactoryBuilder;
import com.fasterxml.jackson.databind.ObjectMapper;

class Test {
public String foo(@JsonProperty("foo") String foo) {
return foo;
}

static void helloJackson() {
Object[] input = new Object[] { "one", "two" };
JsonFactory factory = new JsonFactoryBuilder().build();
}
}
After​
import com.fasterxml.jackson.annotation.JsonProperty;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.core.json.JsonFactory;

class Test {
public String foo(@JsonProperty("foo") String foo) {
return foo;
}

static void helloJackson() {
Object[] input = new Object[] { "one", "two" };
JsonFactory factory = JsonFactory.builder().build();
}
}
Unchanged​
pom.xml
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>example</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.19.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.19.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.19.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-parameter-names</artifactId>
<version>2.19.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
<version>2.19.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.19.0</version>
</dependency>
</dependencies>
</project>

Usage​

This recipe has no required configuration options. It can be activated by adding a dependency on `org.openrewrite.recipe:rewrite-jackson` in your build file or by running a shell command (in which case no build changes are needed):

OpenRewrite artifacts, including the Maven and Gradle plugins themselves, are distributed through the Code Genome Project repository (https://artifacts.codegenomeproject.org/maven), which requires authentication. Sign in to the Code Genome Project to create a download token; your build authenticates with the email or username you signed in with, plus that token as the password. See the quickstart guide for details.

  1. Put your Code Genome Project credentials in ~/.gradle/gradle.properties, so that they are not committed alongside your build:
    ~/.gradle/gradle.properties
    codeGenomeUsername=you@example.com
    codeGenomeToken=your-download-token
  2. Add the Code Genome Project repository to your settings.gradle file, so that the plugin itself can be resolved:
    settings.gradle
    pluginManagement {
    repositories {
    maven {
    url = "https://artifacts.codegenomeproject.org/maven"
    credentials {
    username = providers.gradleProperty("codeGenomeUsername").get()
    password = providers.gradleProperty("codeGenomeToken").get()
    }
    }
    // Keep the portal for any other plugins your build applies
    gradlePluginPortal()
    }
    }
  3. Add the following to your build.gradle file:
    build.gradle
    plugins {
    id("org.openrewrite.rewrite") version("latest.release")
    }

    rewrite {
    activeRecipe("org.openrewrite.java.jackson.UpgradeJackson_2_3")
    setExportDatatables(true)
    }

    repositories {
    mavenCentral()
    maven {
    url = "https://artifacts.codegenomeproject.org/maven"
    credentials {
    username = providers.gradleProperty("codeGenomeUsername").get()
    password = providers.gradleProperty("codeGenomeToken").get()
    }
    }
    }

    dependencies {
    rewrite("org.openrewrite.recipe:rewrite-jackson:1.31.0")
    }
  4. Run gradle rewriteRun to run the recipe.

See how this recipe works across multiple open-source repositories​

Run this recipe on OSS repos at scale with the Moderne SaaS.

The community edition of the Moderne platform enables you to easily run recipes across thousands of open-source repositories.

Please contact Moderne for more information about safely running the recipes on your own codebase in a private SaaS.

Data Tables​

Source files that had results​

org.openrewrite.table.SourcesFileResults

Source files that were modified by the recipe run.

Column NameDescription
Source path before the runThe source path of the file before the run. null when a source file was created during the run.
Source path after the runA recipe may modify the source path. This is the path after the run. null when a source file was deleted during the run.
Parent of the recipe that made changesIn a hierarchical recipe, the parent of the recipe that made a change. Empty if this is the root of a hierarchy or if the recipe is not hierarchical at all.
Recipe that made changesThe specific recipe that made a change.
Estimated time savingAn estimated effort that a developer to fix manually instead of using this recipe, in unit of seconds.
CycleThe recipe cycle in which the change was made.