4

私はApache CXF(バージョン2.2.2)JAX-RSでいくつかの作業を行ってきました。ビジネス メソッドが呼び出される前に、CXF 要求ハンドラーにデータ検証レイヤーを導入しようとしています。幸いなことに:)、リクエストハンドラー(DataValidationHandler)での入力パラメーターの処理に関する問題が発生しています。リクエスト ハンドラーのコード行に従って、JSON オブジェクトを手動で読み取ることができます。ただし、CXF フレームワークに登録されている JSONProvider と重複しています。JSON オブジェクトの入力ストリームは 1 回しか読み取れないため、そうしないと、「java.io.EOFException: No content to map due to end of input」という例外が発生します。さらに、複製された JSON オブジェクトのデシリアライズは、パフォーマンスに影響を与えます。次のコードは参考用のサンプルです。

JSON オブジェクトを HTTP 本文から手動で読み取ります。

OperationResourceInfo ori = paramMessage.getExchange().get(OperationResourceInfo.class);
MultivaluedMap<String, String> values = new MetadataMap<String, String>();
List<Object> objList = JAXRSUtils.processParameters(ori, values, paramMessage);

JSONProvider を CXF JAX-RS フレームワークに登録します。

<bean id="JSONProvider" class="com.accela.govxml2.jaxrs.util.JSONProvider"></bean>

入力ストリームから JSON オブジェクトを Java オブジェクトに読み取ります。

public Object readFrom(......){
    ObjectMapper objectMapper = new ObjectMapper();
    Object result = objectMapper.readValue(entityStream, TypeFactory.defaultInstance().constructType(genericType));
    Return result;
}

コード行に従って、パスパラメーターを手動で処理しています。

OperationResourceInfo ori = paramMessage.getExchange().get(OperationResourceInfo.class);
URITemplate t1 = ori.getClassResourceInfo().getURITemplate();
URITemplate t2 = ori.getURITemplate();
UriInfo uriInfo = new UriInfoImpl(paramMessage, null);
MultivaluedMap<String, String> map = new MetadataMap<String, String>();
t1.match(uriInfo.getPath(), map);
String str = map.get(URITemplate.FINAL_MATCH_GROUP).get(0);
t2.match(str, map);
String pathParameter= null;
if (map.containsKey("pathParam") && !ValidationUtil.isEmpty(map.get("pathParam")))
{
    pathParameter= map.get("pathParam").get(0);
}

私の質問はここにあります:

  1. 一般的に、リクエストハンドラーでhttpボディのPOST / PUT入力パラメーターを処理する方法は?
  2. 入力パラメータを効率的に読み取るためのパフォーマンスの問題を回避するにはどうすればよいですか?
  3. CXF(JSONProvider)によるパラメータ読み込みとビジネスメソッド呼び出しの間にバリデーション(ハンドラ/インターセプタ)層を挿入する方法はありますか?
  4. パスパラメータを処理するエレガントな方法はありますか?

ご協力いただきありがとうございます。コメントや提案をいただければ幸いです。

よろしく、ディラン

4

2 に答える 2

1

DataValidation Interceptor を読み取りパラメーター フェーズに挿入する別の方法を見つけました。フレームワークに登録された JSONProvider によって逆シリアル化されたメッセージ コンテンツから、逆シリアル化された入力モデルを再利用できます。入力モデルを一度だけデシリアライズするだけなので、パフォーマンスを向上させることができます。

public class DataValidationInInterceptor extends AbstractPhaseInterceptor<Message>
{
public DataValidationInInterceptor()
{
    super(Phase.READ);
}

@Override
public void handleMessage(Message message)
{
    OperationResourceInfo ori = message.getExchange().get(OperationResourceInfo.class);
    Method method = ori.getMethodToInvoke();
    Class<?>[] types = method.getParameterTypes();
    Type[] genericParameterTypes = method.getGenericParameterTypes();

    for (int i = 0; i < types.length; i++)
    {
        Class<?> type = types[i];
        List obj = (List) message.getContent(List.class);
        System.out.println(obj);
        System.out.println(type);
    }
}
}
于 2012-05-29T03:06:48.617 に答える
0

調査後、次の質問の回答に基づいて、入力ストリームを 2 回読み取ることができます (ストリームを 2 回読み取る)。

ただし、JSON オブジェクトのデシリアライズのパフォーマンスは依然として懸念事項です。誰がそれに対するより良い解決策を持っていますか?

リクエストをインターセプトし、メッセージの内容を CoyoteInputStream から ByteArrayInputStream に変更して、InputStream を 2 回読み取ることができるようにします。

InputStream in = message.getContent(InputStream.class);
if (in != null)
{
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    IOUtils.copy(in, baos);
    byte[] bytes = baos.toByteArray();
    ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
    message.setContent(InputStream.class, bais);
}

JSON オブジェクトを入力ストリームから Java オブジェクトに読み込む前に、ByteArrayInputStream をリセットします。

public Object readFrom(......){
    ObjectMapper objectMapper = new ObjectMapper();
    if (entityStream.markSupported())
    {
        entityStream.reset();
    }
    Object result = objectMapper.readValue(entityStream, TypeFactory.defaultInstance().constructType(genericType));
    return result;
}
于 2012-05-26T12:21:12.507 に答える