Disable field serialization per ObjectMapper

Viewed 825

I'm developing a REST application using application/json Content-Type (server). I'm developing the REST client library for it as well (client). Both server and client use the same Jackson annotated classes/resources.

One of my server use cases includes adding a field which should be write-only (enable only deserialization). I do it like this:

public class MyClass {

  @JsonProperty(access = WRITE_ONLY)
  private String field;

  ...

}

However, since this class is used on the client side too, I am unable to send value to this field because the serialization processing skips it. I want the client to be able serialize this field. The server and client use separate object mappers.

I can use separate implementations of JsonSerializer<MyClass> and set it to the object mapper but this mean that I have to serialize all other fields manually. I don't want this.

I am wondering, if there is some way to instruct object mapper (or inject something into it) to handle such field differently?

1 Answers

When you use common model classes on two sides: client and server you can register all differences using com.fasterxml.jackson.databind.Module class and its implementations. In case, some Jackson configuration should be available only on one side you can move it to MixIn classes/interfaces and register only on given side.

Simple example:

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.IOException;

public class ClientServerApp {

    public static void main(String[] args) throws IOException {
        // Client side
        ObjectMapper clientMapper = JsonMapper.builder().build();

        // create payload on client side
        MyClass instance = new MyClass(1, "fieldValue");
        String payload = clientMapper.writeValueAsString(instance);

        // send to server
        System.out.println("Send: " + payload);
        // ..

        // Server side
        ObjectMapper serverMapper = JsonMapper.builder()
                .addModule(new ServerModule())
                .build();
        MyClass deserialized = serverMapper.readValue(payload, MyClass.class);
        System.out.println("Deserialized: " + deserialized);

        System.out.println("Payload on server side: " + serverMapper.writeValueAsString(deserialized));
    }
}

class ServerModule extends SimpleModule {
    public ServerModule() {
        setMixInAnnotation(MyClass.class, MyClassServerMixIn.class);
        // add other configuration
    }
}

@Data
@AllArgsConstructor
@NoArgsConstructor
class MyClass {

    private int id;
    private String field;
}

interface MyClassServerMixIn {

    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    String getField();
}

Above code prints:

Send: {"id":1,"field":"fieldValue"}
Deserialized: MyClass(id=1, field=fieldValue)
Payload on server side: {"id":1}

As you can notice, only ObjectMapper on client side can serialise field property.

Related