Master Jackson Mixins: Serialize/Deserialize Java Objects Without Changing Their Code

This tutorial explains how Java developers can use Jackson Mixins to add custom JSON serialization and deserialization behavior to classes that lack default constructors or getters, without modifying the original classes, and shows how to register Mixins via ObjectMapper or custom modules.

Programmer DD
Programmer DD
Programmer DD
Master Jackson Mixins: Serialize/Deserialize Java Objects Without Changing Their Code

Mixin is familiar to frontend developers using Vue or React, but Java backend developers often encounter it for the first time. This article introduces Jackson Mixins so backend developers can leverage this concept.

Scenario

Suppose a third‑party JAR provides a class that needs to be deserialized, but the class lacks a no‑arg constructor. Instead of modifying the source, you can solve the problem with Jackson's Mixin feature.

Jackson Mixins

In Jackson, a Mixin (mix‑in) allows you to attach serialization or deserialization configuration to a target class via a separate mix‑in class. The mix‑in does not alter the target class itself; it merely maps additional annotations to it.

Mixin Implementation

Consider a User class without a default constructor or getter methods:

public class User {
    private final String name;
    private final Integer age;

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" + "name='" + name + '\'' + ", age=" + age + '}';
    }
}

Creating the Mixin Class

To serialize and deserialize User without touching its source, define a mix‑in that supplies the necessary Jackson annotations:

@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE,
        isGetterVisibility = JsonAutoDetect.Visibility.NONE)
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonDeserialize(using = UserMixin.UserDeserializer.class)
public abstract class UserMixin {
    /**
     * Custom deserializer for User
     */
    static class UserDeserializer extends JsonDeserializer<User> {
        @Override
        public User deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            ObjectMapper mapper = (ObjectMapper) p.getCodec();
            JsonNode jsonNode = mapper.readTree(p);
            String name = readJsonNode(jsonNode, "name").asText(null);
            String age = readJsonNode(jsonNode, "age").asText(null);
            Integer ageVal = age == null ? null : Integer.valueOf(age);
            return new User(name, ageVal);
        }
        private JsonNode readJsonNode(JsonNode jsonNode, String field) {
            return jsonNode.has(field) ? jsonNode.get(field) : MissingNode.getInstance();
        }
    }
}

Mapping the Mixin to the Target Class

Register the mix‑in with ObjectMapper using addMixIn, then serialize and deserialize as usual:

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.addMixIn(User.class, UserMixin.class);

User felord = new User("felord", 12);
String json = objectMapper.writeValueAsString(felord); // {"name":"felord","age":12}
System.out.println("json = " + json);

String jsonStr = "{\"name\":\"felord\",\"age\":12}";
User user = objectMapper.readValue(jsonStr, User.class);
System.out.println("user = " + user); // User{name='felord', age=12}

This achieves custom JSON serialization/deserialization without modifying the original User class.

Jackson Modules

Jackson also supports modular configuration via SimpleModule. By extending SimpleModule you can register a set of Mixins in one place:

public class UserModule extends SimpleModule {
    public UserModule() {
        super(UserModule.class.getName());
    }

    @Override
    public void setupModule(SetupContext context) {
        context.setMixInAnnotations(User.class, UserMixin.class);
    }
}

Register the module with the mapper:

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new UserModule());

Jackson provides many useful modules, such as jackson-module-parameter-names , jackson-datatype-jdk8 , and jackson-datatype-jsr310 . Spring Security also offers SecurityJackson2Modules for security‑related serialization.

Other annotations can be referenced from previous Jackson articles.
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaserializationJSONJacksonDeserializationMixinObjectMapper
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.