在我的一个应用场景中,使用脚本根据配置直接生成java pojo源码和对应proto文件,并在pojo中加上自身的编解码方法。这样的话若采用调用protoc生成代理的策略显得十分笨拙,另外既然protobuf能用代理类去解编码数据,那理论上,直接编解码数据也是可以实现的,但遗憾的是google并没有提供这方面的文档说明。
下面是编解码代码的实现:
package miniserver.util;
import static miniserver.util.ReflectionUtil.gatherAllFields;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.google.protobuf.DescriptorProtos.FileDescriptorProto;
import com.google.protobuf.DescriptorProtos.FileDescriptorSet;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.DescriptorValidationException;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.Descriptors.FileDescriptor;
import com.google.protobuf.DynamicMessage;
import com.google.protobuf.DynamicMessage.Builder;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Message;
public class ProtoParserOrBuilder {
private Map<String, Descriptor> descriptors = null;
private static final String TEMP_DIR = "D://";
public static final String PROTOC_PATH = System.getProperty("user.dir")
+ "/protoc/protoc.exe";
private File descFile;
public ProtoParserOrBuilder() {
descriptors = new HashMap<String, Descriptor>();
}
public ProtoParserOrBuilder(File proto) {
descriptors = new HashMap<String, Descriptor>();
init(proto);
}
private void init(File proto) {
if (descFile != null && descFile.exists()) {
descFile.delete();
}
this.descFile = createDescripFile(proto);
FileInputStream fin = null;
try {
fin = new FileInputStream(descFile);
FileDescriptorSet descriptorSet = FileDescriptorSet.parseFrom(fin);
for (FileDescriptorProto fdp : descriptorSet.getFileList()) {
FileDescriptor fd = FileDescriptor.buildFrom(fdp,
new FileDescriptor[] {});
for (Descriptor descriptor : fd.getMessageTypes()) {
String className = descriptor.getName();
this.descriptors.put(className, descriptor);
}
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (DescriptorValidationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
if (fin != null) {
fin.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private File createDescripFile(File proto) {
try {
Runtime run = Runtime.getRuntime();
String descFileName = System.currentTimeMillis()
+ "FastProtoParser.desc";
String protoPath = proto.getCanonicalPath();
String protoFPath = proto.getParentFile().getAbsolutePath();
String cmd = PROTOC_PATH + " -I=" + protoFPath
+ " --descriptor_set_out=" + TEMP_DIR + descFileName + " "
+ protoPath;
System.out.println(cmd);
// 如果不正常终止, 则生成desc文件失败
Process p = run.exec(cmd);
if (p.waitFor() != 0) {
if (p.exitValue() == 1) {// p.exitValue()==0表示正常结束,1:非正常结束
throw new RuntimeException("protoc 编译器报错");
}
}
return new File(TEMP_DIR + descFileName);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public <T> T parse(Class<T> clazz, byte[] bytes) {
String className = clazz.getSimpleName();
Descriptor desc = this.descriptors.get(className);
Map<String, String> fields = new HashMap<String, String>();
try {
DynamicMessage message = DynamicMessage.parseFrom(desc, bytes);
Map<FieldDescriptor, Object> fieldDescs = message.getAllFields();
for (Map.Entry<FieldDescriptor, Object> entry : fieldDescs
.entrySet()) {
fields.put(entry.getKey().getName(), entry.getValue()
.toString());
}
T instance = clazz.newInstance();
List<Field> fieldList = ReflectionUtil.gatherAllFields(clazz);
for (Field f : fieldList) {
ReflectionUtil.fillField(fields, instance, f);
}
return instance;
} catch (InvalidProtocolBufferException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public byte[] build(Object obj) {
Class<? extends Object> clazz = obj.getClass();
String className = clazz.getSimpleName();
Descriptor desc = this.descriptors.get(className);
Builder builder = DynamicMessage.newBuilder(desc);
List<FieldDescriptor> fieldDescs = desc.getFields();
List<Field> fields = gatherAllFields(clazz);
try {
Map<String, Object> fieldValues = new HashMap<String, Object>();
for (Field field : fields) {
field.setAccessible(true);
String fieldName = field.getName();
Object fieldValueObject;
fieldValueObject = field.get(obj);
if (fieldValueObject != null) {
fieldValues.put(fieldName, fieldValueObject);
}
}
for (FieldDescriptor fieldDesc : fieldDescs) {
String fieldName = fieldDesc.getName();
Object val = fieldValues.get(fieldName);
if (val != null) {
builder.setField(fieldDesc, val);
}
}
Message message = builder.build();
return message.toByteArray();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
@Override
protected void finalize() throws Throwable {
super.finalize();
this.descFile.delete();
}
}
已经经过验证,与代理类生成的数据是一模一样的,解析也没有问题,请放心使用。
严正声明,本博的原创网站是ITeye,如再有转载请注明出处.谢谢合作.
分享到:
相关推荐
webservice1 pojo实现0配置
POJO In action 代码 POJO In action 代码 POJO In action 代码
POJO转Map代码,POJO转Map代码POJO转Map代码POJO转Map代码
SSM笔记-POJO,测试POJO,SpringMVC会根据请求参数名和POJO类的属性名自动匹配为对应对象填充值
dao和mapper 抛弃了mybatis插件生成的一个POJO一个mapper 很冗余的数据,这里直接生成增删改查3个dao/mapper对照,依托于IDEA-DataBase-Tools能够直接选取需要生成POJOS 表模型的选择器。可以很方便的生成pojo/dao/...
本POJO代码生成器采用Java的Swing技术编码实现,是绿色免费工具,可以自由传播。 由于本工具的内部实现较菜,所以还请反编译高手手下留情,让我留几分颜面。^_^ 作者本人只用过Oracle、MySQL、MS SQL Server这三款...
netty pojo netty pojo替换 channelbuffer
Mybatis pojo插件生成工具 把包下载下来,配置到eclipse中,project new 可以看到mybatis插件已经安装好
POJO javaBean EJB JNDI 理解及区别
参照https://github.com/joelittlejohn/jsonschema2pojo/wiki/Getting-Started的步骤Using jsonschema2pojo within your Java project (embedded)
本POJO代码生成器采用Java的Swing技术编码实现,是绿色免费工具,可以自由传播。 由于本工具的内部实现较烂,所以还请反编译高手手下留情,让我留几分颜面。^_^ 由于本人只用过Oracle、DB2、MySQL、MS SQL Server这...
利用Mybatis逆向工程来生成pojo,dao和mapper。然后将pojo实体类和dao拷贝到工程当中。这样可以快速地实现数据库的开发
hibernate生成pojo
NULL 博文链接:https://lcb530.iteye.com/blog/288977
This is a easy POJO class!
1.1.1版本 简单数据库逆向工程 自动生成POJO类 JAVA WEB jsp
本资源为博客中ssm项目实战第二天需要用到的pojo类的压缩包,包含该项目所有的pojo类
当我们从数据库读出数据得到ResultSet... 这里面还有一段代码,是把数据库结果集封装到Map代替pojo,有些人也许认为不符合OO思想,但是这还没有成为一个定论,而且Map和List,在迭代时的效率非常高,我认为值得这样去做
保存资源,以后开发备用,数据表生成pojo,java代码。
jsp上使用object[]看不懂吧?写vo太烦琐了?ok,都交给map吧、本工具类的使命就是让map代替所有的vo,让编程变得更美好。 附有详细的使用例子。 java精英团队十年编程精华。