com.baidu.bjf.remoting.protobuf.CodedConstant Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jprotobuf-jre Show documentation
Show all versions of jprotobuf-jre Show documentation
A very useful utility library for java programmer using google protobuf.
The newest version!
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.baidu.bjf.remoting.protobuf;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.baidu.bjf.remoting.protobuf.descriptor.DescriptorProtoPOJO;
import com.baidu.bjf.remoting.protobuf.descriptor.EnumDescriptorProtoPOJO;
import com.baidu.bjf.remoting.protobuf.descriptor.EnumOptionsPOJO;
import com.baidu.bjf.remoting.protobuf.descriptor.EnumValueDescriptorProtoPOJO;
import com.baidu.bjf.remoting.protobuf.descriptor.ExtensionRangePOJO;
import com.baidu.bjf.remoting.protobuf.descriptor.FieldDescriptorProtoPOJO;
import com.baidu.bjf.remoting.protobuf.descriptor.FileDescriptorProtoPOJO;
import com.baidu.bjf.remoting.protobuf.descriptor.Label;
import com.baidu.bjf.remoting.protobuf.descriptor.MessageOptionsPOJO;
import com.baidu.bjf.remoting.protobuf.descriptor.ServiceDescriptorProtoPOJO;
import com.baidu.bjf.remoting.protobuf.descriptor.Type;
import com.baidu.bjf.remoting.protobuf.utils.ClassHelper;
import com.baidu.bjf.remoting.protobuf.utils.FieldInfo;
import com.baidu.bjf.remoting.protobuf.utils.StringUtils;
import com.google.protobuf.ByteString;
import com.google.protobuf.CodedOutputStream;
import com.google.protobuf.DescriptorProtos.FileDescriptorProto;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.DescriptorValidationException;
import com.google.protobuf.Descriptors.FileDescriptor;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.WireFormat;
import com.squareup.protoparser.EnumType;
import com.squareup.protoparser.EnumType.Value;
import com.squareup.protoparser.MessageType;
import com.squareup.protoparser.Option;
import com.squareup.protoparser.ProtoFile;
import com.squareup.protoparser.ProtoSchemaParser;
/**
* Utility class for codec.
*
* @author xiemalin
* @since 1.0.0
*/
public class CodedConstant {
/** The descriptor codec. */
private static Codec descriptorCodec = ProtobufProxy.create(FileDescriptorProtoPOJO.class);
/** default proto file name. */
public static final String DEFAULT_FILE_NAME = "jprotobuf_autogenerate";
/**
* get field name.
*
* @param order field order
* @return field name
*/
private static String getFieldName(int order) {
String fieldName = "f_" + order;
return fieldName;
}
/**
* get mapped type defined java expression.
*
* @param order field order
* @param type field type
* @param express java expression
* @param isList is field type is a {@link List}
* @return full java expression
*/
public static String getMappedTypeDefined(int order, FieldType type, String express, boolean isList) {
String fieldName = getFieldName(order);
if ((type == FieldType.STRING || type == FieldType.BYTES) && !isList) {
// add null check
String code = "com.google.protobuf.ByteString " + fieldName + "=null;\n";
code += "if (!CodedConstant.isNull(" + express + ")) {\n";
String method = "copyFromUtf8";
if (type == FieldType.BYTES) {
method = "copyFrom";
}
code += fieldName + " = com.google.protobuf.ByteString." + method + "(" + express + ");\n";
code += "}";
return code;
}
// add null check
String defineType = type.getJavaType();
if (isList) {
defineType = "List";
}
String code = defineType + " " + fieldName + "=null;\n";
code += "if (!CodedConstant.isNull(" + express + ")) {\n";
code += fieldName + "=" + express + ";\n";
code += "}";
return code;
}
/**
* Gets the mapped type size.
*
* @param field field
* @param order field order
* @param type field type
* @param isList is field type is a {@link List}
* @param debug debug mode if true enable debug.
* @param path the path
* @return full java expression
*/
public static String getMappedTypeSize(FieldInfo field, int order, FieldType type, boolean isList, boolean debug,
File path) {
String fieldName = getFieldName(order);
String spath = "ProtobufProxy.OUTPUT_PATH.get()";
if (isList) {
String typeString = type.getType().toUpperCase();
return "CodedConstant.computeListSize(" + order + "," + fieldName + ", FieldType." + typeString + ","
+ Boolean.valueOf(debug) + "," + spath + ");\n";
}
if (type == FieldType.OBJECT) {
String typeString = type.getType().toUpperCase();
return "CodedConstant.computeSize(" + order + "," + fieldName + ", FieldType." + typeString + ","
+ Boolean.valueOf(debug) + "," + spath + ");\n";
}
String t = type.getType();
if (type == FieldType.STRING || type == FieldType.BYTES) {
t = "bytes";
}
t = capitalize(t);
boolean enumSpecial = false;
if (type == FieldType.ENUM) {
if (EnumReadable.class.isAssignableFrom(field.getField().getType())) {
String clsName = field.getField().getType().getName().replaceAll("\\$", ".");
fieldName = "((" + clsName + ") " + fieldName + ").value()";
enumSpecial = true;
}
}
if (!enumSpecial) {
fieldName = fieldName + type.getToPrimitiveType();
}
return "com.google.protobuf.CodedOutputStream.compute" + t + "Size(" + order + "," + fieldName + ");\n";
}
/**
* Compute list size.
*
* @param order field order
* @param list field value
* @param type field type of list obj
* @param debug the debug
* @param path the path
* @return full java expression
*/
public static int computeListSize(int order, List list, FieldType type, boolean debug, File path) {
int size = 0;
if (list == null || list.isEmpty()) {
return size;
}
for (Object object : list) {
size += computeSize(order, object, type, debug, path);
}
if (type != FieldType.OBJECT) {
size += list.size() * CodedOutputStream.computeTagSize(order);
}
return size;
}
/**
* get object size by {@link FieldType}.
*
* @param order the order
* @param o the o
* @param type the type
* @param debug the debug
* @param path the path
* @return the int
*/
public static int computeSize(int order, Object o, FieldType type, boolean debug, File path) {
return computeSize(order, o, type, false, debug, path);
}
/**
* get object size by {@link FieldType}.
*
* @param order the order
* @param o the o
* @param type the type
* @param list the list
* @param debug the debug
* @param path the path
* @return the int
*/
public static int computeSize(int order, Object o, FieldType type, boolean list, boolean debug, File path) {
int size = 0;
if (o == null) {
return size;
}
if (type == FieldType.OBJECT) {
Class cls = o.getClass();
Codec target = ProtobufProxy.create(cls, debug, path);
try {
size = target.size(o);
size = size + CodedOutputStream.computeRawVarint32Size(size);
return size + CodedOutputStream.computeTagSize(order);
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
if (type == FieldType.STRING) {
size = CodedOutputStream.computeStringSizeNoTag(String.valueOf(o));
} else if (type == FieldType.BOOL) {
size = CodedOutputStream.computeBoolSizeNoTag(Boolean.valueOf(String.valueOf(o)));
} else if (type == FieldType.BYTES) {
byte[] bb = (byte[]) o;
size = CodedOutputStream.computeBytesSizeNoTag(ByteString.copyFrom(bb));
} else if (type == FieldType.DOUBLE) {
size = CodedOutputStream.computeDoubleSizeNoTag(Double.valueOf(o.toString()));
} else if (type == FieldType.FIXED32 || type == FieldType.INT32 || type == FieldType.SFIXED32
|| type == FieldType.SINT32 || type == FieldType.UINT32) {
size = CodedOutputStream.computeInt32SizeNoTag(Integer.valueOf(o.toString()));
} else if (type == FieldType.FIXED64 || type == FieldType.INT64 || type == FieldType.SFIXED64
|| type == FieldType.SINT64 || type == FieldType.UINT64) {
size = CodedOutputStream.computeInt64SizeNoTag(Long.valueOf(o.toString()));
} else if (type == FieldType.FLOAT) {
size = CodedOutputStream.computeFloatSizeNoTag(Float.valueOf(o.toString()));
} else if (type == FieldType.ENUM) {
if (o instanceof EnumReadable) {
size = CodedOutputStream.computeInt32SizeNoTag(((EnumReadable) o).value());
} else if (o instanceof Enum) {
size = CodedOutputStream.computeInt32SizeNoTag(((Enum) o).ordinal());
}
}
return size;
}
/**
* get mapped object byte write java expression.
*
* @param field the field
* @param prefix the prefix
* @param order field order
* @param type field type
* @param isList the is list
* @return full java expression
*/
public static String getMappedWriteCode(FieldInfo field, String prefix, int order, FieldType type, boolean isList) {
String fieldName = getFieldName(order);
StringBuilder ret = new StringBuilder();
ret.append("if (").append(fieldName).append("!=null){");
if (isList) {
String typeString = type.getType().toUpperCase();
ret.append("CodedConstant.writeToList(").append(prefix).append(",");
ret.append(order).append(",").append("FieldType.").append(typeString);
ret.append(",").append(fieldName).append(");\n}");
return ret.toString();
} else {
// not list so should add convert to primitive type
boolean enumSpecial = false;
if (type == FieldType.ENUM) {
if (EnumReadable.class.isAssignableFrom(field.getField().getType())) {
String clsName = ClassHelper.getInternalName(field.getField().getType().getName());
fieldName = "((" + clsName + ") " + fieldName + ").value()";
enumSpecial = true;
}
}
if (!enumSpecial) {
fieldName = fieldName + type.getToPrimitiveType();
}
}
if (type == FieldType.OBJECT) {
String typeString = type.getType().toUpperCase();
ret.append("CodedConstant.writeObject(").append(prefix).append(",");
ret.append(order).append(",").append("FieldType.").append(typeString);
ret.append(",").append(fieldName).append(", false)").append(CodeGenerator.JAVA_LINE_BREAK).append("}")
.append(CodeGenerator.LINE_BREAK);
;
return ret.toString();
}
if (type == FieldType.STRING || type == FieldType.BYTES) {
ret.append(prefix).append(".writeBytes(").append(order);
ret.append(", ").append(fieldName).append(")").append(CodeGenerator.JAVA_LINE_BREAK).append("}")
.append(CodeGenerator.LINE_BREAK);
;
return ret.toString();
}
String t = type.getType();
t = capitalize(t);
ret.append(prefix).append(".write").append(t).append("(").append(order);
ret.append(", ").append(fieldName).append(")").append(CodeGenerator.JAVA_LINE_BREAK).append("}")
.append(CodeGenerator.LINE_BREAK);
;
return ret.toString();
}
/**
* write list to {@link CodedOutputStream} object.
*
* @param out target output stream to write
* @param order field order
* @param type field type
* @param list target list object to be serialized
* @throws IOException Signals that an I/O exception has occurred.
*/
public static void writeToList(CodedOutputStream out, int order, FieldType type, List list) throws IOException {
if (list == null || list.isEmpty()) {
return;
}
for (Object object : list) {
writeObject(out, order, type, object, true);
}
}
/**
* Write object to byte array by {@link FieldType}.
*
* @param out the out
* @param order the order
* @param type the type
* @param o the o
* @param list the list
* @throws IOException Signals that an I/O exception has occurred.
*/
public static void writeObject(CodedOutputStream out, int order, FieldType type, Object o, boolean list)
throws IOException {
if (o == null) {
return;
}
if (type == FieldType.OBJECT) {
Class cls = o.getClass();
Codec target = ProtobufProxy.create(cls);
out.writeRawVarint32(makeTag(order, WireFormat.WIRETYPE_LENGTH_DELIMITED));
out.writeRawVarint32(target.size(o));
target.writeTo(o, out);
return;
}
if (type == FieldType.BOOL) {
out.writeBool(order, (Boolean) o);
} else if (type == FieldType.BYTES) {
byte[] bb = (byte[]) o;
out.writeBytes(order, ByteString.copyFrom(bb));
} else if (type == FieldType.DOUBLE) {
out.writeDouble(order, (Double) o);
} else if (type == FieldType.FIXED32) {
out.writeFixed32(order, (Integer) o);
} else if (type == FieldType.FIXED64) {
out.writeFixed64(order, (Long) o);
} else if (type == FieldType.FLOAT) {
out.writeFloat(order, (Float) o);
} else if (type == FieldType.INT32) {
out.writeInt32(order, (Integer) o);
} else if (type == FieldType.INT64) {
out.writeInt64(order, (Long) o);
} else if (type == FieldType.SFIXED32) {
out.writeSFixed32(order, (Integer) o);
} else if (type == FieldType.SFIXED64) {
out.writeSFixed64(order, (Long) o);
} else if (type == FieldType.SINT32) {
out.writeSInt32(order, (Integer) o);
} else if (type == FieldType.SINT64) {
out.writeSInt64(order, (Long) o);
} else if (type == FieldType.STRING) {
out.writeBytes(order, ByteString.copyFromUtf8(String.valueOf(o)));
} else if (type == FieldType.UINT32) {
out.writeUInt32(order, (Integer) o);
} else if (type == FieldType.UINT64) {
out.writeUInt64(order, (Long) o);
} else if (type == FieldType.ENUM) {
int value = 0;
if (o instanceof EnumReadable) {
value = ((EnumReadable) o).value();
} else if (o instanceof Enum) {
value = ((Enum) o).ordinal();
}
out.writeEnum(order, value);
}
}
/**
* get required field check java expression.
*
* @param order field order
* @param field java field
* @return full java expression
*/
public static String getRequiredCheck(int order, Field field) {
String fieldName = getFieldName(order);
String code = "if (" + fieldName + "== null) {\n";
code += "throw new UninitializedMessageException(CodedConstant.asList(\"" + field.getName() + "\"));\n";
code += "}\n";
return code;
}
/**
* get return required field check java expression.
*
* @param express java expression
* @param field java field
* @return full java expression
*/
public static String getRetRequiredCheck(String express, Field field) {
String code = "if (CodedConstant.isNull(" + express + ")) {\n";
code += "throw new UninitializedMessageException(CodedConstant.asList(\"" + field.getName() + "\"));\n";
code += "}\n";
return code;
}
/**
* check object is null.
*
* @param o to check
* @return true if is null
*/
public static boolean isNull(Object o) {
return o == null;
}
/**
* check double is null.
*
* @param o to check
* @return true if is null
*/
public static boolean isNull(double o) {
return false;
}
/**
* check int is null.
*
* @param o to check
* @return true if is null
*/
public static boolean isNull(int o) {
return false;
}
/**
* check byte is null.
*
* @param o to check
* @return true if is null
*/
public static boolean isNull(byte o) {
return false;
}
/**
* check short is null.
*
* @param o to check
* @return true if is null
*/
public static boolean isNull(short o) {
return false;
}
/**
* check long is null.
*
* @param o to check
* @return true if is null
*/
public static boolean isNull(long o) {
return false;
}
/**
* check float is null.
*
* @param o to check
* @return true if is null
*/
public static boolean isNull(float o) {
return false;
}
/**
* check char is null.
*
* @param o to check
* @return true if is null
*/
public static boolean isNull(char o) {
return false;
}
/**
* As list.
*
* @param value the value
* @return the list
*/
public static List asList(String value) {
return Arrays.asList(value);
}
/**
*
* Capitalizes a String changing the first letter to title case as per {@link Character#toTitleCase(char)}. No other
* letters are changed.
*
*
* @param str the String to capitalize, may be null
* @return the capitalized String, null
if null String input
*/
public static String capitalize(String str) {
int strLen;
if (str == null || (strLen = str.length()) == 0) {
return str;
}
return new StringBuilder(strLen).append(Character.toTitleCase(str.charAt(0))).append(str.substring(1))
.toString();
}
/** bit type tag value. */
static final int TAG_TYPE_BITS = 3;
/**
* make protobuf tag.
*
* @param fieldNumber field number order
* @param wireType wireformat type
* @return tag id
*/
public static int makeTag(final int fieldNumber, final int wireType) {
return (fieldNumber << TAG_TYPE_BITS) | wireType;
}
/**
* Gets the enum name.
*
* @param e the e
* @param value the value
* @return the enum name
*/
public static String getEnumName(Enum[] e, int value) {
if (e != null) {
int toCompareValue;
for (Enum en : e) {
if (en instanceof EnumReadable) {
toCompareValue = ((EnumReadable) en).value();
} else {
toCompareValue = en.ordinal();
}
if (value == toCompareValue) {
return en.name();
}
}
}
return "";
}
/**
* Gets the descriptor.
*
* @param cls the cls
* @return the descriptor
* @throws IOException Signals that an I/O exception has occurred.
*/
public static Descriptor getDescriptor(Class cls) throws IOException {
String idl = ProtobufIDLGenerator.getIDL(cls);
ProtoFile file = ProtoSchemaParser.parse(DEFAULT_FILE_NAME, idl);
FileDescriptorProtoPOJO fileDescriptorProto = new FileDescriptorProtoPOJO();
fileDescriptorProto.name = DEFAULT_FILE_NAME;
fileDescriptorProto.pkg = file.getPackageName();
fileDescriptorProto.dependencies = file.getDependencies();
fileDescriptorProto.publicDependency = convertList(file.getPublicDependencies());
fileDescriptorProto.weakDependency = null; // XXX
fileDescriptorProto.messageTypes = new ArrayList();
fileDescriptorProto.enumTypes = new ArrayList();
fileDescriptorProto.services = new ArrayList();
Set messageSet = new HashSet();
Set enumSet = new HashSet();
List typeElements = file.getTypes();
if (typeElements != null) {
for (com.squareup.protoparser.Type typeElement : typeElements) {
if (typeElement instanceof MessageType) {
messageSet.add(typeElement.getName());
} else if (typeElement instanceof EnumType) {
enumSet.add(typeElement.getName());
}
}
for (com.squareup.protoparser.Type typeElement : typeElements) {
if (typeElement instanceof MessageType) {
fileDescriptorProto.messageTypes.add(
getDescritorProtoPOJO(fileDescriptorProto, (MessageType) typeElement, messageSet, enumSet));
} else if (typeElement instanceof EnumType) {
fileDescriptorProto.enumTypes.add(
getDescritorProtoPOJO(fileDescriptorProto, (EnumType) typeElement, messageSet, enumSet));
}
}
}
FileDescriptorProto fileproto;
try {
byte[] bs = descriptorCodec.encode(fileDescriptorProto);
fileproto = FileDescriptorProto.parseFrom(bs);
} catch (InvalidProtocolBufferException e) {
throw new IOException("Failed to parse protocol buffer descriptor for generated code.", e);
}
FileDescriptor fileDescriptor;
try {
fileDescriptor =
FileDescriptor.buildFrom(fileproto, new com.google.protobuf.Descriptors.FileDescriptor[] {});
} catch (DescriptorValidationException e) {
throw new IOException(e.getMessage(), e);
}
return fileDescriptor.getMessageTypes().get(0);
}
/**
* Gets the descritor proto pojo.
*
* @param fileDescriptorProto the file descriptor proto
* @param typeElement the type element
* @param messageSet the message set
* @param enumSet the enum set
* @return the descritor proto pojo
*/
private static DescriptorProtoPOJO getDescritorProtoPOJO(FileDescriptorProtoPOJO fileDescriptorProto,
MessageType typeElement, Set messageSet, Set enumSet) {
DescriptorProtoPOJO ret = new DescriptorProtoPOJO();
ret.name = typeElement.getName();
ret.fields = new ArrayList();
ret.nestedTypes = new ArrayList();
ret.enumTypes = new ArrayList();
ret.extensionRanges = new ArrayList();
ret.extensions = new ArrayList();
ret.options = new ArrayList();
List fields = typeElement.getFields();
if (fields != null) {
FieldDescriptorProtoPOJO fieldDescriptorProto;
for (com.squareup.protoparser.MessageType.Field fieldElement : fields) {
fieldDescriptorProto = new FieldDescriptorProtoPOJO();
fieldDescriptorProto.name = fieldElement.getName();
fieldDescriptorProto.extendee = null; // XXX
fieldDescriptorProto.number = fieldElement.getTag();
com.squareup.protoparser.MessageType.Label label = fieldElement.getLabel();
if (label == com.squareup.protoparser.MessageType.Label.OPTIONAL) {
fieldDescriptorProto.label = Label.LABEL_OPTIONAL;
} else if (label == com.squareup.protoparser.MessageType.Label.REQUIRED) {
fieldDescriptorProto.label = Label.LABEL_REQUIRED;
} else if (label == com.squareup.protoparser.MessageType.Label.REPEATED) {
fieldDescriptorProto.label = Label.LABEL_REPEATED;
}
String type = fieldElement.getType();
fieldDescriptorProto.defaultValue = fieldElement.getDefault();
try {
fieldDescriptorProto.type = Type.valueOf("TYPE_" + type.toUpperCase());
} catch (Exception e) {
if (messageSet.contains(type)) {
fieldDescriptorProto.type = Type.TYPE_MESSAGE;
} else {
fieldDescriptorProto.type = Type.TYPE_ENUM;
}
fieldDescriptorProto.typeName = "." + fileDescriptorProto.pkg + "." + type;
}
ret.fields.add(fieldDescriptorProto);
}
}
List nestedElements = typeElement.getNestedTypes();
if (nestedElements != null) {
for (com.squareup.protoparser.Type nestedTypeElement : nestedElements) {
if (nestedTypeElement instanceof MessageType) {
ret.nestedTypes.add(getDescritorProtoPOJO(fileDescriptorProto, (MessageType) nestedTypeElement,
messageSet, enumSet));
} else {
ret.enumTypes.add(getDescritorProtoPOJO(fileDescriptorProto, (EnumType) nestedTypeElement,
messageSet, enumSet));
}
}
}
return ret;
}
/**
* Gets the descritor proto pojo.
*
* @param fileDescriptorProto the file descriptor proto
* @param typeElement the type element
* @param messageSet the message set
* @param enumSet the enum set
* @return the descritor proto pojo
*/
private static EnumDescriptorProtoPOJO getDescritorProtoPOJO(FileDescriptorProtoPOJO fileDescriptorProto,
EnumType typeElement, Set messageSet, Set enumSet) {
EnumDescriptorProtoPOJO ret = new EnumDescriptorProtoPOJO();
ret.name = typeElement.getName();
ret.values = new ArrayList();
ret.options = new ArrayList();
List values = typeElement.getValues();
if (values != null) {
EnumValueDescriptorProtoPOJO fieldDescriptorProto;
for (com.squareup.protoparser.EnumType.Value fieldElement : values) {
fieldDescriptorProto = new EnumValueDescriptorProtoPOJO();
fieldDescriptorProto.name = fieldElement.getName();
fieldDescriptorProto.number = fieldElement.getTag();
ret.values.add(fieldDescriptorProto);
}
}
List