在使用GOOGLE BUFFER的时候经常要编写存根在生成类,而有往往和数据库通信的实体类又要独立出来,怎么办了能不能通过实体类来生成PROTO存根文件,在通过调用protoc.exe来生成BUFFER类了,为了提高开发效率最近就用JAVA的反射技术和JAVA的注解技术来编写了一个小工具,专门从实体到存根在从存根到BUFFER的工具类。
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.ElementType;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Proto {
String protoPackage() default "";
String packageName() default "";
String className() default "";
boolean subClass() default false;
}
类注解
package com.buffer.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.ElementType;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Fields {
String fieldType() default "required";
String fieldName() default "";
String protoType() default "";
String mapping() default "";
int fieldIndex() default -1;
String defValue() default "";
String enums() default "";
}
字段注解
package com.buffer.transform;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import com.buffer.annotation.Fields;
import com.buffer.annotation.Proto;
import com.buffer.util.TypeHandler;
public class JavaTransformProtos {
private String srcClassPath = "";
private String protoFilePath = "";
private String protoFileName = "";
private String projectDir = "";
private String classPackage = "";
public JavaTransformProtos(String classPackage, String protoFileDir) throws Exception {
File currentFile = new File("");
projectDir = currentFile.getCanonicalPath();
this.classPackage = classPackage;
System.out.println(classPackage);
this.srcClassPath = projectDir + "/src/" + classPackage.replace(".", "/");;
System.out.println(srcClassPath);
this.protoFilePath = projectDir + "/" + protoFileDir;
File protoDir = new File(this.protoFilePath);
if(!protoDir.isDirectory()) {
protoDir.mkdirs();
}
}
public void startTransform() throws Exception {
File pojoPackage = new File(srcClassPath);
for(String classFile : pojoPackage.list()) {
String className = classFile.substring(0, classFile.indexOf("."));
System.out.println(className);
Class<?> clazz = Class.forName(classPackage + "." + className);
System.out.println(clazz.getName());
Proto proto = clazz.getAnnotation(Proto.class);
if(proto != null && !proto.subClass()) {
String protoFile = transform(clazz);
if(protoFile != null) {
System.out.println(protoFile);
protoFileName = clazz.getSimpleName() + "Proto.proto";
System.out.println(protoFilePath + "/" + protoFileName);
File writeProtoFile = new File(protoFilePath + "/" + protoFileName);
FileOutputStream out = new FileOutputStream(writeProtoFile);
out.write(protoFile.getBytes());
out.flush();
out.close();
}
}
}
buildJava();
}
public void buildJava() throws Exception {
Runtime run = Runtime.getRuntime();
BufferedReader reader = null;
File file = new File(protoFilePath);
for(String protoName : file.list()) {
System.out.println(protoName);
String commend = projectDir + "/protoc.exe -I=" + protoFilePath + " --java_out=" + projectDir + "/src/" + " " + protoFilePath + "/" + protoName;
System.out.println(commend);
Process process = run.exec(commend);
reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = null;
while((line = reader.readLine()) != null) {
System.out.println(line);
}
}
}
private String transform(Class<?> clazz) throws Exception {
Proto proto = clazz.getAnnotation(Proto.class);
if(proto != null) {
String protoFile = "";
String protoPackage = "";
String packageName = "";
String className = "";
if(!proto.subClass()) {
if(!proto.protoPackage().equals("")) {
protoPackage = "package " + proto.protoPackage() + ";\n";
}
if(!proto.packageName().equals("")) {
packageName = "option java_package = \"" + proto.packageName() + "\";\n";
} else {
System.out.println("default:" + clazz.getPackage());
packageName = "option java_package = \"" + clazz.getPackage() + "\";\n";
}
if(!proto.className().equals("")) {
className = "option java_outer_classname = \"" + proto.className() + "\";\n";
} else {
System.out.println("default:" + clazz.getSimpleName());
className = "option java_outer_classname = \"" + clazz.getSimpleName() + "\";\n";
}
}
String messageName = "message " + clazz.getSimpleName() + " {\n";
String protoFields = "";
String subProto = "";
String enumType = "";
int defaultIndex = 1;
for(Field field : clazz.getDeclaredFields()) {
String protoField = "";
Fields fieldAnno = field.getAnnotation(Fields.class);
if(fieldAnno != null) {
String fieldType = fieldAnno.fieldType();
String fieldName = fieldAnno.fieldName();
String protoType = fieldAnno.protoType();
int index = fieldAnno.fieldIndex();
String mapping = fieldAnno.mapping();
String defValue = fieldAnno.defValue();
String enums = fieldAnno.enums();
if(!fieldType.equals("")) {
protoField += fieldType;
}
if(!protoType.equals("")) {
protoField += " " + protoType;
} else if(enums.equals("") && mapping.equals("")){
protoType = TypeHandler.getProtoType(field.getType().getName());
if(protoType == null) {
throw new Exception("@Fields mapping error Class can not find");
}
protoField += " " + protoType;
} else if(!enums.equals("")){
Class<?> enumClass = Class.forName(enums);
int enumIndex = 1;
String enumName = enumClass.getSimpleName();
enumType = "enum " + enumName + " {\n";
for(Field enumField : enumClass.getFields()) {
enumType += enumField.getName() + "=" + enumIndex + ";\n";
enumIndex++;
}
enumType += "}\n";
protoFields += enumType;
protoField += " " + enumName;
}
if(!mapping.equals("")) {
Class<?> mappingClazz = Class.forName(mapping);
subProto = transform(mappingClazz);
protoFields += subProto;
protoField += " " + mappingClazz.getSimpleName();
}
if(!fieldName.equals("")) {
protoField += " " + fieldName;
} else {
protoField += " " + field.getName();
}
if(index != -1) {
protoField += " = " + index;
} else {
protoField += " = " + defaultIndex;
}
if(!defValue.equals("")) {
switch(protoType) {
case "string" : {
defValue = "\"" + defValue + "\"";
break;
}
case "float" : {
defValue = "" + Float.parseFloat(defValue);
break;
}
case "double" : {
defValue = "" + Double.parseDouble(defValue);
break;
}
case "int32":
case "int64": {
defValue = "" + Integer.parseInt(defValue);
break;
}
}
protoField += " [default = " + defValue + "]";
}
protoFields += protoField +";\n";
protoField = "";
defaultIndex++;
}
}
protoFile = protoPackage + packageName + className + messageName + protoFields;
protoFile += "}\n";
return protoFile;
} else {
return null;
}
}
public static void main(String[] args) throws Exception {
JavaTransformProtos jtp = new JavaTransformProtos("com.pojo", "proto");
jtp.startTransform();
}
}
处理类
package com.buffer.util;
import java.util.HashMap;
import java.util.Map;
public class TypeHandler {
private static Map<String, String> typeMap = new HashMap<String, String>();
static {
typeMap.put("byte", "int32");
typeMap.put("java.lang.Byte", "int32");
typeMap.put("short", "int32");
typeMap.put("java.lang.Short", "int32");
typeMap.put("int", "int32");
typeMap.put("java.lang.Integer", "int32");
typeMap.put("long", "int64");
typeMap.put("java.lang.Long", "int64");
typeMap.put("float", "float");
typeMap.put("java.lang.Float", "float");
typeMap.put("double", "double");
typeMap.put("java.lang.Double", "double");
typeMap.put("java.lang.String", "string");
typeMap.put("boolean", "bool");
typeMap.put("java.lang.Boolean", "bool");
typeMap.put("com.google.protobuf.ByteString", "bytes");
}
public static String getProtoType(String javaType) {
System.out.println(javaType);
return typeMap.get(javaType);
}
}
基本对象类型映射
package com.pojo;
import java.util.ArrayList;
import java.util.List;
import com.buffer.annotation.Fields;
import com.buffer.annotation.Proto;
@Proto(protoPackage="com.test", packageName="com.pojo", className="MemberOrder")
public class Member {
@Fields
private long uid;
@Fields(fieldType="optional", fieldName="username", protoType="string", fieldIndex=2, defValue="134567")
private String username;
@Fields
private String password;
@Fields(fieldType="repeated", mapping="com.pojo.Order")
private List<Order> orders = new ArrayList<Order>();
public long getUid() {
return uid;
}
public void setUid(long uid) {
this.uid = uid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public List<Order> getOrders() {
return orders;
}
public void setOrders(List<Order> orders) {
this.orders = orders;
}
}
测试类1
package com.pojo;
import com.buffer.annotation.Fields;
import com.buffer.annotation.Proto;
@Proto(subClass=true)
public class Order {
@Fields(fieldType="required", fieldName="orderId", protoType="int32", fieldIndex=1)
private int orderId;
@Fields(fieldType="optional", fieldName="productName", protoType="string", fieldIndex=2)
private String productName;
@Fields(enums="com.pojo.OrderType", defValue="BUY")
private OrderType orderType;
private Member member;
public int getOrderId() {
return orderId;
}
public void setOrderId(int orderId) {
this.orderId = orderId;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public Member getMember() {
return member;
}
public void setMember(Member member) {
this.member = member;
}
public OrderType getOrderType() {
return orderType;
}
public void setOrderType(OrderType orderType) {
this.orderType = orderType;
}
}
测试类2
package com.pojo;
public enum OrderType {
GROUPBUY,
BUY
}
测试类3
使用方法在你的工程的ENTITY对象上加上注解,在构造方法中传入ENTITY对象的包路径格式为 例:com.entity 在传入存根要存放的位置 ,运行程序就可以在类注解指定的包中生成BUFFER类,请一定要将protoc.exe拷贝到项目根目录下。如我的项目名称是bufferTools那么就拷贝到这个目录下。