Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Serialize json field based on field name/other fields, without overriding the whole serialization

Suppose I have a class

public class Product {

    private BigDecimal value;
    private String valueFormatted;

}

and I want the serialization of valueFormatted havè currency formatting. What I have today, is a custom getter which transforms value to the formatted String.
The problem is, I have a class with loads of value fields, and I don’t want to create getters for all (Lombok).

I tried creating a custom serializer, but I have to create the serialization logic for each of the fields, and I need it to behave like this:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

fieldName contains "Formatted" -> get value of field without "Formatted" and serialize.

And for any other field, do the default.

>Solution :

You can achieve this by creating a custom serializer that uses reflection to get the value of the corresponding value field for any valueFormatted field, and formats the value as currency. For all other fields, you can delegate to the default serializer.

Here’s an example implementation:

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;

import java.io.IOException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.NumberFormat;

public class ProductSerializer extends StdSerializer<Product> {

    public ProductSerializer() {
        this(null);
    }

    public ProductSerializer(Class<Product> t) {
        super(t);
    }

    @Override
    public void serialize(Product product, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        Field[] fields = Product.class.getDeclaredFields();
        for (Field field : fields) {
            if (field.getName().endsWith("Formatted")) {
                // For fields that end with "Formatted", get the corresponding "value" field and format it as currency
                String fieldName = field.getName();
                String valueFieldName = fieldName.substring(0, fieldName.length() - 9); // Remove "Formatted" suffix
                try {
                    Field valueField = Product.class.getDeclaredField(valueFieldName);
                    valueField.setAccessible(true);
                    BigDecimal value = (BigDecimal) valueField.get(product);
                    NumberFormat currencyFormat = NumberFormat.getCurrencyInstance();
                    String formattedValue = currencyFormat.format(value);
                    jsonGenerator.writeStringField(fieldName, formattedValue);
                } catch (Exception e) {
                    // Handle exceptions as appropriate
                }
            } else {
                // For all other fields, delegate to the default serializer
                try {
                    field.setAccessible(true);
                    Object value = field.get(product);
                    serializerProvider.defaultSerializeField(field.getName(), value, jsonGenerator);
                } catch (Exception e) {
                    // Handle exceptions as appropriate
                }
            }
        }
    }
}

This serializer uses reflection to loop over all fields in the Product class, and checks if each field’s name ends with "Formatted". If it does, it gets the value of the corresponding value field using reflection, formats the value as currency, and writes the formatted value to the JSON output. If the field’s name doesn’t end with "Formatted", it delegates to the default serializer provided by the SerializerProvider.

To use this serializer, you can simply annotate the Product class with @JsonSerialize:

import com.fasterxml.jackson.databind.annotation.JsonSerialize;

@JsonSerialize(using = ProductSerializer.class)
public class Product {

    private BigDecimal value;
    private String valueFormatted;

    // Constructors, getters, setters, etc.
}

This tells Jackson to use the ProductSerializer to serialize instances of the Product class.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading