Java如何转换protobuf-net中的bcl.Decimal对象

参考文章:http://www.cnblogs.com/cuyt/p/6141723.html

    公司内部有些C#服务使用proto-net,引入了bcl.proto中的bcl.Decimal、bcl.DateTime等。对于java的proto生成代码需要对bcl.Decimal、bcl.DateTime转换成本地支持的数据类型。
    bcl.Decimal结构为32位int保存高位、64位long保存低位,signScale 保存符号(正负)及模数。转换过程如下:

一、bcl.Decimal  --> BigDecimal
  1. 将高32位的int以高位在前格式转换为4个长度的byte数组;
  2. 将低64位的long以高位在前的格式转换为8个长度的byte数组;
  3. 将两个数组组合为12长度的byte数组bigIntBytes,获取signScale的符号值sgin = (signScale & 1) == 1 ? -1 : 1; (参考bcl.Decimal 注释:the number of decimal digits (bits 1-16), and the sign (bit 0))
  4. 根据bigIntBytes和sgin获取BigInteger对象bInt,new BigInteger(sgin,bigIntBytes);
  5. 获取signScale的模数值scale = (signScale & 0b1111_1111_1111_1110) >> 1; (参考bcl.Decimal 注释:the number of decimal digits (bits 1-16), and the sign (bit 0))

     6.根据bInt和scale获取BigDecimal对象,new BigDecimal(bint, scale);

二、BigDecimal  -->bcl.Decimal

    上述过程反之即可

代码如下:
/*JDK1.7*/
public class BclUtil {
    /**
     *
     */
    private static final long TICKS_PER_MILLISECOND = 10000;
 
    private static final int SIGNSCALE_FLAG = 0b1111_1111_1111_1110;
 
    private BclUtil() {
 
    }
 
    /**
     * 转换 bcl.Decimal,返回BigDecimal<br>
     * 高位在前<br>
     *
     * @param bclDecimal
     * @return
     */
    public final static BigDecimal bclDecimalToBigDecimal(Bcl.Decimal bclDecimal) {
        if (bclDecimal == null) {
            return BigDecimal.ZERO;
        }
        byte[] deBytes = new byte[12];
        int2byte(deBytes, 0, bclDecimal.getHi());
        long2byte(deBytes, 4, bclDecimal.getLo());
        int signScale = bclDecimal.getSignScale();
        BigInteger bint = new BigInteger(getSign(signScale), deBytes);
        return new BigDecimal(bint, getScale(signScale));
    }
 
    /**
     * 转换BigDecimal,返回bcl.Decimal<br>
     * 高位在前<br>
     *
     * @param bigDecimal
     * @return
     */
    public final static Bcl.Decimal bigDecimalToBclDecimal(BigDecimal bigDecimal) {
        if (bigDecimal == null) {
            return null;
        }
        Bcl.Decimal.Builder b = Bcl.Decimal.newBuilder();
        // 获取BigInteger,必须是unscaledValue
        BigInteger bi = bigDecimal.unscaledValue();
        byte[] deBytes = new byte[12];
        byte[] bigIntegerBytes = bi.toByteArray();
        System.arraycopy(bigIntegerBytes, 0, deBytes, 12 - bigIntegerBytes.length, bigIntegerBytes.length);
        // 取高4位int
        int hi = Eutil.bytes2int(deBytes, 0);
        b.setHi(hi);
        // 取低8位long
        long lo = Eutil.bytes2long(deBytes, 4);
        b.setLo(lo);
        int signScale = getSignScale(bi.signum(), bigDecimal.scale());
        b.setSignScale(signScale);
        return b.build();
    }
 
    private static int getSignScale(int signum, int scale) {
        // 从BigInteger获取取标志位放在bit 0/从BigDecimal获取取标志位放在bit 1-16
        return getSignInSignScale(signum) | (scale << 1);
    }
 
    public final static Bcl.Decimal zeroOfBclDecimal() {
        Bcl.Decimal.Builder b = Bcl.Decimal.newBuilder();
        b.setHi(0);
        b.setLo(0);
        b.setSignScale(0);
        return b.build();
    }
 
    /**
     * 填充值符号<br>
     *
     * @param sign
     * @return
     */
    public final static byte getSignInSignScale(int sign) {
        byte signTemp = 0;
        if (sign < 0) {
            signTemp = 1;
        }
        return signTemp;
    }
 
    /**
     * 获取值符号<br>
     *
     * @param signScale
     * @return
     */
    public final static int getSign(int signScale) {
        // the number of decimal digits (bits 1-16), and the sign (bit 0)
        boolean isNegative = (signScale & 1) == 1;
        return isNegative ? -1 : 1;
    }
 
    /**
     * 获取模数
     *
     * @param signScale
     * @return
     */
    public final static int getScale(int signScale) {
        // the number of decimal digits (bits 1-16), and the sign (bit 0)
        return (signScale & SIGNSCALE_FLAG) >> 1;
    }
 
    /**
     * 获取int的byte数组,高位在前
     *
     * @param dst
     * @param pos
     * @param src
     */
    public final static void int2byte(byte[] dst, int pos, int src) {
        int2byte(dst, pos, src, true);
    }
 
    public final static byte[] int2byte(byte[] dst, int pos, int src, boolean big_endian) {
        if (big_endian) {
            dst[pos + 3] = (byte) ((src >>> 0) & 0xff);
            dst[pos + 2] = (byte) ((src >>> 8) & 0xff);
            dst[pos + 1] = (byte) ((src >>> 16) & 0xff);
            dst[pos + 0] = (byte) ((src >>> 24) & 0xff);
        } else {
            dst[pos + 0] = (byte) ((src >>> 0) & 0xff);
            dst[pos + 1] = (byte) ((src >>> 8) & 0xff);
            dst[pos + 2] = (byte) ((src >>> 16) & 0xff);
            dst[pos + 3] = (byte) ((src >>> 24) & 0xff);
        }
 
        return dst;
    }
 
    public final static byte[] int2unSignByte(byte[] dst, int pos, int src, boolean big_endian) {
        if (big_endian) {
            dst[pos + 3] = (byte) ((src >>> 0) & 0xff + 128);
            dst[pos + 2] = (byte) ((src >>> 8) & 0xff + 128);
            dst[pos + 1] = (byte) ((src >>> 16) & 0xff + 128);
            dst[pos + 0] = (byte) ((src >>> 24) & 0xff + 128);
        } else {
            dst[pos + 0] = (byte) ((src >>> 0) & 0xff + 128);
            dst[pos + 1] = (byte) ((src >>> 8) & 0xff + 128);
            dst[pos + 2] = (byte) ((src >>> 16) & 0xff + 128);
            dst[pos + 3] = (byte) ((src >>> 24) & 0xff + 128);
        }
 
        return dst;
    }
 
    /**
     * 获取long的byte数组,高位在前
     *
     * @param dst
     * @param pos
     * @param src
     */
    final static void long2byte(byte[] dst, int pos, long src) {
        long2byte(dst, pos, src, true);
    }
 
    final static void long2byte(byte[] dst, int pos, long src, boolean big_endian) {
        if (big_endian) {
            int2byte(dst, 4 + pos, (int) (src & 0xffffffff));
            int2byte(dst, 0 + pos, (int) ((src >>> 32) & 0xffffffff));
        } else {
            int2byte(dst, 0 + pos, (int) (src & 0xffffffff));
            int2byte(dst, 4 + pos, (int) ((src >>> 32) & 0xffffffff));
        }
    }
}

 

posted @ 2017-05-13 23:32  静若清池  阅读(564)  评论(1编辑  收藏  举报