ProtoStuff는 BigDecimal 직렬화/역직렬화를 지원하지 않습니까?

함께 만들고 함께 성장하기 위해 함께 노력하십시오! "너겟 데일리 뉴플랜·8월 업데이트 챌린지" 참여 12일차 입니다 . 이벤트 상세보기 클릭

저는 보통 ProtoStuff를 직렬화 도구로 사용하여 일부 POJO 개체를 직렬화하지만 실제 사용에서는 BigDecimal 개체를 직렬화할 때 문제가 있음을 발견했습니다.

  • 숫자에 관계없이 결과 바이트 배열은 동일합니다.
  • 제대로 역직렬화할 수 없음

아래에 이 문제를 기록하세요.

1. 장면 재현

우리가 사용하는 protostuff 종속성은 다음과 같습니다.

 <dependency>
    <groupId>com.dyuproject.protostuff</groupId>
    <artifactId>protostuff-core</artifactId>
    <version>1.1.3</version>
</dependency>
<dependency>
    <groupId>com.dyuproject.protostuff</groupId>
    <artifactId>protostuff-runtime</artifactId>
    <version>1.1.3</version>
</dependency>
复制代码

다음과 같이 간단한 테스트 데모를 작성하십시오.

public static byte[] serialize(Object obj) {
    Schema schema = RuntimeSchema.getSchema(obj.getClass());
    LinkedBuffer buffer = LinkedBuffer.allocate(1048576);

    byte[] protoStuff;
    try {
        protoStuff = ProtostuffIOUtil.toByteArray(obj, schema, buffer);
    } catch (Exception var8) {
        throw new RuntimeException("Failed to serializer");
    } finally {
        buffer.clear();
    }

    return protoStuff;
}

public static <T> T deserialize(byte[] paramArrayOfByte, Class<T> targetClass) {
    if (paramArrayOfByte != null && paramArrayOfByte.length != 0) {
        Schema<T> schema = RuntimeSchema.getSchema(targetClass);
        T instance = schema.newMessage();
        ProtostuffIOUtil.mergeFrom(paramArrayOfByte, instance, schema);
        return instance;
    } else {
        throw new RuntimeException("Failed to deserialize");
    }
}


@Test
public void testSer() {
    byte[] ans = serialize(new BigDecimal(20));
    byte[] ans2 = serialize(new BigDecimal(120));

    System.out.println(new String(ans));
    System.out.println(new String(ans2));

    BigDecimal res = deserialize(ans, BigDecimal.class);
    System.out.println(res);
}
复制代码

다음과 같이 실행

2. 의심되는 원인 및 대응 방법

구체적인 이유를 찾지 못했습니다. github에 문제가 있습니다: github.com/protostuff/… , 여기서 답장은

Protostuff는 내장 jdk 유형이 아닌 사용자 정의 유형(pojos)에서 작동합니다.

위의 문장은 ProtoStuff가 기본 jdk 유형이 아닌 단순 객체의 직렬화에 더 적합하므로 멤버 변수가 BigDecimal인 객체를 직렬화하는 것이 좋습니다.

다음으로 BigDecimal 멤버를 사용하여 간단한 개체를 정의해 보겠습니다.

@Data
public static class InnerDecimal {
    private BigDecimal decimal;

    public InnerDecimal() {
    }

    public InnerDecimal(BigDecimal decimal) {
        this.decimal = decimal;
    }
}

@Test
public void testSer() {
    byte[] ans = serialize(new InnerDecimal(new BigDecimal(20.123)));
    byte[] ans2 = serialize(new InnerDecimal(new BigDecimal(120.1970824)));

    System.out.println(new String(ans));
    System.out.println(new String(ans2));

    InnerDecimal res = deserialize(ans, InnerDecimal.class);
    System.out.println(res);
}
复制代码

테스트 출력은 다음과 같습니다

위의 내용은 정상적으로 동작할 수 있지만 우리가 바라던 것과는 조금 다른데 BigDecimal을 직렬화하기 위해서는 이를 감싸는 POJO를 정의해야 하는 번거로움이 있으니 BigDeimal.특별 대우

public static byte[] serialize(Object obj) {
    if (obj instanceof BigDecimal) {
        obj = ((BigDecimal) obj).toPlainString();
    }

    Schema schema = RuntimeSchema.getSchema(obj.getClass());
    LinkedBuffer buffer = LinkedBuffer.allocate(1048576);

    byte[] protoStuff;
    try {
        protoStuff = ProtostuffIOUtil.toByteArray(obj, schema, buffer);
    } catch (Exception var8) {
        throw new RuntimeException("Failed to serializer");
    } finally {
        buffer.clear();
    }

    return protoStuff;
}

public static <T> T deserialize(byte[] paramArrayOfByte, Class<T> targetClass) {
    if (paramArrayOfByte != null && paramArrayOfByte.length != 0) {
        Schema schema;
        if (targetClass.isAssignableFrom(BigDecimal.class)) {
            schema = RuntimeSchema.getSchema(String.class);
            Object instance = schema.newMessage();
            ProtostuffIOUtil.mergeFrom(paramArrayOfByte, instance, schema);
            return (T) new BigDecimal((String) instance);
        } else {
            schema = RuntimeSchema.getSchema(targetClass);
            Object instance = schema.newMessage();
            ProtostuffIOUtil.mergeFrom(paramArrayOfByte, instance, schema);
            return (T) instance;
        }
    } else {
        throw new RuntimeException("Failed to deserialize");
    }
}
复制代码

다시 테스트, 정상 실행

성명

신앙의 서신만큼 좋지는 않습니다 내용은 이미 작성되었으며 순전히 가족들에게서 나온 것입니다 개인의 한계로 인해 누락과 오역이 있을 수 밖에 없습니다 버그를 찾거나 더 나은 점이 있다면 제안, 비판 및 수정을 환영합니다. 감사합니다.

  • QQ:그레이 그레이/ 3302797840
  • 공개 번호: 회색 블로그
  • 그레이 사이트: hhui.top

추천

출처juejin.im/post/7133583979667521544