私は、会社でさまざまなサービス用に複数の小さな Java RESTful クライアント ライブラリを作成して遊んでいます。ほとんどの場合、サーバー側では何も変更できず、Jerseyのコードを記述して既存の RESTful API とやり取りする必要があります。
環境
ご存知のように、私はJSON を使用するためにJacksonと一緒に Jersey を使用してきました。POJO にクエリを実行するときは JSON からデシリアライズし、POJO を送信する必要があるときはそれを JSON 本体にシリアライズします。この2種類のスニペットは、今まで私のために仕事をしてきました...
クエリと逆シリアル化
ClientResponse response = webResource
.path("/path/to/resource")
.queryParam("key", "value")
.accept(Mediatype.APPLICATION_JSON)
.get(ClientResponse.class);
// (...) Check response status code
MyClassPojo pojo = response.getEntity(MyClassPojo.class);
シリアル化と送信
ClientResponse response = webResource
.path("/path/to/resource")
.type(Mediatype.APPLICATION_JSON_TYPE)
.accept(Mediatype.APPLICATION_JSON)
.post(ClientResponse.class, pojo)
// (...) Check response status code
問題
POJO を送信するための JSON 本文を受け入れない RESTful サーバーに直面しています。機能しているように見える唯一のことは、クエリパラメーターを使用することです。
たとえば、オブジェクトを送信したい場合
public MyClassPojo {
public int attr1;
public String attr2;
}
MyClassPojo pojo = new MyClassPojo();
pojo.attr1 = 42;
pojo.attr2 = "Foo bar";
JSONでシリアル化したかったのですが:
{
"attr1": 42,
"attr2": "Foo bar"
}
しかし、この特定の RESTful サーバーはクエリ パラメータを想定しています。
?attr1=42&attr2=Foo+bar
質問
これはちょっとひどいですが、私には選択肢がありません...そして、Jerseyでこれを達成する簡単な方法があることを今願っています.RESTfulサーバーに送信するために、オブジェクトをクエリパラメーターとして自動的にシリアル化するにはどうすればよいですか?
注: @Jukkaが回答したため、この質問を閉じました。私のように、実際に x-www-form-urlencoded データを送信する方法を探している場合は、作成した新しい質問を参照することを躊躇しないでください。私は何かを働かせようとしています...
アップデート
@Jukka のアイデアに従って、次のメソッドを作成しました。
public MultivaluedMap<String, String> toQueryParams() {
final MultivaluedMap<String, String> queryParams = new Form();
final Field[] fields = getClass().getDeclaredFields();
for (Field field : fields) {
final boolean accessible = field.isAccessible();
try {
field.setAccessible(true);
final Object value = field.get(this);
if (value != null) {
final String name = field.getName();
queryParams.add(name, value.toString());
}
} catch (IllegalAccessException e) {
LOGGER.error("Error accessing a field", e);
} finally {
field.setAccessible(accessible);
}
}
return queryParams;
}
これは素晴らしい出発点であり、実際に Query Params が必要な場合は完璧に機能します。私の場合、混乱してしまい、実際には x-www-form-urlencoded! が必要です。そのためには、MessageBodyWriter を作成する必要がありました。
私のフォームエンコーディングプロバイダー
@Produces(MediaType.APPLICATION_FORM_URLENCODED)
public class MyFormEncodingProvider implements MessageBodyWriter<Object> {
private static final String ENCODING = "UTF-8";
@Override
public boolean isWriteable(Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
return true;
}
@Override
public long getSize(Object obj, Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
return -1;
}
@Override
public void writeTo(Object obj, Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, Object> stringObjectMultivaluedMap, OutputStream outputStream) throws IOException, WebApplicationException {
final Writer osWriter = new OutputStreamWriter(outputStream);
final MultivaluedMap<String, String> fieldsAndValues = getFieldsAndValues(obj);
boolean firstVal = true;
for (Entry<String, List<String>> entry : fieldsAndValues.entrySet()) {
final List<String> values = entry.getValue();
if (values == null || values.size() == 0) {
if (!firstVal) {
osWriter.write("&");
}
osWriter.write(entry.getKey() + "=");
firstVal = false;
} else {
for (String value : values) {
if (!firstVal) {
osWriter.write("&");
}
osWriter.write(entry.getKey() + "=" + URLEncoder.encode(value, ENCODING));
firstVal = false;
}
}
}
osWriter.flush();
osWriter.close();
}
private static MultivaluedMap<String, String> getFieldsAndValues(Object obj) {
// Find all available fields
final Collection<Field> allFields = new ArrayList<>();
Class<?> clazz = obj.getClass();
while (clazz != null && clazz != Object.class) {
Collections.addAll(allFields, clazz.getDeclaredFields());
clazz = clazz.getSuperclass();
}
// Get all non-null values
final MultivaluedMap<String, String> queryParams = new Form();
for (Field field : allFields) {
final boolean accessible = field.isAccessible();
try {
field.setAccessible(true);
final Object value = field.get(obj);
if (value != null) {
final String name = field.getName();
queryParams.add(name, value.toString());
}
} catch (IllegalAccessException e) {
Logger.getLogger(AbstractIMSPojo.class).error("Error accessing a field", e);
} finally {
field.setAccessible(accessible);
}
}
return queryParams;
}
}