1

応答をログに記録するために ObjectMapper を使用して、どこかに bytebuffer を含む複雑なオブジェクトを文字列にシリアル化しようとしています。これにより、バイトバッファ内のカーソル位置が変更され、応答が単純に破損します。

私が使用しているコードスニペット:

import org.codehaus.jackson.map.ObjectMapper;

private static final ObjectMapper MAPPER = new ObjectMapper();

public static String serializeToString(final Object obj) {
    Preconditions.checkArgument(obj != null, "Object to be serialized is null");
    try {
        final String str = MAPPER.writeValueAsString(obj);
        if (Strings.isNullOrEmpty(str)) {
            log.warn("Serialized to null/empty string");
        }
        return str;
    } catch (final JsonGenerationException e) {
        throw new IllegalArgumentException("Json generation exception occured in de-serializing obj", e);
    } catch (final JsonMappingException e) {
        throw new IllegalArgumentException("Json mapping exception occured in de-serializing obj", e);
    } catch (final IOException e) {
        throw new IllegalArgumentException("IO exception occured in de-serializing obj", e);
    }
}

上記のメソッドに、内部に bytebuffer を持つ複雑なオブジェクトを渡しました。上記のメソッドを呼び出す前後にバイトバッファを出力しました。

public static void main(final String[] args) throws SecurityException, NoSuchMethodException {
    final String x =
            "Random data i am using for this test for byte buffer. Random data i am using for this test for byte buffer";
    final byte[] byteArr = x.getBytes();
    final ByteBuffer bb = ByteBuffer.wrap(byteArr);
    System.out.println("before bytebuffer :" + bb);
    String stringData = SerializerUtil.serializeToString(bb); // In real i am passing a complex structure having
                                                              // bytebuffer inside
    System.out.println(stringData);
    System.out.println("after bytebuffer :" + bb);
}

出力:

before bytebuffer :java.nio.HeapByteBuffer[pos=0 lim=106 cap=106]

{"short":21089,"char":"\u6e64","int":1869422692,"long":7022344510808023405,"float":2.0790493E-19,"double":6.687717052371733E223,"direct":false,"readOnly":false}

after bytebuffer :java.nio.HeapByteBuffer[pos=28 lim=106 cap=106]

この (pos=0 から pos=28 への) 位置の変更は、送信された応答を単純に破損します。byteBuffer に影響を与えずに、この複雑なオブジェクトを文字列に変換する方法はありますか?

どんな助けでも大歓迎です。

4

1 に答える 1

2

明らかに、ByteBufferプロパティを別の構造化クラスとしてシリアル化するのではなく、コンテンツだけを文字列としてシリアル化します。これを行う 1 つの方法は@JsonProperty、フィールドを直接シリアライズしようとする代わりに、メソッドにアノテーションを使用して、そのメソッドを使用するようマッパーに指示することです。次のような Bean があるとします。

class Stuff {

    private ByteBuffer data;

    public Stuff() {
    }

    public Stuff(ByteBuffer data) {
        super();
        this.data = data;
    }

    public ByteBuffer getData() {
        return data;
    }

    public void setData(ByteBuffer data) {
        this.data = data;
    }

    @JsonProperty(value = "data")
    public String convertData() {
        return new String(data.array());
    }

    @JsonProperty("data")
    public void convertData(String s) {
        data = ByteBuffer.wrap(s.getBytes());
    }

}

マッパーは convertData メソッドを使用して ByteBuffer データ プロパティをシリアライズおよびデシリアライズしますが、通常の Java Bean プロパティ メソッドを引き続き使用できます。

更新

シリアル化されたクラスは変更できないため、一部の高度な JACKSON を使用した代替方法を次に示します。まず、カスタム シリアライザーとデシリアライザーを作成します。

static class ByteBufferSerializer extends JsonSerializer<ByteBuffer> {

    @Override
    public void serialize(ByteBuffer value, JsonGenerator jgen,
            SerializerProvider provider) throws IOException,
            JsonProcessingException {
        jgen.writeString(new String(value.array()));
    }
}

static class ByteBufferDeserializer extends JsonDeserializer<ByteBuffer> {

    @Override
    public ByteBuffer deserialize(JsonParser jp,
            DeserializationContext context) throws IOException,
            JsonProcessingException {
        return ByteBuffer.wrap(jp.getText().getBytes());
    }

}

次に、Mixin インターフェイスを作成して、実際のターゲット クラスでは提供できないプロパティの注釈を提供します。

static interface Mixin {

    @JsonSerialize(using = ByteBufferSerializer.class, contentAs = String.class)
    ByteBuffer getData();

    @JsonDeserialize(using = ByteBufferDeserializer.class, contentAs = String.class)
    void setData(ByteBuffer data);

}

さらに、オブジェクト マッパーの構成に使用するモジュールを作成し、mixin インターフェイスを追加します。

static class MyModule extends SimpleModule {
    public MyModule() {
        super("ByteBuffer wrangling");
    }

    @Override
    public void setupModule(SetupContext context) {
        context.setMixInAnnotations(Stuff.class, Mixin.class);
    }
}

最後に、モジュールをマッパーに登録します。

    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(new MyModule());

ほら、ケーキ!:-)

于 2013-06-25T09:31:18.983 に答える