Есть ли способ использовать Jackson JSON Processor для выполнения пользовательской сериализации на уровне поля? Например, я хотел бы иметь класс
public class Person {
public String name;
public int age;
public int favoriteNumber;
}
сериализован для следующего JSON:
{ "name": "Joe", "age": 25, "favoriteNumber": "123" }
Обратите внимание, что возраст = 25 кодируется как число, а favoriteNumber = 123 кодируется как строка . Из коробки Jackson marshalls int
к числу. В этом случае я хочу, чтобы favoriteNumber был закодирован как строка.
Ответ 1
Вы можете реализовать собственный сериализатор следующим образом:
public class Person {
public String name;
public int age;
@JsonSerialize(using = IntToStringSerializer.class, as=String.class)
public int favoriteNumber:
}
public class IntToStringSerializer extends JsonSerializer<Integer> {
@Override
public void serialize(Integer tmpInt,
JsonGenerator jsonGenerator,
SerializerProvider serializerProvider)
throws IOException, JsonProcessingException {
jsonGenerator.writeObject(tmpInt.toString());
}
}
Java должен обрабатывать автобоксинг от int
до Integer
для вас.
Ответ 2
Jackson-databind (не менее 2.1.3) предоставляет специальные ToStringSerializer
(com.fasterxml.jackson.databind.ser.std.ToStringSerializer
)
Пример:
public class Person {
public String name;
public int age;
@JsonSerialize(using = ToStringSerializer.class)
public int favoriteNumber:
}
Ответ 3
Добавьте аннотированный getter @JsonProperty
, который возвращает String
для поля favoriteNumber
:
public class Person {
public String name;
public int age;
private int favoriteNumber;
public Person(String name, int age, int favoriteNumber) {
this.name = name;
this.age = age;
this.favoriteNumber = favoriteNumber;
}
@JsonProperty
public String getFavoriteNumber() {
return String.valueOf(favoriteNumber);
}
public static void main(String... args) throws Exception {
Person p = new Person("Joe", 25, 123);
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(p));
// {"name":"Joe","age":25,"favoriteNumber":"123"}
}
}
Ответ 4
jackson-annotations предоставляет @JsonFormat
, который может обрабатывать множество настроек без необходимости писать собственный сериализатор.
Например, запрос формы STRING
для поля с числовым типом выводит числовое значение в виде строки
public class Person {
public String name;
public int age;
@JsonFormat(shape = JsonFormat.Shape.STRING)
public int favoriteNumber;
}
приведет к желаемому результату
{"name":"Joe","age":25,"favoriteNumber":"123"}
Ответ 5
с помощью @JsonView мы можем определить поля классов моделей для сериализации, которые удовлетворяют минимальным критериям (мы должны определить критерии), так как мы можем иметь один основной класс с 10 свойствами, но только 5 свойств могут быть сериализованы, которые необходимы только для клиента
Определите наши представления, просто создав следующий класс:
public class Views
{
static class Android{};
static class IOS{};
static class Web{};
}
Аннотированный класс модели с представлениями:
public class Demo
{
public Demo()
{
}
@JsonView(Views.IOS.class)
private String iosField;
@JsonView(Views.Android.class)
private String androidField;
@JsonView(Views.Web.class)
private String webField;
// getters/setters
...
..
}
Теперь нам нужно написать собственный json-конвертер, просто расширив класс HttpMessageConverter от spring как:
public class CustomJacksonConverter implements HttpMessageConverter<Object>
{
public CustomJacksonConverter()
{
super();
//this.delegate.getObjectMapper().setConfig(this.delegate.getObjectMapper().getSerializationConfig().withView(Views.ClientView.class));
this.delegate.getObjectMapper().configure(MapperFeature.DEFAULT_VIEW_INCLUSION, true);
this.delegate.getObjectMapper().setSerializationInclusion(Include.NON_NULL);
}
// a real message converter that will respond to methods and do the actual work
private MappingJackson2HttpMessageConverter delegate = new MappingJackson2HttpMessageConverter();
@Override
public boolean canRead(Class<?> clazz, MediaType mediaType) {
return delegate.canRead(clazz, mediaType);
}
@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return delegate.canWrite(clazz, mediaType);
}
@Override
public List<MediaType> getSupportedMediaTypes() {
return delegate.getSupportedMediaTypes();
}
@Override
public Object read(Class<? extends Object> clazz,
HttpInputMessage inputMessage) throws IOException,
HttpMessageNotReadableException {
return delegate.read(clazz, inputMessage);
}
@Override
public void write(Object obj, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException
{
synchronized(this)
{
String userAgent = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getHeader("userAgent");
if ( userAgent != null )
{
switch (userAgent)
{
case "IOS" :
this.delegate.getObjectMapper().setConfig(this.delegate.getObjectMapper().getSerializationConfig().withView(Views.IOS.class));
break;
case "Android" :
this.delegate.getObjectMapper().setConfig(this.delegate.getObjectMapper().getSerializationConfig().withView(Views.Android.class));
break;
case "Web" :
this.delegate.getObjectMapper().setConfig(this.delegate.getObjectMapper().getSerializationConfig().withView( Views.Web.class));
break;
default:
this.delegate.getObjectMapper().setConfig(this.delegate.getObjectMapper().getSerializationConfig().withView( null ));
break;
}
}
else
{
// reset to default view
this.delegate.getObjectMapper().setConfig(this.delegate.getObjectMapper().getSerializationConfig().withView( null ));
}
delegate.write(obj, contentType, outputMessage);
}
}
}
Теперь нужно сказать spring использовать этот пользовательский конвертер json, просто поместив его в dispatcher-servlet.xml
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean id="jsonConverter" class="com.mactores.org.CustomJacksonConverter" >
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
То, как вы сможете решить, какие поля нужно сериализовать.
Ответ 6
мы использовали пользовательскую сериализацию, но теперь я больше не могу использовать POJO, так как все больше клиентов будут получать доступ к нашему сервису отдыха. как я могу все еще настраивать сериализацию определенных полей? только что опубликовал этот вопрос Пользовательская сериализация на основе атрибута в JSON
Ответ 7
Если вы не хотите загрязнять вашу модель аннотациями и хотите выполнять некоторые пользовательские операции, вы можете использовать миксины.
ObjectMapper mapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
simpleModule.setMixInAnnotation(Person.class, PersonMixin.class);
mapper.registerModule(simpleModule);
Отменить возраст:
public abstract class PersonMixin {
@JsonSerialize(using = PersonAgeSerializer.class)
public String age;
}
Делайте все, что вам нужно с возрастом:
public class PersonAgeSerializer extends JsonSerializer<Integer> {
@Override
public void serialize(Integer integer, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString(String.valueOf(integer * 52) + " months");
}
}