5

私は、会社でさまざまなサービス用に複数の小さな 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;
    }
}
4

1 に答える 1

6

この種のビューを POJO に実装するだけです。

class Pojo {
    ...
   public MultiValuedMap<String,String> asQueryParams() {
       ...
   }
}

結果を に渡しWebResource.queryParams(..)ます。

于 2013-06-12T17:43:10.037 に答える