0

I want to create .proto file through java code. I am able to do it with message having primitive type attributes as follow :

public void testDynamicProto() throws Exception {
    byte[] bytes = buildPersonProtoDesc();
    byte[] personBytes = buildPersonProto(bytes);

    Descriptors.FileDescriptor fileDescriptor = Descriptors.FileDescriptor
            .buildFrom(
                    DescriptorProtos.FileDescriptorProto.parseFrom(bytes),
                    new Descriptors.FileDescriptor[0]);

    Descriptors.Descriptor personDesc = fileDescriptor
            .findMessageTypeByName(PERSON_MESSAGE);
    DynamicMessage message = DynamicMessage.parseFrom(personDesc,
            personBytes);
    for (Map.Entry<Descriptors.FieldDescriptor, Object> entry : message
            .getAllFields().entrySet()) {
        // TODO: add asserts
        System.out.println(entry.getKey().getName() + "------------"
                + entry.getValue());
    }

    // TODO: test repeated field
    // TODO: test non destructive updates (addition of column) to person proto and make sure old protos can be parsed
}


private byte[] buildPersonProto(byte[] bytes)
        throws Descriptors.DescriptorValidationException,
        InvalidProtocolBufferException {
    Descriptors.FileDescriptor fileDescriptor = Descriptors.FileDescriptor
            .buildFrom(
                    DescriptorProtos.FileDescriptorProto.parseFrom(bytes),
                    new Descriptors.FileDescriptor[0]);

    Descriptors.Descriptor personDesc = fileDescriptor
            .findMessageTypeByName(PERSON_MESSAGE);

    DynamicMessage.Builder personBuilder = DynamicMessage
            .newBuilder(personDesc);
    personBuilder.setField(personDesc.findFieldByName(FNAME_FIELD), "Jon");
    personBuilder.setField(personDesc.findFieldByName(LNAME_FIELD), "Doe");
    personBuilder.setField(personDesc.findFieldByName(STATUS_FIELD), 2);


    return personBuilder.build().toByteArray();
}

private byte[] buildPersonProtoDesc() {
    DescriptorProtos.FileDescriptorProto.Builder fileDescriptorProtoBuilder = DescriptorProtos.FileDescriptorProto
            .newBuilder();
    DescriptorProtos.DescriptorProto.Builder messageProtoBuilderA = DescriptorProtos.DescriptorProto
            .newBuilder();
    messageProtoBuilderA.setName(PERSON_MESSAGE);
    messageProtoBuilderA
            .addFieldBuilder()
            .setName(FNAME_FIELD)
            .setNumber(1)
            .setType(DescriptorProtos.FieldDescriptorProto.Type.TYPE_STRING);
    messageProtoBuilderA
            .addFieldBuilder()
            .setName(LNAME_FIELD)
            .setNumber(2)
            .setType(DescriptorProtos.FieldDescriptorProto.Type.TYPE_STRING);
    messageProtoBuilderA.addFieldBuilder().setName(STATUS_FIELD)
            .setNumber(3)
            .setType(DescriptorProtos.FieldDescriptorProto.Type.TYPE_INT32);



    fileDescriptorProtoBuilder.addMessageType(messageProtoBuilderA);
    DescriptorProtos.FileDescriptorProto fileDescriptorProto = fileDescriptorProtoBuilder
            .build();
    return fileDescriptorProto.toByteArray();
}

Now my proto structure is

message Person{

optional string FName=1;
optional string LName=2;
optional string Status=3;}

And I can achieve this by using above methods.

I want to achieve:

message Person{

optional string FName=1;
optional string LName=2;
optional string Status=3;

message Address {

    optional string country=1;
    optional string state=2;
    optional string city=3;}

repeated Address address=4;}

Queries:

  1. How to add Address under Person(can try method addRepeatedField but couldn't create FileDescriptor)
  2. How to add Address as repeated field(ArrayList) under Person

Please give me any hint if anybody has.

2 Answers 2

0

To add a type under Person call addNestedType() on messageProtoBuilderA (the DescriptorProto.Builder for Person). The input for addNestedType() is a DescriptorProto for Address, which is built in the same way as the one for Person.

When adding the address field to the Person type, call setLabel(Label.LABEL_REPEATED) on the corresponding FieldDescriptorProto.Builder.

DescriptorProto.Builder messageProtoBuilderA = ...;
messageProtoBuilderA.addNestedType(createAddressType());

FieldDescriptorProto.Builder addressField = FieldDescriptorProto.newBuilder();
addressField.setName("address")
            .setLabel(Label.LABEL_REPEATED)
            .setNumber(4)
            .setType(Type.TYPE_MESSAGE)
            .setTypeName("Address");
messageProtoBuilderA.addField(addressField);
...

private DescriptorProto.Builder createAddressType() {
    DescriptorProto.Builder addressProtoBuilder = DescriptorProto.newBuilder();
    addressProtoBuilder.setName("Address");
    // add fields
    return addressProtoBuilder;
}
Sign up to request clarification or add additional context in comments.

Comments

0

I believe for protos all the fields have to be together. So it should be

optional string FName=1;
optional string LName=2;
optional string Status=3;
repeated Address address=4;

and you can put this under your definition of Address so that code is already generated.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.