読者です 読者をやめる 読者になる 読者になる

JerseyでJSONシリアライズ対象外のプロパティを指定する (2)

Jersey Java JAX-RS

JerseyでJSONシリアライズ対象外のプロパティを指定する (1)
こちらの続きです。JAX-RS(Jersey)でJavaオブジェクトをJSON形式に変換する際に、@XmlTransientをつけて対象外のプロパティを指定しましたが、今回はJacksonMixInAnnotationsを使用する方法を試してみました。この方法ではシリアライズ対象オブジェクトにアノテーション等を追加することなく、変換対象や名前等を変更することができます。
例えば、以下のようなクラスをJSONに変換するとします。

public class Person {
	public String name;
	public String emailAddress;
	public int age;
	// ...
}

ここで、"age"は変換対象外とし"emailAddress"は"email"という名前に変換したいという場合には以下のようなMixinクラスを作成します。

abstract class PersonMixin {
	PersonMixin (@JsonProperty("email") String emailAddress, @JsonIgnore ("age") int h) { }
}

この例ではコンストラクタにアノテーションをつけていますが、abstractなgetter?を定義してそこにアノテーションをつけることもできますし、PersonMixin自体に@JsonIgnoreProperties等を付けてまとめて指定することもできます。

このMixinを使用するには以下のようにします。

ObjectMapper om = new ObjectMapper();
om.getSerializationConfig().addMixInAnnotations(Person.class, PersonMixin.class);
String str = om.writeValueAsString(obj);

個別のMixinを適用するのではなく、設定をまとめて管理するには、Moduleを使うことができます。

public class MyModule extends SimpleModule {
	public MyModule() {
		super("MyModule", new Version(0, 0, 1, "SNAPSHOT"));
	}

	@Override
	public void setupModule(SetupContext context) {
		super.setupModule(context);
		context.setMixInAnnotations(Person.class, PersonMixin.class);
	}
}

このModuleを使用するには以下のようにします。

ObjectMapper om = new ObjectMapper();
om.registerModule(new MyModule());
String str = om.writeValueAsString(obj);

JerseyでJacksonMixInAnnotationsを使用する

JerseyでJacksonMixInAnnotationsを使用する場合には、ObjectMapperを返すProviderを作成して登録する必要があります。Providerのクラスは以下のようになります。

import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import org.codehaus.jackson.map.ObjectMapper;

@Provider
@Produces(MediaType.APPLICATION_JSON)
public class ObjectMapperProvider implements ContextResolver<ObjectMapper> {

	private ObjectMapper mapper;

	public ObjectMapperProvider() {
		mapper = new ObjectMapper();
		mapper.registerModule(new MyModule());
	}

	@Override
	public ObjectMapper getContext(Class<?> type) {
        return mapper;
	}
}

ObjectMapperはConfigurationを変更しなければスレッドセーフということなのでインスタンスを使い回しています。
TomcatなどのJAX-RSに対応していないコンテナの場合にはApplicationクラスで登録します。

import javax.ws.rs.core.Application;

public class MyApplication extends Application {
	// ...

	@Override
	public Set<Object> getSingletons() {
		Set<Object> classes = new HashSet<Object>();
		classes.add(new ObjectMapperProvider());
		return classes;
	}
}

これでJSONの生成にこのObjectMapperが使用されるので、MyModuleでの指定が反映されます。