Jackson JSONプロセッサを使用してカスタムフィールドレベルのシリアル化を行う方法はありますか?例えば、私はクラスを持ちたいです
public class Person {
public String name;
public int age;
public int favoriteNumber;
}
次のJSONにシリアル化されます。
{ "name": "Joe", "age": 25, "favoriteNumber": "123" }
Age = 25はnumberとしてエンコードされ、favoriteNumber = 123はstringとしてエンコードされることに注意してください。ジャクソンは、すぐにint
を数にマーシャリングします。この場合、favoriteNumberを文字列としてエンコードする必要があります。
次のようにカスタムシリアライザーを実装できます。
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
へのオートボクシングを処理する必要があります。
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:
}
String
フィールドにfavoriteNumber
を返す@JsonProperty
注釈付きゲッターを追加します。
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"}
}
}
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"}
@ JsonViewの助けを借りて、10のプロパティを持つコアクラスを1つ持つことができるが、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
...
..
}
次に、スプリングからHttpMessageConverterクラスを単純に拡張して、カスタムJSONコンバーターを作成する必要があります。
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);
}
}
}
次に、これを単純にdispatcher-servlet.xmlに配置することにより、このカスタムJSON変換を使用するようSpringに指示する必要があります。
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean id="jsonConverter" class="com.mactores.org.CustomJacksonConverter" >
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
これにより、どのフィールドをシリアル化するかを決定できます。
モデルを注釈で汚染したくない場合や、カスタム操作を実行したい場合は、ミックスインを使用できます。
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");
}
}