Есть ли способ использовать Jackson JSON Processor для сериализации на уровне настраиваемого поля? Например, я бы хотел, чтобы класс
public class Person {
public String name;
public int age;
public int favoriteNumber;
}
сериализован в следующий JSON:
{ "name": "Joe", "age": 25, "favoriteNumber": "123" }
Обратите внимание, что age = 25 кодируется как число, а избранноеNumber = 123 - как строка . Из коробки Джексон int
направляется к номеру. В этом случае я хочу, чтобы избранное было закодировано как строка.
java
json
serialization
jackson
Стив Куо
источник
источник
Ответы:
Вы можете реализовать собственный сериализатор следующим образом:
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
за вас.источник
as=String.class
игнорируется из-заusing
параметра и здесь не требуется. Примечание: если также используется using (), он имеет приоритет (поскольку он напрямую указывает сериализатор, тогда как это будет использоваться только для определения местоположения сериализатора), и значение этого свойства аннотации игнорируется.Person implements ToJson
?as=String.class
из-за типов, которые я использовал. @ kevin-bowersox, я предлагаю обновить ваш комментарий в соответствии с тем, что сказал @GarethLatty.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: }
источник
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"}
источник
Добавьте
@JsonProperty
аннотированный геттер, который возвращает aString
, для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"} } }
источник
Если вы не хотите засорять свою модель аннотациями и хотите выполнять какие-то собственные операции, вы можете использовать миксины.
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"); } }
источник
с помощью @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>
Вот так вы сможете решить, какие поля сериализовать.
источник