Я написал собственный JsonSerializer для преобразования BigDecimal в String. Я хочу вызвать этот сериализатор, используя аннотацию @JsonSerialize, но условно, т.е. если конкретное логическое значение истинно, только тогда это преобразование BigDecimal в String не должно выполняться иначе.
У меня есть POJO с полем BigDecimal цена. Этот POJO отправляется в ответ на два вызова отдыха:
Может ли кто-нибудь подсказать, как я могу этого добиться?
Ниже приведен фрагмент кода пользовательского сериализатора, который я написал:
public class BigDecimalToStringSerializer extends JsonSerializer<BigDecimal> {
@Override
public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider serializers) throws IOException,
JsonProcessingException {
gen.writeString(value.toString());
}
}
POJO файл с полем цены:
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;
}
}
Заранее спасибо !!
Для этого вы можете реализовать PropertyFilter
. Во-первых, вам нужно определить фильтр для нашей сущности, используя аннотацию @JsonFilter
:
@JsonFilter("stringValueFilter")
public class Price {
private BigDecimal price;
public Price() {
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal pric) {
this.price = price;
}
}
Это твой 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;
}
Первый метод требует специальной реализации для вашего случая:
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);
}
}
Этот фильтр содержит фактическую логику, определяющую, будет ли поле price
сериализовано или нет, на основе его значения.
Далее вам нужно подключить этот фильтр к ObjectMapper
:
final ObjectMapper mapper = new ObjectMapper();
final FilterProvider filterProvider = new SimpleFilterProvider()
.addFilter("stringValueFilter", new StringValueFilter());
mapper.setFilters(filterProvider);
Чтобы добавить, класс Price имеет и другие поля (Integer, BigDecimal, String и т. д.). Итак, как я могу указать, что только одно поле сериализуется как String? А где логика записать значение BigDecimal как String?
@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;
}
}
Check if field is "price" :
if not, serialize normally and return
if so, check your boolean field to see if you sould serialize or not
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;
}
}
https://www.baeldung.com/jackson-serialize-field-custom-criteria
В моем Java-коде поле цены всегда BigDecimal. Для одной конечной точки отдыха я хочу, чтобы это поле цены было отправлено как есть, то есть числовое значение. Для другой конечной точки я хочу, чтобы она отправлялась в строковом формате. Где я могу указать этот логический флаг, чтобы проверить, когда преобразовывать в String, а когда ничего не делать?
toSerializeOrNot = ((MyDtoWithFilter) pojo) .getYourCoditionalField (); в этой строке вы проверяете свой логический флаг в классе Price. обратите внимание, что ваш флаг должен быть в классе Price, и на основе этого вы можете решить сериализовать его в строку или ничего не делать
Чтобы добавить, класс Price имеет и другие поля (Integer, BigDecimal, String и т. д.). Итак, как я могу указать, что только одно поле сериализуется как String? А где логика записать значение BigDecimal как String?
см. этот код пытается установить условие для вашего поля цены в классе Price, который вы аннотируете с помощью @JsonSerialize (using = BigDecimalToStringSerializer.class), это означает, что по умолчанию вы хотите, чтобы он был сериализован в строку. тогда мы делаем условие для другого поля, например. ((MyDtoWithFilter) pojo) .getYourCoditionalField (), чтобы проверить, разрешено ли использовать BigDecimalToStringSerializer для строкового преобразования или нет, и оставить другие поля как есть
см. этот код пытается установить условие для вашего поля цены в классе Price, который вы аннотируете с помощью @JsonSerialize (using = BigDecimalToStringSerializer.class), это означает, что по умолчанию вы хотите, чтобы он был сериализован в строку. тогда мы делаем условие для другого поля, например. ((MyDtoWithFilter) pojo) .getYourCoditionalField (), чтобы проверить, разрешено ли использовать BigDecimalToStringSerializer для строкового преобразования или нет, и оставить другие поля нетронутыми.
Привет, а что если я хочу наоборот? то есть по умолчанию поля цены должны оставаться в числовом формате при отправке по сети. Но в некоторых случаях его нужно преобразовать в String? Не могли бы вы помочь с этим?
Я понял, что предоставленное вами решение нарушает мой код. Мое требование простое: 1) если значение флага истинно, не выполняйте пользовательскую сериализацию, т.е. BigDecimal должен оставаться как есть. 2) если значение флага равно false, выполнить настраиваемую сериализацию, т.е. преобразовать BigDecimal в String. Не могли бы вы помочь с этим?
Я нашел решение своей проблемы. Единственное, что мне нужно было сделать, это: поставить отметку в классе BigDecimalToStringSerilizer.
Единственное изменение требуется в пользовательском классе сериализатора:
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);
}
}
}
В моем Java-коде поле цены всегда BigDecimal. Для одной конечной точки отдыха я хочу, чтобы это поле цены было отправлено как есть, то есть числовое значение. Для другой конечной точки я хочу, чтобы она отправлялась в строковом формате. Где я могу указать этот логический флаг, чтобы проверить, когда преобразовывать в String, а когда ничего не делать?