代码自动生成工具(二)-miniproto的java库实现
2017-06-25 16:32
731 查看
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
本项目暂命名miniproto1.0。
有限的兼容protobuf的语法规则 和 编码规则。包括protobuf2.0和3.0的编码规则。
实现proto结构的序列化、反序列化功能。
代码生成工具,需要boost库支持(主要用了spirit库做文本解析),本人用的是boost.1.64.0。
生成后的代码,仅需要miniproto自身提供的lib(对应c++)、dll(对应c#)、jar(对应java),不需要其他第三方库。
完整项目下载地址(vs工程编译请选择release/win32)
Github项目地址
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
前文介绍了miniproto,这里介绍其java库的实现
java本着一切皆对象的思想,容器中不能放基本数据类型,只能放基本数据类型的封装类对象。
也就是说List<int>是非法的,List<Integer>才合法。
因此miniproto中对于array/set/map这种类型的字段来说,不可避免的会出现拆装箱操作,比较蛋疼。
对于java中的泛型,个人理解,就是发明出来,用来在编译时做参数类型校验的一个玩意。
上面说了,java中一切皆对象,容器中只能放对象。
所以我向一个List中,同时放Integer,和String,在有泛型之前是没问题的。编译不会报错。
导致当你处理容器中的元素的时候,如果不小心把一个Integer强转成String处理了,就会ClassCastException。
于是有了泛型,你向List<Integer>中放一个String对象,编译器就会报错了。
然而也仅此而已了!!!
编译完之后,就没有泛型什么事了!!!
class文件中,已经没有泛型参数的信息了!!!
全部变成Object了,wtf!!!
它既没有像c++的模板机制那样,编译时,不同的泛型参数,直接生成不同的代码再编译。
也没有像c#那样,编译时先生成中间代码,泛型形参是中间代码中的一个占位符。创建实例时,再根据泛型参数的实参类型,生成不同的本地代码。
因此在miniproto中,希望通过泛型,直接进行不同数据类型的编解码功能的重载的意图就没法实现了。
当然我也不可能穷举所有参数类型,分别给出重载。
主要是map,它有key和value两个泛型参数,穷举的话,key的种类×value的种类实在太多,懒的写。
因此只能另外多传入一个类型参数(miniproto中是一个自定义枚举)。
根据这个参数,对T(运行时T已经变成Object)做强转,再去调用不同数据类型的编解码功能的重载。
jdk1.5之前我们只能用 public static final 来定义一系列的常量。1.5增加了枚举。
但是枚举是个类。
你写的 public enum XXX,最终都是被换成了public class XXX extends java.lang.Enum。
你写的枚举中的常量YYY,最终都是被换成了这个类中的 public static final XXX YYY 这样一个XXX的静态对象。
于是当我有一个数字int,我要转成对应的枚举项的时候,只能通过一个这个class XXX中的一个static方法,switch...case返回对应的YYY。
而static方法,意味着不能多态。也就是说我不能通过调用基类的接口,得到子类的实现,来完成数字转枚举。必须拿到具体的枚举类型,才能完成转化。
因此,在编解码功能的底层实现中,对于枚举类型,只能当成一个Integer处理。
proto的message中的枚举成员,或者枚举类型的容器,只能实现成Integer,或者是List<Integer>。
在message的getter/setter中,再调用具体的枚举类型做相应转化。
下面给出ProtoTool代码,对照代码做出注释说明。具体实现就不贴了,可以去下载完整项目。
本项目暂命名miniproto1.0。
有限的兼容protobuf的语法规则 和 编码规则。包括protobuf2.0和3.0的编码规则。
实现proto结构的序列化、反序列化功能。
代码生成工具,需要boost库支持(主要用了spirit库做文本解析),本人用的是boost.1.64.0。
生成后的代码,仅需要miniproto自身提供的lib(对应c++)、dll(对应c#)、jar(对应java),不需要其他第三方库。
完整项目下载地址(vs工程编译请选择release/win32)
Github项目地址
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
前文介绍了miniproto,这里介绍其java库的实现
1、容器
先吐槽一下java的容器。java本着一切皆对象的思想,容器中不能放基本数据类型,只能放基本数据类型的封装类对象。
也就是说List<int>是非法的,List<Integer>才合法。
因此miniproto中对于array/set/map这种类型的字段来说,不可避免的会出现拆装箱操作,比较蛋疼。
2、泛型
再吐槽一下java中的泛型。对于java中的泛型,个人理解,就是发明出来,用来在编译时做参数类型校验的一个玩意。
上面说了,java中一切皆对象,容器中只能放对象。
所以我向一个List中,同时放Integer,和String,在有泛型之前是没问题的。编译不会报错。
导致当你处理容器中的元素的时候,如果不小心把一个Integer强转成String处理了,就会ClassCastException。
于是有了泛型,你向List<Integer>中放一个String对象,编译器就会报错了。
然而也仅此而已了!!!
编译完之后,就没有泛型什么事了!!!
class文件中,已经没有泛型参数的信息了!!!
全部变成Object了,wtf!!!
它既没有像c++的模板机制那样,编译时,不同的泛型参数,直接生成不同的代码再编译。
也没有像c#那样,编译时先生成中间代码,泛型形参是中间代码中的一个占位符。创建实例时,再根据泛型参数的实参类型,生成不同的本地代码。
因此在miniproto中,希望通过泛型,直接进行不同数据类型的编解码功能的重载的意图就没法实现了。
当然我也不可能穷举所有参数类型,分别给出重载。
主要是map,它有key和value两个泛型参数,穷举的话,key的种类×value的种类实在太多,懒的写。
因此只能另外多传入一个类型参数(miniproto中是一个自定义枚举)。
根据这个参数,对T(运行时T已经变成Object)做强转,再去调用不同数据类型的编解码功能的重载。
3、枚举
java的槽点实在有点多。jdk1.5之前我们只能用 public static final 来定义一系列的常量。1.5增加了枚举。
但是枚举是个类。
你写的 public enum XXX,最终都是被换成了public class XXX extends java.lang.Enum。
你写的枚举中的常量YYY,最终都是被换成了这个类中的 public static final XXX YYY 这样一个XXX的静态对象。
于是当我有一个数字int,我要转成对应的枚举项的时候,只能通过一个这个class XXX中的一个static方法,switch...case返回对应的YYY。
而static方法,意味着不能多态。也就是说我不能通过调用基类的接口,得到子类的实现,来完成数字转枚举。必须拿到具体的枚举类型,才能完成转化。
因此,在编解码功能的底层实现中,对于枚举类型,只能当成一个Integer处理。
proto的message中的枚举成员,或者枚举类型的容器,只能实现成Integer,或者是List<Integer>。
在message的getter/setter中,再调用具体的枚举类型做相应转化。
4、ProtoTool
基本雷同C++的ProtoTool(除掉上面吐槽的几点)。针对不同数据类型,给出一系列的编解码功能实现。下面给出ProtoTool代码,对照代码做出注释说明。具体实现就不贴了,可以去下载完整项目。
package common.miniproto; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Iterator; public class ProtoTool { // Zigzag编/解码 public static int Zigzag(int value); public static long Zigzag(long value); public static int DeZigzag(int value); public static long DeZigzag(long value); // Number编/解码 public static int NumberByteSize(int value); public static int NumberByteSize(long value); public static int NumberByteSize(float value); public static int NumberByteSize(double value); public static void NumberCode(int value, OutputStream buf) throws IOException; public static void NumberCode(long value, OutputStream buf) throws IOException; public static void NumberCode(float value, OutputStream buf) throws IOException; public static void NumberCode(double value, OutputStream buf) throws IOException; public static int NumberDecode(int value, InputStream buf) throws IOException; public static long NumberDecode(long value, InputStream buf) throws IOException; public static float NumberDecode(float value, InputStream buf) throws IOException; public static double NumberDecode(double value, InputStream buf) throws IOException; // proto key编/解码 public static int KeyByteSize(int num, ProtoDefine.ProtoWireType type); public static void KeyCode(int num, ProtoDefine.ProtoWireType type, OutputStream buf) throws IOException; public static int KeyDecode(InputStream buf) throws IOException; // 未知字段解码 public static void UnknownDecode(ProtoDefine.ProtoWireType type, InputStream buf) throws IOException; // 单个字段编/解码 public static int BoolByteSize(Boolean value); public static void BoolCode(Boolean value, OutputStream buf) throws IOException; public static Boolean BoolDecode(InputStream buf) throws IOException; public static int Int32ByteSize(Integer value); public static void Int32Code(Integer value, OutputStream buf) throws IOException; public static Integer Int32Decode(InputStream buf) throws IOException; public static int SInt32ByteSize(Integer value); public static void SInt32Code(Integer value, OutputStream buf) throws IOException; public static Integer SInt32Decode(InputStream buf) throws IOException; public static int UInt32ByteSize(Integer value); public static void UInt32Code(Integer value, OutputStream buf) throws IOException; public static Integer UInt32Decode(InputStream buf) throws IOException; public static int Int64ByteSize(Long value); public static void Int64Code(Long value, OutputStream buf) throws IOException; public static Long Int64Decode(InputStream buf) throws IOException; public static int SInt64ByteSize(Long value); public static void SInt64Code(Long value, OutputStream buf) throws IOException; public static Long SInt64Decode(InputStream buf) throws IOException; public static int UInt64ByteSize(Long value); public static void UInt64Code(Long value, OutputStream buf) throws IOException; public static Long UInt64Decode(InputStream buf) throws IOException; public static int EnumByteSize(Integer value); public static void EnumCode(Integer value, OutputStream buf) throws IOException; public static Integer EnumDecode(InputStream buf) throws IOException; public static int FloatByteSize(Float value); public static void FloatCode(Float value, OutputStream buf) throws IOException; public static Float FloatDecode(InputStream buf) throws IOException; public static int DoubleByteSize(Double value); public static void DoubleCode(Double value, OutputStream buf) throws IOException; public static Double DoubleDecode(InputStream buf) throws IOException; public static int StringByteSize(String value) throws IOException; public static void StringCode(String value, OutputStream buf) throws IOException; public static String StringDecode(InputStream buf) throws IOException; public static <M extends ProtoBase> int MessageByteSize(M value) throws IOException; public static <M extends ProtoBase> void MessageCode(M value, OutputStream buf) throws IOException; public static <M extends ProtoBase> M MessageDecode(InputStream buf, Class<M> cls) throws IOException; // Array,Set容器中,每一个元素的编/解码 private static <T> int EntryByteSize(T value, ProtoDefine.ProtoFieldType type) throws IOException; private static <T> void EntryCode(T value, OutputStream buf, ProtoDefine.ProtoFieldType type) throws IOException; private static <T> void EntryDecode(Collection<T> values, InputStream buf, ProtoDefine.ProtoFieldType type) throws IOException; private static <T extends ProtoBase> void EntryDecode(Collection<T> values, InputStream buf, ProtoDefine.ProtoFieldType type, Class<T> cls) throws IOException; // Array容器的编/解码 // 内部调用EntryByteSize/Code/Decode private static <T> int ArrayByteSizeWithoutLength(List<T> values, ProtoDefine.ProtoFieldType type) throws IOException; public static <T> int ArrayByteSize(List<T> values, ProtoDefine.ProtoFieldType type) throws IOException; public static <T> void ArrayCode(List<T> values, OutputStream buf, ProtoDefine.ProtoFieldType type) throws IOException; public static <T> void ArrayDecode(List<T> values, InputStream buf, ProtoDefine.ProtoFieldType type) throws IOException; public static <T extends ProtoBase> void ArrayDecode(List<T> values, InputStream buf, ProtoDefine.ProtoFieldType type, Class<T> cls) throws IOException; // Set容器的编/解码 // 内部调用EntryByteSize/Code/Decode private static <T> int SetByteSizeWithoutLength(Set<T> values, ProtoDefine.ProtoFieldType type) throws IOException; public static <T> int SetByteSize(Set<T> values, ProtoDefine.ProtoFieldType type) throws IOException; public static <T> void SetCode(Set<T> values, OutputStream buf, ProtoDefine.ProtoFieldType type) throws IOException; public static <T> void SetDecode(Set<T> values, InputStream buf, ProtoDefine.ProtoFieldType type) throws IOException; // Map容器中,每一个元素的编/解码 private static <K, V> int EntryByteSizeWithoutLength(K key, V value, ProtoDefine.ProtoFieldType keyType, ProtoDefine.ProtoFieldType valueType) throws IOException; public static <K, V> int EntryByteSize(K key, V value, ProtoDefine.ProtoFieldType keyType, ProtoDefine.ProtoFieldType valueType) throws IOException; public static <K, V> void EntryCode(K key, V value, OutputStream buf, ProtoDefine.ProtoFieldType keyType, ProtoDefine.ProtoFieldType valueType) throws IOException; public static <K, V> void EntryDecode(Map<K, V> values, InputStream buf, ProtoDefine.ProtoFieldType keyType, ProtoDefine.ProtoFieldType valueType) throws IOException; public static <K, V extends ProtoBase> void EntryDecode(Map<K, V> values, InputStream buf, ProtoDefine.ProtoFieldType keyType, ProtoDefine.ProtoFieldType valueType, Class<V> cls) throws IOException; // Map容器的编/解码 // 内部调用EntryByteSize/Code/Decode private static <K, V> int MapByteSizeWithoutLength(Map<K, V> values, ProtoDefine.ProtoFieldType keyType, ProtoDefine.ProtoFieldType valueType) throws IOException; public static <K, V> int MapByteSize(Map<K, V> values, ProtoDefine.ProtoFieldType keyType, ProtoDefine.ProtoFieldType valueType) throws IOException; public static <K, V> void MapCode(Map<K, V> values, OutputStream buf, ProtoDefine.ProtoFieldType keyType, ProtoDefine.ProtoFieldType valueType) throws IOException; public static <K, V> void MapDecode(Map<K, V> values, InputStream buf, ProtoDefine.ProtoFieldType keyType, ProtoDefine.ProtoFieldType valueType) throws IOException; public static <K, V extends ProtoBase> void MapDecode(Map<K, V> values, InputStream buf, ProtoDefine.ProtoFieldType keyType, ProtoDefine.ProtoFieldType valueType, Class<V> cls) throws IOException; }
5、ProtoBase
基本雷同C++的ProtoBase,多一个toString接口,方便调式时显示message的内容信息package common.miniproto; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Field; public abstract class ProtoBase { public ProtoBase(); public abstract int ByteSize() throws IOException; public abstract void Code(OutputStream buf, int size) throws IOException; public abstract void Decode(InputStream buf, int size) throws IOException; public abstract void Clear(); public abstract void Release(); public boolean SerializeToStream(OutputStream buf, int size); public boolean ParseFromStream(InputStream buf, int size); public String toString(); }
6、ProtoBitMap
基本雷同c++的ProtoBitMap,位图长度作为构造函数的参数,多一个toString接口。package common.miniproto; public class ProtoBitMap { public ProtoBitMap(int count); public void SetBit(int index); public void ClearBit(int index); public boolean HasBit(int index); public void Clear(); private byte[] m_Bits = null; public String toString(); }
相关文章推荐
- 代码自动生成工具(二)-miniproto的c++库实现
- 代码自动生成工具(二)-miniproto的c#库实现
- 自动生成代码工具【JAVA版】
- Eclipse插件Lambok,实现自动生成Java代码
- MyBatisGenerator 自动生成java代码(反向工具)
- 用代码实现在eclipse中自动生成package_这个功能很有用_java版
- UML工具推荐 Poseidon版本 可以免费下载,自动生成代码 C++ Java C# VB.NET等 (来自德国汉堡的国际性建模软件开发商Gentleware AG的)
- 自己写的一个代码自动生成工具_java版_源码下载
- 代码自动生成工具_java版
- Mybatis Generator Configuration Eclipse自动生成代码工具使用及实现基本crud
- jnaerator:java调用动态库的神器,JNA代码自动生成工具
- IBM将公布能够自动生成Java代码的编程工具
- JAVA 自动生成对应数据库表的JPA代码工具
- JAVA中Mybatis连接oracle数据库自动生成代码工具
- java代码通过freemarker模板实现自动生成dao,model,service,jsp
- java代码自动生成UML-工具集
- 代码在线自动生成工具,在线生成java代码,springmvc框架,mapper,实体类,控制器,页面代码
- [C#]一步一步开发自己的自动代码生成工具之二:SQLServer字段与C#变量的对应转化
- j2ee代码自动生成工具HaivDb4J2ee
- java-web-PIO实现自动生成excel录入模板(实现下拉列表框)[原创]