I use Jackson to serialise POJOs into CSV. Now we need to change the naming for certain fields to snake_case. This is easily done by @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class).
For compatibility reasons we need some of the renamed fields also with their old name.
E.g.:
public class Pojo {
    private int someField;
}
Default will serialise to "someField", SnakeCaseStrategy will serialise to "some_field".
How to get serialization with both?:
{
  "someField" : "one",
  "some_field" : "one" 
}
My first try was a mixin:
public abstract class PojoFormat {
    @JsonProperty("someField")
    abstract String getSomeField();
}
but this effectively only undoes the naming strategy change. So how to copy a field in serialization - preferable not by changing the Pojo (this copied fields should be removed when all clients can cope with it).
Little update:
in my real class there some nested class that use JsonUnwrapped and the doc stated that this is not working with custom serializer (didn't know that this makes a difference here).
Well, I have never seen this before, I would be very happy if someone here in this site knows how.
The easy way, in my opinion, is to use a Custom Serializer.
For example:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
@JsonSerializer(using=PojoSerializer.class)
class Pojo {
 
  private String myValue;
   
  // getters and setters
}
class PojoSerializer extends StdSerializer<Pojo> {
  public PojoSerializer() {
   super(Pojo.class);
  }
      @Override
    public void serialize(Pojo value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        gen.writeStartObject();
        gen.writeStringField("myValue", value.getMyValue());
        gen.writeStringField("my_value", value.getMyValue());
        gen.writeEndObject();
    }
}
static class Pojo {
    private String myValue;
    public String getMyValue() {
        return myValue;
    }
    public Pojo setMyValue(String myValue) {
        this.myValue = myValue;
        return this;
    }
}
static class PojoSerializer extends StdSerializer<Pojo> {
    public PojoSerializer() {
        super(Pojo.class);
    }
    @Override
    public void serialize(Pojo value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        gen.writeStartObject();
        gen.writeStringField("myValue", value.getMyValue());
        gen.writeStringField("my_value", value.getMyValue());
        gen.writeEndObject();
    }
}
public static void main(String[] args) throws  JsonProcessingException {
    final ObjectMapper mapper = new ObjectMapper();
    final SimpleModule module = new SimpleModule("PojoModule");
    module.addSerializer(Pojo.class, new PojoSerializer());
    mapper.registerModule(module);
    final Pojo pojo = new Pojo();
    pojo.setMyValue("This is the value of my pojo");
    System.out.println(mapper.writeValueAsString(pojo));
}
I write some code for you, you might want to see to get new ideias. This works as a generic way(just to not write several serializers).
// The serializer will be register in the ObjectMapper module.
static class Pojo {
    private String myValue = "With snake and camel";
    private String value = "Without snake case";
    private String thirdValue = "snake & camel";
}
// using the annotation
@JsonSerialize(using = PojoSerializer.class)
static class Pojo2 {
    private String pojoName = "Pojo 2";
    private String pojo = "pojp";
}
static class PojoSerializer extends StdSerializer<Object> {
    public PojoSerializer() {
        super(Object.class);
    }
    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        gen.writeStartObject();
        final Field[] fields = value.getClass().getDeclaredFields();
        for(final Field field : fields) {
            final String name = field.getName();
            final String fieldValue;
            try {
                // Do not use this!
                fieldValue = (String)field.get(value);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
            byte firstUpperCase = -1;
            for(byte index = 0; index < name.length(); index++) {
                final char caractere = name.charAt(index);
                // A ascii code is 66 decimal, and 90 is the Z in decimal
                if(caractere > 'A' && caractere < 'Z') {
                    // found the first upper
                    firstUpperCase = index;
                    break;
                }
            }
            // writes the normal field name
            gen.writeStringField(name, fieldValue);
            // if the name is in camel case, we will write in snake case too.
            if(firstUpperCase != -1) {
                final char lowerLetter = (char)((int) name.charAt(firstUpperCase) + 32);
                final String left = name.substring(0, firstUpperCase);
                final String right = String.format("%c%s",lowerLetter, name.substring(firstUpperCase + 1));
                gen.writeStringField(String.format("%s_%s", left, right), fieldValue);
            }
        }
        gen.writeEndObject();
    }
}
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With