下面列出了com.google.protobuf.DescriptorProtos#DescriptorProto ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Add a new record type to the meta-data.
*
* <p>
* Adding the record type involves three steps: the message type is added to the file descriptor's list of message types,
* a field of the given type is added to the union, and its primary key is set.
* Note that adding {@code UNION} record types is not allowed. To add {@code NESTED} record types, use {@link #addNestedRecordType}.
* </p>
*
* @param metaDataBuilder the meta-data builder
* @param newRecordType the new record type
* @param primaryKey the primary key of the new record type
*/
public static void addRecordType(@Nonnull RecordMetaDataProto.MetaData.Builder metaDataBuilder, @Nonnull DescriptorProtos.DescriptorProto newRecordType, @Nonnull KeyExpression primaryKey) {
RecordMetaDataOptionsProto.RecordTypeOptions.Usage newRecordTypeUsage = getMessageTypeUsage(newRecordType);
if (newRecordType.getName().equals(RecordMetaDataBuilder.DEFAULT_UNION_NAME) ||
newRecordTypeUsage == RecordMetaDataOptionsProto.RecordTypeOptions.Usage.UNION) {
throw new MetaDataException("Adding UNION record type not allowed");
}
if (newRecordTypeUsage == RecordMetaDataOptionsProto.RecordTypeOptions.Usage.NESTED) {
throw new MetaDataException("Use addNestedRecordType for adding NESTED record types");
}
if (findMessageTypeByName(metaDataBuilder.getRecordsBuilder(), newRecordType.getName()) != null) {
throw new MetaDataException("Record type " + newRecordType.getName() + " already exists");
}
DescriptorProtos.FileDescriptorProto.Builder recordsBuilder = metaDataBuilder.getRecordsBuilder();
recordsBuilder.addMessageType(newRecordType);
metaDataBuilder.setVersion(metaDataBuilder.getVersion() + 1);
metaDataBuilder.addRecordTypes(RecordMetaDataProto.RecordType.newBuilder()
.setName(newRecordType.getName())
.setPrimaryKey(primaryKey.toKeyExpression())
.setSinceVersion(metaDataBuilder.getVersion())
.build());
addFieldToUnion(fetchUnionBuilder(recordsBuilder), recordsBuilder, newRecordType);
}
/**
* Iterate through a component's path inside a proto descriptor.
*
* <p>The path is a tuple of component type and a relative position For example: [4, 1, 3, 2, 2,
* 1] or [MESSAGE_TYPE_FIELD_NUMBER, 1, NESTED_TYPE_FIELD_NUMBER, 2, FIELD_FIELD_NUMBER, 1] is
* representing the second field of the third nested message in the second message in the file
*
* @see DescriptorProtos.SourceCodeInfoOrBuilder for more info
* @param descriptor proto file descriptor
* @param path path of the element
* @return full element's path as a string
*/
private static Optional<String> getFullName(
DescriptorProtos.FileDescriptorProto descriptor, List<Integer> path) {
String fullName = descriptor.getPackage();
switch (path.get(0)) {
case DescriptorProtos.FileDescriptorProto.ENUM_TYPE_FIELD_NUMBER:
DescriptorProtos.EnumDescriptorProto enumDescriptor = descriptor.getEnumType(path.get(1));
return Optional.of(appendEnum(enumDescriptor, path, fullName));
case DescriptorProtos.FileDescriptorProto.MESSAGE_TYPE_FIELD_NUMBER:
DescriptorProtos.DescriptorProto message = descriptor.getMessageType(path.get(1));
return appendMessage(message, path, fullName);
case DescriptorProtos.FileDescriptorProto.SERVICE_FIELD_NUMBER:
DescriptorProtos.ServiceDescriptorProto serviceDescriptor =
descriptor.getService(path.get(1));
fullName += appendNameComponent(serviceDescriptor.getName());
if (path.size() > 2) {
fullName += appendNameComponent(serviceDescriptor.getMethod(path.get(3)).getName());
}
return Optional.of(fullName);
default:
return Optional.empty();
}
}
private static Optional<String> append(
DescriptorProtos.DescriptorProto messageDescriptor, List<Integer> path, String fullName) {
switch (path.get(0)) {
case DescriptorProtos.DescriptorProto.NESTED_TYPE_FIELD_NUMBER:
DescriptorProtos.DescriptorProto nestedMessage =
messageDescriptor.getNestedType(path.get(1));
return appendMessage(nestedMessage, path, fullName);
case DescriptorProtos.DescriptorProto.ENUM_TYPE_FIELD_NUMBER:
DescriptorProtos.EnumDescriptorProto enumDescriptor =
messageDescriptor.getEnumType(path.get(1));
return Optional.of(appendEnum(enumDescriptor, path, fullName));
case DescriptorProtos.DescriptorProto.FIELD_FIELD_NUMBER:
DescriptorProtos.FieldDescriptorProto fieldDescriptor =
messageDescriptor.getField(path.get(1));
return Optional.of(fullName + appendNameComponent(fieldDescriptor.getName()));
default:
return Optional.empty();
}
}
private static void recursivelyAddTypes(ImmutableMap.Builder<String, String> types, DescriptorProtos.DescriptorProto m, String protoPackage, String enclosingClassName, String javaPackage) {
// Identify current type
String protoTypeName = protoPackage + "." + m.getName();
types.put(
protoTypeName,
DOT_JOINER.join(javaPackage, enclosingClassName, m.getName()));
// Identify any nested Enums
m.getEnumTypeList().forEach(
e -> types.put(
protoPackage + "." + m.getName() + "." + e.getName(),
DOT_JOINER.join(javaPackage, enclosingClassName, m.getName(), e.getName())));
// Recursively identify any nested types
m.getNestedTypeList().forEach(
n -> recursivelyAddTypes(
types,
n,
protoPackage + "." + m.getName(),
DOT_JOINER.join(enclosingClassName, m.getName()),
javaPackage));
}
public DataVerifyPbMsgField(DescriptorProtos.DescriptorProto desc) {
super(desc.getName());
for (DescriptorProtos.FieldDescriptorProto fd : desc.getFieldList()) {
all_names.put(fd.getName(), (long) fd.getNumber());
all_numbers.add((long) fd.getNumber());
// alias extension
if (fd.getOptions().hasExtension(Xresloader.fieldAlias)) {
String alias_name = fd.getOptions().getExtension(Xresloader.fieldAlias);
if (!alias_name.isEmpty()) {
all_names.put(alias_name, (long) fd.getNumber());
}
}
}
}
private DescriptorProtos.DescriptorProto applyMessageOptionChanges(
DescriptorProtos.DescriptorProto.Builder newDescriptorBuilder,
Descriptors.Descriptor descriptor,
List<OptionChangeInfo> optionChanges) {
UnknownFieldSet unknownFieldSet = buildUnknownFieldSet(optionChanges);
DescriptorProtos.MessageOptions messageOptions =
DescriptorProtos.MessageOptions.newBuilder().setUnknownFields(unknownFieldSet).build();
return newDescriptorBuilder.setOptions(messageOptions).build();
}
/**
* Add a new {@code NESTED} record type to the meta-data. This can be used to define fields in other record types,
* but it does not add the new record type to the union.
*
* @param metaDataBuilder the meta-data builder
* @param newRecordType the new record type
*/
public static void addNestedRecordType(@Nonnull RecordMetaDataProto.MetaData.Builder metaDataBuilder, @Nonnull DescriptorProtos.DescriptorProto newRecordType) {
RecordMetaDataOptionsProto.RecordTypeOptions.Usage newRecordTypeUsage = getMessageTypeUsage(newRecordType);
if (newRecordTypeUsage != RecordMetaDataOptionsProto.RecordTypeOptions.Usage.NESTED &&
newRecordTypeUsage != RecordMetaDataOptionsProto.RecordTypeOptions.Usage.UNSET) {
throw new MetaDataException("Record type is not NESTED");
}
if (findMessageTypeByName(metaDataBuilder.getRecordsBuilder(), newRecordType.getName()) != null) {
throw new MetaDataException("Record type " + newRecordType.getName() + " already exists");
}
metaDataBuilder.getRecordsBuilder().addMessageType(newRecordType);
}
@Test
public void recordTypesWithOneOfUnion() {
try (FDBRecordContext context = fdb.openContext()) {
openMetaDataStore(context);
RecordMetaDataBuilder metaData = RecordMetaData.newBuilder().setRecords(TestRecordsOneOfProto.getDescriptor());
final KeyExpression pkey = Key.Expressions.field("rec_no");
metaData.getRecordType("MySimpleRecord").setPrimaryKey(pkey);
metaData.getRecordType("MyOtherRecord").setPrimaryKey(pkey);
metaDataStore.saveRecordMetaData(metaData);
context.commit();
}
// Add a record type to oneOf. It should fail.
try (FDBRecordContext context = fdb.openContext()) {
openMetaDataStore(context);
assertNotNull(metaDataStore.getRecordMetaData().getRecordType("MySimpleRecord"));
DescriptorProtos.DescriptorProto newRecordType = DescriptorProtos.DescriptorProto.newBuilder()
.setName("MyNewRecord")
.addField(DescriptorProtos.FieldDescriptorProto.newBuilder()
.setLabel(DescriptorProtos.FieldDescriptorProto.Label.LABEL_OPTIONAL)
.setType(DescriptorProtos.FieldDescriptorProto.Type.TYPE_INT32)
.setName("rec_no")
.setNumber(1))
.build();
MetaDataException e = assertThrows(MetaDataException.class, () -> addRecordType(newRecordType, Key.Expressions.field("rec_no")));
assertEquals(e.getMessage(), "Adding record type to oneof is not allowed");
context.commit();
}
}
@EnumSource(TestProtoFiles.class)
@ParameterizedTest(name = "noUnion [protoFile = {0}]")
public void noUnion(@Nonnull TestProtoFiles protoFile) {
int version;
try (FDBRecordContext context = fdb.openContext()) {
openMetaDataStore(context);
metaDataStore.saveRecordMetaData(protoFile.getFileDescriptor());
context.commit();
version = metaDataStore.getRecordMetaData().getVersion();
}
// Add a record type.
try (FDBRecordContext context = fdb.openContext()) {
openMetaDataStore(context);
assertEquals(version, metaDataStore.getRecordMetaData().getVersion());
DescriptorProtos.DescriptorProto newRecordType = DescriptorProtos.DescriptorProto.newBuilder()
.setName("MyNewRecord")
.addField(DescriptorProtos.FieldDescriptorProto.newBuilder()
.setLabel(DescriptorProtos.FieldDescriptorProto.Label.LABEL_OPTIONAL)
.setType(DescriptorProtos.FieldDescriptorProto.Type.TYPE_INT32)
.setName("rec_no")
.setNumber(1))
.build();
addRecordType(newRecordType, Key.Expressions.field("rec_no"));
assertNotNull(metaDataStore.getRecordMetaData().getRecordType("MyNewRecord"));
assertEquals(version + 1, metaDataStore.getRecordMetaData().getVersion());
assertEquals(version + 1, metaDataStore.getRecordMetaData().getRecordType("MyNewRecord").getSinceVersion().intValue());
context.commit();
}
}
@Nonnull
private FieldTypeMatch fieldIsType(@Nonnull DescriptorProtos.FileDescriptorProtoOrBuilder file,
@Nonnull String messageName, @Nonnull String fieldName,
@Nonnull String typeName) {
final DescriptorProtos.DescriptorProto record = file.getMessageTypeList().stream()
.filter(message -> message.getName().equals(messageName))
.findAny()
.get();
final DescriptorProtos.FieldDescriptorProto field = record.getFieldList().stream()
.filter(f -> f.getName().equals(fieldName))
.findAny()
.get();
return MetaDataProtoEditor.fieldIsType(file, record, field, typeName);
}
private Descriptors.Descriptor mutateUnionDescriptor(@Nonnull UnaryOperator<DescriptorProtos.DescriptorProto> mutation) throws Descriptors.DescriptorValidationException {
final Descriptors.Descriptor oldUnionDescriptor = metaData.getUnionDescriptor();
final DescriptorProtos.DescriptorProto oldUnionDescriptorProto = oldUnionDescriptor.toProto();
final DescriptorProtos.FileDescriptorProto fileDescriptorProto = metaData.getRecordsDescriptor().toProto();
int unionDescriptorIndex = fileDescriptorProto.getMessageTypeList().indexOf(oldUnionDescriptorProto);
final DescriptorProtos.FileDescriptorProto newFileDescriptorProto = metaData.getRecordsDescriptor().toProto().toBuilder()
.setMessageType(unionDescriptorIndex, mutation.apply(oldUnionDescriptorProto))
.build();
return buildRecordDescriptor(newFileDescriptorProto).findMessageTypeByName(oldUnionDescriptor.getName());
}
private static Optional<String> appendMessage(
DescriptorProtos.DescriptorProto message, List<Integer> path, String fullName) {
fullName += appendNameComponent(message.getName());
return path.size() > 2
? append(message, path.subList(2, path.size()), fullName)
: Optional.of(fullName);
}
private static DescriptorProtos.FileDescriptorProto containsMessageType(
DescriptorProtos.FileDescriptorProto fileDescriptorProto, String messageType
) {
DescriptorProtos.FileDescriptorProto file = null;
for (DescriptorProtos.DescriptorProto descriptorProto :
getAllMessageTypesInDescriptorProto(fileDescriptorProto)) {
if (messageType.equals(descriptorProto.getName())) {
file = fileDescriptorProto;
break;
}
}
return file;
}
private static List<DescriptorProtos.DescriptorProto> getAllMessageTypesInDescriptorProto(
DescriptorProtos.FileDescriptorProto fileDescriptorProto
) {
Queue<DescriptorProtos.DescriptorProto> queue = new LinkedList<>();
queue.addAll(fileDescriptorProto.getMessageTypeList());
List<DescriptorProtos.DescriptorProto> result = new ArrayList<>();
while (!queue.isEmpty()) {
DescriptorProtos.DescriptorProto descriptorProto = queue.poll();
queue.addAll(descriptorProto.getNestedTypeList());
result.add(descriptorProto);
}
return result;
}
static void load_pb_message(PbInfoSet pbs, DescriptorProtos.DescriptorProto mdp, String package_name,
HashMap<String, PbAliasNode<DescriptorProtos.DescriptorProto>> hashmap) {
String full_name = String.format("%s.%s", package_name, mdp.getName());
append_alias_list(mdp.getName(), full_name, pbs.messages, mdp);
for (DescriptorProtos.DescriptorProto sub_mdp : mdp.getNestedTypeList()) {
load_pb_message(pbs, sub_mdp, full_name, hashmap);
}
// oneof
for (DescriptorProtos.OneofDescriptorProto oneof_desc : mdp.getOneofDeclList()) {
append_alias_list(oneof_desc.getName(),
String.format("%s.%s.%s", package_name, mdp.getName(), oneof_desc.getName()), pbs.oneofs,
oneof_desc);
}
}
@Test
public void writeService() throws Exception {
DescriptorProtos.FileDescriptorProto.Builder fileDescriptorProtoBuilder =
DescriptorProtos.FileDescriptorProto.newBuilder()
.setName("test")
.setSyntax("proto3")
.addDependency("google/protobuf/descriptor.proto");
DescriptorProtos.DescriptorProto methodRequest =
DescriptorProtos.DescriptorProto.newBuilder().setName("MethodRequest").build();
DescriptorProtos.DescriptorProto methodResponse =
DescriptorProtos.DescriptorProto.newBuilder().setName("MethodResponse").build();
DescriptorProtos.ServiceDescriptorProto service =
DescriptorProtos.ServiceDescriptorProto.newBuilder()
.setName("Service")
.addMethod(
DescriptorProtos.MethodDescriptorProto.newBuilder()
.setName("FirstMethod")
.setInputType("MethodRequest")
.setOutputType("MethodResponse"))
.addMethod(
DescriptorProtos.MethodDescriptorProto.newBuilder()
.setName("ClientStreamingMethod")
.setInputType("MethodRequest")
.setOutputType("MethodResponse")
.setClientStreaming(true))
.addMethod(
DescriptorProtos.MethodDescriptorProto.newBuilder()
.setName("ServerStreamingMethod")
.setInputType("MethodRequest")
.setOutputType("MethodResponse")
.setServerStreaming(true)
.setOptions(
DescriptorProtos.MethodOptions.newBuilder()
.setExtension(Option.methodOption, TestProto.TEST_MINIMAL)))
.addMethod(
DescriptorProtos.MethodDescriptorProto.newBuilder()
.setName("BiStreamingMethod")
.setInputType("MethodRequest")
.setOutputType("MethodResponse")
.setClientStreaming(true)
.setServerStreaming(true)
.setOptions(TestProto.METHOD_OPTIONS))
.setOptions(TestProto.SERVICE_OPTIONS)
.build();
fileDescriptorProtoBuilder.addService(service);
fileDescriptorProtoBuilder.addMessageType(methodRequest);
fileDescriptorProtoBuilder.addMessageType(methodResponse);
assertService(fileDescriptorProtoBuilder.build(), null);
}
/**
* Rename a record type. This can be used to update any top-level record type defined within the
* meta-data's records descriptor, including {@code NESTED} records or the union descriptor. However,
* it cannot be used to rename nested messages (i.e., messages defined within other messages) or
* records defined in imported files. In addition to updating the file descriptor, if the record type
* is not {@code NESTED} or the union descriptor, update any other references to the record type
* within the meta-data (such as within index definitions).
*
* @param metaDataBuilder the meta-data builder
* @param recordTypeName the name of the existing top-level record type
* @param newRecordTypeName the new name to give to the record type
*/
public static void renameRecordType(@Nonnull RecordMetaDataProto.MetaData.Builder metaDataBuilder,
@Nonnull String recordTypeName, @Nonnull String newRecordTypeName) {
// Create a copy of the records builder (rather than calling metaDataBuilder.getRecordsBuilder()) to avoid
// corrupting the records builder in metaDataBuilder before all validation has been done.
final DescriptorProtos.FileDescriptorProto records = metaDataBuilder.getRecords();
boolean found = false;
for (DescriptorProtos.DescriptorProto messageType : records.getMessageTypeList()) {
if (messageType.getName().equals(recordTypeName)) {
found = true;
} else if (messageType.getName().equals(newRecordTypeName)) {
throw new MetaDataException("Cannot rename record type to " + newRecordTypeName + " as it already exists");
}
}
if (!found) {
throw new MetaDataException("No record type found with name " + recordTypeName);
}
if (recordTypeName.equals(newRecordTypeName)) {
// Identity transformation requires no work.
// From here on in, we can assume that recordTypeName != newRecordTypeName, which simplifies things.
return;
}
final DescriptorProtos.FileDescriptorProto.Builder recordsBuilder = records.toBuilder();
// Determine the usage of the original record type by looking through the union builder.
// If we find a field that matches, also update its name to be in the canonical form (i.e., "_" + recordTypeName)
DescriptorProtos.DescriptorProto.Builder unionBuilder = fetchUnionBuilder(recordsBuilder);
RecordMetaDataOptionsProto.RecordTypeOptions.Usage usage;
if (unionBuilder.getName().equals(recordTypeName)) {
usage = RecordMetaDataOptionsProto.RecordTypeOptions.Usage.UNION;
} else {
DescriptorProtos.FieldDescriptorProto.Builder unionFieldBuilder = fetchUnionFieldBuilder(recordsBuilder, unionBuilder, recordTypeName);
if (unionFieldBuilder == null) {
usage = RecordMetaDataOptionsProto.RecordTypeOptions.Usage.NESTED;
} else {
usage = RecordMetaDataOptionsProto.RecordTypeOptions.Usage.RECORD;
// Change the name to the "canonical" form unless that would cause a field name conflict
if (unionFieldBuilder.getName().equals("_" + recordTypeName)) {
String newFieldName = "_" + newRecordTypeName;
if (unionBuilder.getFieldBuilderList().stream()
.noneMatch(otherUnionField -> otherUnionField != unionFieldBuilder && otherUnionField.getName().equals(newFieldName))) {
unionFieldBuilder.setName(newFieldName);
}
}
}
}
// Do not allow renaming to the default union name unless the record type is already the union
if (newRecordTypeName.equals(RecordMetaDataBuilder.DEFAULT_UNION_NAME) &&
!RecordMetaDataOptionsProto.RecordTypeOptions.Usage.UNION.equals(usage)) {
throw new MetaDataException("Cannot rename record type to the default union name", LogMessageKeys.RECORD_TYPE, recordTypeName);
}
// Rename the record type within the file
renameRecordTypeUsages(recordsBuilder, recordTypeName, newRecordTypeName);
// If the record type is a top level record type, change its usage elsewhere in the meta-data
if (RecordMetaDataOptionsProto.RecordTypeOptions.Usage.RECORD.equals(usage)) {
renameTopLevelRecordType(metaDataBuilder, recordTypeName, newRecordTypeName);
}
// Update the file descriptor
metaDataBuilder.setRecords(recordsBuilder);
}
private void addRecordType(@Nonnull DescriptorProtos.DescriptorProto newRecordType, @Nonnull KeyExpression primaryKey) {
metaDataStore.mutateMetaData(metaDataProto -> MetaDataProtoEditor.addRecordType(metaDataProto, newRecordType, primaryKey));
}
private void addRecordType(@Nonnull DescriptorProtos.DescriptorProto newRecordType, @Nonnull KeyExpression primaryKey, @Nonnull Index index) {
metaDataStore.mutateMetaData(metaDataProto -> MetaDataProtoEditor.addRecordType(metaDataProto, newRecordType, primaryKey),
recordMetaDataBuilder -> recordMetaDataBuilder.addIndex(newRecordType.getName(), index));
}
private void addNestedRecordType(DescriptorProtos.DescriptorProto newRecordType) {
metaDataStore.mutateMetaData((metaDataProto) -> MetaDataProtoEditor.addNestedRecordType(metaDataProto, newRecordType));
}