He escrito un JsonSerializer personalizado para convertir BigDecimal a String. Quiero invocar este serializador usando la anotación @JsonSerialize pero condicionalmente, es decir, si un valor booleano particular es verdadero solo entonces esta conversión de BigDecimal a String no debería hacerse.

Tengo un POJO que tiene un campo BigDecimal price . Este POJO se envía en respuesta a dos llamadas de descanso:

  • espera el campo de precio como valor numérico // entonces @JsonSerialize no debería ejecutarse
  • espera el campo de precio como valor de cadena // por lo que @JsonSerialize debería ejecutarse

¿Alguien puede sugerir cómo puedo lograrlo?

A continuación se muestra el fragmento de código del serializador personalizado que he escrito:

public class BigDecimalToStringSerializer extends JsonSerializer<BigDecimal> {

    @Override
    public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider serializers) throws IOException,
        JsonProcessingException {
        gen.writeString(value.toString());
    }

}

Archivo POJO con campo de precio:

JsonInclude(Include.NON_NULL)
public class Price{
    private BigDecimal price;
    public Price() {
    }
    @JsonSerialize(using = BigDecimalToStringSerializer.class)
    public BigDecimal getPrice() {
        return price;
    }   
    public void setPrice(BigDecimal pric) {
        this.price  = price;
    }
}

Muchas gracias de antemano!

1
G.G. 9 sep. 2018 a las 08:18

3 respuestas

La mejor respuesta

El único cambio se requiere en la clase de serializador personalizado:

public class BigDecimalToStringSerializer extends JsonSerializer<BigDecimal> {

    @Override
    public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider serializers) throws IOException,
        JsonProcessingException {
    if (pojo instanceof Price && ((Price) pojo).shouldConvertInString()) {
        gen.writeString(value.toString());
    } else {
        gen.writeNumber(value);
    }
    }

}

2
G.G. 11 sep. 2018 a las 07:23

Puede implementar un PropertyFilter para esto. Primero, debe definir el filtro en nuestra entidad, utilizando la anotación @JsonFilter:

@JsonFilter("stringValueFilter")
public class Price {
  private BigDecimal price;
  public Price() {
  }

  public BigDecimal getPrice() {
     return price;
  }   
  public void setPrice(BigDecimal pric) {
     this.price  = price;
  }
}

Este es tu PropertyFilter

public interface PropertyFilter {
    void serializeAsField(Object pojo, JsonGenerator jgen, SerializerProvider prov, PropertyWriter writer);

    void serializeAsElement(Object elementValue, JsonGenerator jgen, SerializerProvider prov, PropertyWriter writer) throws Exception;

    void depositSchemaProperty(PropertyWriter writer, JsonObjectFormatVisitor objectVisitor, SerializerProvider provider) throws JsonMappingException;

    @Deprecated 
    void depositSchemaProperty(PropertyWriter writer, ObjectNode propertiesNode, SerializerProvider provider) throws JsonMappingException;
}

El primer método requiere una implementación especial para su caso:

public class StringValueFilter implements PropertyFilter {
    void serializeAsField(Object pojo, JsonGenerator jgen, SerializerProvider prov, PropertyWriter writer) {
        if (pojo instanceof Price && isValueFieldNumber((Price) pojo)) {
            return; // skip this field
        }
        writer.serializeAsField(pojo, jgen, prov);
    }

    private isValueFieldNumber(Price price) {
        return: //check your logic and return
     }

    void serializeAsElement(Object elementValue, JsonGenerator jgen, SerializerProvider prov, PropertyWriter writer) throws Exception {
        writer.serializeAsField(elementValue, jgen, prov);
    }

    void depositSchemaProperty(PropertyWriter writer, JsonObjectFormatVisitor objectVisitor, SerializerProvider provider) throws JsonMappingException {
        writer.depositSchemaProperty(objectVisitor);
    }

    @Deprecated 
    void depositSchemaProperty(PropertyWriter writer, ObjectNode propertiesNode, SerializerProvider provider) throws JsonMappingException {
        writer.depositSchemaProperty(propertiesNode, provider);
    }
}

Este filtro contiene la lógica real que decide si el campo price se va a serializar o no, en función de su valor.

A continuación, debe conectar este filtro a ObjectMapper:

final ObjectMapper mapper = new ObjectMapper();
final FilterProvider filterProvider = new SimpleFilterProvider()
        .addFilter("stringValueFilter", new StringValueFilter());
mapper.setFilters(filterProvider);
2
imk 9 sep. 2018 a las 07:39

1.Coloque @JsonFilter en usted Clase de precio:

@JsonFilter("myFilter")
@JsonInclude(Include.NON_NULL)
public class Price {
    private BigDecimal price;
    public Price() {}
    @JsonSerialize(using = BigDecimalToStringSerializer.class)
    public BigDecimal getPrice() {
        return price;
    }
    public void setPrice(BigDecimal pric) {
        this.price = price;
    }
}

2.Definir la lógica de CustomFilter

Compruebe si el campo es "precio":
si no, serialice normalmente y devuelva
si es así, verifique su campo booleano para ver si puede serializar o no

    public class CustomFilter extends SimpleBeanPropertyFilter {
    @Override
    public void serializeAsField
        (Object pojo, JsonGenerator jgen, SerializerProvider provider, PropertyWriter writer)
    throws Exception {
        if (include(writer)) {
            if (!writer.getName().equals("price")) {
                writer.serializeAsField(pojo, jgen, provider);
                return;
            }
            Boolean toSerializeOrNot = ((MyDtoWithFilter) pojo).getYourCoditionalField();
            if (toSerializeOrNot) {
                writer.serializeAsField(pojo, jgen, provider);
            }
        } else if (!jgen.canOmitFields()) { 
            writer.serializeAsOmittedField(pojo, jgen, provider);
        }
    }
    @Override
    protected boolean include(BeanPropertyWriter writer) {
        return true;
    }
    @Override
    protected boolean include(PropertyWriter writer) {
        return true;
    }
}

Más información

https://www.baeldung.com/jackson-serialize-field-custom-criteria

1
MohammadReza Alagheband 9 sep. 2018 a las 08:46