├── protokit-generator ├── README.md ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── alibaba │ │ │ │ └── protokit │ │ │ │ ├── gen │ │ │ │ ├── package-info.java │ │ │ │ ├── PbConvertor.java │ │ │ │ ├── IntegerPbConvertor.java │ │ │ │ ├── PbConvertorUtils.java │ │ │ │ └── template │ │ │ │ │ ├── ProtoDumper.java │ │ │ │ │ └── JavaDumper.java │ │ │ │ ├── common │ │ │ │ └── Constants.java │ │ │ │ ├── annotation │ │ │ │ ├── PbMessage.java │ │ │ │ ├── PbField.java │ │ │ │ ├── JavaType.java │ │ │ │ ├── Type.java │ │ │ │ └── PbAnnotationParser.java │ │ │ │ ├── utils │ │ │ │ ├── TypeUtils.java │ │ │ │ └── NameUtils.java │ │ │ │ └── model │ │ │ │ └── MetaData.java │ │ ├── resources │ │ │ ├── pb-templates │ │ │ │ ├── message.proto │ │ │ │ └── descriptor.proto │ │ │ ├── proto3.stg │ │ │ └── convertor.stg │ │ └── proto │ │ │ ├── StudentPB.proto │ │ │ ├── SchoolPB.proto │ │ │ └── google │ │ │ └── protobuf │ │ │ ├── any.proto │ │ │ └── descriptor.proto │ └── test │ │ └── java │ │ ├── com │ │ ├── aaa │ │ │ ├── City.java │ │ │ ├── SchoolPbConvertorTest.java │ │ │ ├── SchoolPbConvertor.java │ │ │ └── School.java │ │ ├── alibaba │ │ │ └── protokit │ │ │ │ ├── utils │ │ │ │ ├── TypeUtilsTest.java │ │ │ │ └── NameUtilsTest.java │ │ │ │ └── gen │ │ │ │ └── template │ │ │ │ ├── JavaDumperTest.java │ │ │ │ └── ProtoDumperTest.java │ │ └── abc │ │ │ ├── StudentPbConvertorTest.java │ │ │ ├── StudentPbConvertor.java │ │ │ └── Student.java │ │ └── aaa │ │ ├── StudentPbConvertor.java │ │ └── SchoolPbConvertor.java └── pom.xml ├── protokit-maven-plugin ├── README.md ├── src │ └── main │ │ ├── resources │ │ └── META-INF │ │ │ └── m2e │ │ │ └── lifecycle-mapping-metadata.xml │ │ └── java │ │ └── com │ │ └── alibaba │ │ └── protokit │ │ └── plugin │ │ └── ProtoKitCompileMojo.java └── pom.xml ├── protokit-demo2 ├── src │ └── main │ │ ├── proto │ │ └── com │ │ │ └── alibaba │ │ │ └── protokit │ │ │ └── gen │ │ │ └── UserPB.proto │ │ └── java │ │ └── com │ │ └── demo2 │ │ └── Test.java └── pom.xml ├── .gitignore ├── protokit-demo ├── src │ └── main │ │ └── java │ │ └── com │ │ └── test │ │ └── demo │ │ ├── CartService.java │ │ ├── User.java │ │ └── Company.java └── pom.xml ├── .github └── workflows │ └── test.yaml ├── README.md ├── LICENSE └── pom.xml /protokit-generator/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## protokit generator 4 | 5 | 从JAVA类中生成 .proto文件。 6 | 7 | -------------------------------------------------------------------------------- /protokit-maven-plugin/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## protokit generator 4 | 5 | 从JAVA类中生成 .proto文件。 6 | 7 | -------------------------------------------------------------------------------- /protokit-generator/src/main/java/com/alibaba/protokit/gen/package-info.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.protokit.gen; -------------------------------------------------------------------------------- /protokit-generator/src/main/resources/pb-templates/message.proto: -------------------------------------------------------------------------------- 1 | message {{messageName}} { 2 | {{fields}} 3 | } -------------------------------------------------------------------------------- /protokit-demo2/src/main/proto/com/alibaba/protokit/gen/UserPB.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package com.alibaba.protokit.gen; 3 | option java_multiple_files = true; 4 | option java_package = 'com.alibaba.protokit.gen'; 5 | message UserPB { 6 | string name = 1; 7 | int32 age = 2; 8 | } 9 | 10 | -------------------------------------------------------------------------------- /protokit-generator/src/main/proto/StudentPB.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "com.abc"; 4 | option java_multiple_files = true; 5 | 6 | package com.abc; 7 | 8 | message StudentPB { 9 | fixed64 id = 1; 10 | string name = 2; 11 | int32 age = 3; 12 | bool checked = 4; 13 | } 14 | -------------------------------------------------------------------------------- /protokit-generator/src/main/java/com/alibaba/protokit/gen/PbConvertor.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.protokit.gen; 2 | 3 | import com.google.protobuf.Message; 4 | 5 | // TODO 能支持 这样子的泛型不? 6 | public interface PbConvertor { 7 | T2 convertToPbObject(T object); 8 | T fromPbObject(Object pbObject); 9 | } 10 | -------------------------------------------------------------------------------- /protokit-generator/src/main/resources/pb-templates/descriptor.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "{{javaPackage}}"; 4 | option java_multiple_files = true; 5 | 6 | package {{package}}; 7 | 8 | {{#imports}} 9 | import "{{.}}"; 10 | {{/imports}} 11 | 12 | {{#messages}} 13 | {{> message}} 14 | {{/messages}} 15 | 16 | -------------------------------------------------------------------------------- /protokit-generator/src/main/java/com/alibaba/protokit/common/Constants.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.protokit.common; 2 | 3 | /** 4 | * 5 | * @author hengyunabc 2021-01-22 6 | * 7 | */ 8 | public class Constants { 9 | 10 | public static final String PB_MESSAGE_SUFFIX = "PB"; 11 | 12 | public static final String PB_FILE_EXT = ".proto"; 13 | 14 | public static final String CONVERTOR_SUFFIX = "PbConvertor"; 15 | 16 | public static final String JAVA_FILE_EXT = ".java"; 17 | } 18 | -------------------------------------------------------------------------------- /protokit-generator/src/main/java/com/alibaba/protokit/gen/IntegerPbConvertor.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.protokit.gen; 2 | 3 | /** 4 | * 5 | * @author hengyunabc 2021-03-15 6 | * 7 | */ 8 | public class IntegerPbConvertor implements PbConvertor { 9 | 10 | @Override 11 | public T2 convertToPbObject(Integer object) { 12 | return (T2) object; 13 | } 14 | 15 | @Override 16 | public Integer fromPbObject(Object pbObject) { 17 | return (Integer) pbObject; 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /protokit-generator/src/main/proto/SchoolPB.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "com.aaa"; 4 | option java_multiple_files = true; 5 | 6 | import "StudentPB.proto"; 7 | 8 | package com.aaa; 9 | 10 | 11 | message SchoolPB { 12 | string name = 1; 13 | repeated com.abc.StudentPB students = 2; 14 | 15 | map nameToStudents = 3; 16 | map idToStudents = 4; 17 | repeated int32 ids = 5; 18 | } 19 | 20 | message CityPB { 21 | string name = 1; 22 | repeated SchoolPB students = 2; 23 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *# 2 | *.iml 3 | *.ipr 4 | *.iws 5 | *.jar 6 | *.sw? 7 | *~ 8 | .#* 9 | .*.md.html 10 | .DS_Store 11 | .classpath 12 | .factorypath 13 | .gradle 14 | .idea 15 | .metadata 16 | .project 17 | .recommenders 18 | .settings 19 | .springBeans 20 | /build 21 | /code 22 | MANIFEST.MF 23 | _site/ 24 | activemq-data 25 | bin 26 | build 27 | build.log 28 | dependency-reduced-pom.xml 29 | dump.rdb 30 | interpolated*.xml 31 | lib/ 32 | manifest.yml 33 | overridedb.* 34 | settings.xml 35 | target 36 | transaction-logs 37 | .flattened-pom.xml 38 | secrets.yml 39 | .gradletasknamecache 40 | .sts4-cache 41 | -------------------------------------------------------------------------------- /protokit-generator/src/main/java/com/alibaba/protokit/annotation/PbMessage.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.protokit.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Inherited; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | /** 11 | * 12 | * @author hengyunabc 2021-01-18 13 | * 14 | */ 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Target({ ElementType.TYPE }) 17 | @Inherited 18 | @Documented 19 | public @interface PbMessage { 20 | 21 | String comment() default ""; 22 | } -------------------------------------------------------------------------------- /protokit-maven-plugin/src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | compile 9 | 10 | 11 | 12 | 13 | true 14 | true 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /protokit-generator/src/test/java/com/aaa/City.java: -------------------------------------------------------------------------------- 1 | package com.aaa; 2 | 3 | import java.util.List; 4 | 5 | import com.alibaba.protokit.annotation.PbField; 6 | import com.alibaba.protokit.annotation.PbMessage; 7 | 8 | @PbMessage 9 | public class City { 10 | @PbField(tag = 1) 11 | private String name; 12 | @PbField(tag = 2) 13 | private List schools; 14 | 15 | public String getName() { 16 | return name; 17 | } 18 | 19 | public void setName(String name) { 20 | this.name = name; 21 | } 22 | 23 | public List getSchools() { 24 | return schools; 25 | } 26 | 27 | public void setSchools(List schools) { 28 | this.schools = schools; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /protokit-generator/src/test/java/com/alibaba/protokit/utils/TypeUtilsTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.protokit.utils; 2 | 3 | import org.assertj.core.api.Assertions; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import com.alibaba.protokit.annotation.Type; 7 | 8 | import io.protostuff.compiler.model.Field; 9 | import io.protostuff.compiler.model.ScalarFieldType; 10 | 11 | /** 12 | * 13 | * @author hengyunabc 2021-02-04 14 | * 15 | */ 16 | public class TypeUtilsTest { 17 | 18 | @Test 19 | public void test() { 20 | Assertions.assertThat(TypeUtils.toFieldType(Type.BOOL)).isEqualTo(ScalarFieldType.BOOL); 21 | Assertions.assertThat(TypeUtils.toFieldType(Type.FIXED32)).isEqualTo(ScalarFieldType.FIXED32); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /protokit-generator/src/main/java/com/alibaba/protokit/annotation/PbField.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.protokit.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Inherited; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | /** 11 | * TODO 直接叫 `@Tag` 是否就可以了? 12 | * 13 | * TODO 增加 from/to ,用户可以显式指定转换的函数? 14 | * 15 | * @author hengyunabc 2021-01-18 16 | * 17 | */ 18 | @Retention(RetentionPolicy.RUNTIME) 19 | @Target(ElementType.FIELD) 20 | @Inherited 21 | @Documented 22 | public @interface PbField { 23 | 24 | int tag(); 25 | 26 | Type type() default Type.UNKNOWN; 27 | 28 | String comment() default ""; 29 | } -------------------------------------------------------------------------------- /protokit-generator/src/main/java/com/alibaba/protokit/annotation/JavaType.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.protokit.annotation; 2 | 3 | import com.google.protobuf.ByteString; 4 | 5 | /** 6 | * @see com.google.protobuf.Descriptors.FieldDescriptor.JavaType 7 | * @author hengyunabc 2021-01-18 8 | * 9 | */ 10 | public enum JavaType { 11 | INT(0), LONG(0L), FLOAT(0F), DOUBLE(0D), BOOLEAN(false), STRING(""), BYTE_STRING(ByteString.EMPTY), ENUM(null), 12 | MESSAGE(null), UNKNOWN(null); 13 | 14 | JavaType(final Object defaultDefault) { 15 | this.defaultDefault = defaultDefault; 16 | } 17 | 18 | /** 19 | * The default default value for fields of this type, if it's a primitive type. 20 | * This is meant for use inside this file only, hence is private. 21 | */ 22 | private final Object defaultDefault; 23 | } -------------------------------------------------------------------------------- /protokit-demo/src/main/java/com/test/demo/CartService.java: -------------------------------------------------------------------------------- 1 | package com.test.demo; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | 6 | public interface CartService { 7 | User echoUser(User user); 8 | 9 | List echoUserList(List userList); 10 | 11 | Map echoMap(Map userMap); 12 | 13 | Map> echoMapList(Map> userMap); 14 | 15 | List> echoListMap(List> userMap); 16 | 17 | Map> echoMapMap(Map> user); 18 | 19 | Map>> echoMapMapMap(Map>> userDTO); 20 | 21 | boolean multiParam(User user, String productID, int quantity); 22 | // TODO InnerClass 23 | // // TODO 异常 24 | // String getProviderIp(String name, int age); 25 | 26 | } -------------------------------------------------------------------------------- /protokit-generator/src/test/java/com/abc/StudentPbConvertorTest.java: -------------------------------------------------------------------------------- 1 | package com.abc; 2 | 3 | import org.assertj.core.api.Assertions; 4 | import org.junit.jupiter.api.Test; 5 | 6 | /** 7 | * 8 | * @author hengyunabc 2021-03-10 9 | * 10 | */ 11 | public class StudentPbConvertorTest { 12 | 13 | @Test 14 | public void test() { 15 | StudentPbConvertor convertor = new StudentPbConvertor(); 16 | 17 | Student student = new Student(); 18 | student.setAge(10); 19 | student.setId(123); 20 | student.setName("hello"); 21 | 22 | StudentPB pbObject = convertor.convertToPbObject(student); 23 | 24 | Student student2 = convertor.fromPbObject(pbObject); 25 | 26 | Assertions.assertThat(student.getAge()).isEqualTo(student2.getAge()); 27 | 28 | Assertions.assertThat(student.getId()).isEqualTo(student2.getId()); 29 | Assertions.assertThat(student.getName()).isEqualTo(student2.getName()); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /protokit-generator/src/test/java/com/alibaba/protokit/utils/NameUtilsTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.protokit.utils; 2 | 3 | import org.assertj.core.api.Assertions; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import io.protostuff.compiler.model.Field; 7 | 8 | /** 9 | * 10 | * @author hengyunabc 2021-02-04 11 | * 12 | */ 13 | public class NameUtilsTest { 14 | 15 | @Test 16 | public void testGetterSetter() { 17 | Field field = new Field(null); 18 | field.setName("abc"); 19 | Assertions.assertThat(NameUtils.getterMethod(field, true)).isEqualTo("getAbc"); 20 | Assertions.assertThat(NameUtils.setterMethod(field)).isEqualTo("setAbc"); 21 | 22 | Field boolField = new Field(null); 23 | boolField.setName("bbb"); 24 | boolField.setTypeName("bool"); 25 | Assertions.assertThat(NameUtils.getterMethod(boolField, true)).isEqualTo("isBbb"); 26 | Assertions.assertThat(NameUtils.setterMethod(boolField)).isEqualTo("setBbb"); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /protokit-generator/src/test/java/com/alibaba/protokit/gen/template/JavaDumperTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.protokit.gen.template; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | 6 | import org.junit.jupiter.api.Test; 7 | 8 | import com.aaa.School; 9 | import com.abc.Student; 10 | 11 | /** 12 | * 13 | * @author hengyunabc 2021-03-09 14 | * 15 | */ 16 | public class JavaDumperTest { 17 | @Test 18 | public void test() throws IOException { 19 | 20 | String file = this.getClass().getProtectionDomain().getCodeSource().getLocation().getFile(); 21 | String outputPath = new File(file, "../test-output").getAbsolutePath(); 22 | 23 | JavaDumper.dumpCode(Student.class, outputPath); 24 | JavaDumper.dumpCode(School.class, outputPath); 25 | 26 | String studentCodeString = JavaDumper.dumpCode(Student.class); 27 | 28 | System.err.println(studentCodeString); 29 | 30 | String schoolCodeString = JavaDumper.dumpCode(School.class); 31 | 32 | System.err.println(schoolCodeString); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /protokit-demo/src/main/java/com/test/demo/User.java: -------------------------------------------------------------------------------- 1 | package com.test.demo; 2 | 3 | import com.alibaba.protokit.annotation.PbField; 4 | import com.alibaba.protokit.annotation.PbMessage; 5 | 6 | @PbMessage 7 | public class User { 8 | @PbField(tag = 1) 9 | private long id; 10 | 11 | @PbField(tag = 2) 12 | private String name; 13 | @PbField(tag = 3) 14 | private int age; 15 | 16 | @PbField(tag = 4) 17 | private boolean checked; 18 | 19 | public long getId() { 20 | return id; 21 | } 22 | 23 | public void setId(long id) { 24 | this.id = id; 25 | } 26 | 27 | public String getName() { 28 | return name; 29 | } 30 | 31 | public void setName(String name) { 32 | this.name = name; 33 | } 34 | 35 | public int getAge() { 36 | return age; 37 | } 38 | 39 | public void setAge(int age) { 40 | this.age = age; 41 | } 42 | 43 | public boolean isChecked() { 44 | return checked; 45 | } 46 | 47 | public void setChecked(boolean checked) { 48 | this.checked = checked; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /protokit-generator/src/test/java/com/abc/StudentPbConvertor.java: -------------------------------------------------------------------------------- 1 | package com.abc; 2 | 3 | import com.abc.StudentPB; 4 | import com.abc.StudentPB.Builder; 5 | import com.alibaba.protokit.gen.PbConvertor; 6 | 7 | public class StudentPbConvertor implements PbConvertor { 8 | 9 | @Override 10 | public T convertToPbObject(Student object) { 11 | Builder builder = StudentPB.newBuilder(); 12 | builder.setAge(object.getAge()); 13 | builder.setName(object.getName()); 14 | builder.setId(object.getId()); 15 | builder.setChecked(object.isChecked()); 16 | StudentPB pbObject = builder.build(); 17 | return (T) pbObject; 18 | } 19 | 20 | @Override 21 | public Student fromPbObject(Object pbObject) { 22 | StudentPB object = (StudentPB) pbObject; 23 | Student returnObject = new Student(); 24 | returnObject.setId(object.getId()); 25 | returnObject.setAge(object.getAge()); 26 | returnObject.setName(object.getName()); 27 | returnObject.setChecked(object.getChecked()); 28 | return returnObject; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /protokit-generator/src/test/java/aaa/StudentPbConvertor.java: -------------------------------------------------------------------------------- 1 | package aaa; 2 | import com.abc.StudentPB; 3 | import com.abc.StudentPB.Builder; 4 | import com.alibaba.protokit.gen.PbConvertor; 5 | public class StudentPbConvertor implements com.alibaba.protokit.gen.PbConvertor{ 6 | 7 | @Override 8 | public T convertToPbObject(com.abc.Student object) { 9 | com.abc.StudentPB.Builder builder = com.abc.StudentPB.newBuilder(); 10 | builder.setId(object.getId()); 11 | builder.setName(object.getName()); 12 | builder.setAge(object.getAge()); 13 | builder.setChecked(object.isChecked()); 14 | return (T) builder.build(); 15 | } 16 | @Override 17 | public com.abc.Student fromPbObject(Object pbObject) { 18 | com.abc.Student object = new com.abc.Student(); 19 | com.abc.StudentPB fromPbObject = (com.abc.StudentPB) pbObject; 20 | object.setId(fromPbObject.getId()); 21 | object.setName(fromPbObject.getName()); 22 | object.setAge(fromPbObject.getAge()); 23 | object.setChecked(fromPbObject.getChecked()); 24 | return object; 25 | } 26 | } -------------------------------------------------------------------------------- /protokit-demo2/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.alibaba 8 | protokit-parent 9 | ${revision} 10 | ../pom.xml 11 | 12 | protokit-demo2 13 | protokit-demo2 14 | 15 | 16 | 17 | 18 | com.alibaba 19 | protokit-generator 20 | ${project.version} 21 | 22 | 23 | 24 | com.alibaba 25 | protokit-demo 26 | ${revision} 27 | provided 28 | true 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /protokit-generator/src/main/java/com/alibaba/protokit/utils/TypeUtils.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.protokit.utils; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import com.alibaba.protokit.annotation.Type; 7 | 8 | import io.protostuff.compiler.model.FieldType; 9 | import io.protostuff.compiler.model.ScalarFieldType; 10 | 11 | /** 12 | * 13 | * @author hengyunabc 2021-02-04 14 | * 15 | */ 16 | public class TypeUtils { 17 | 18 | private static Map typeToFieldTypeMap = new HashMap<>(); 19 | private static Map fieldToTypeMap = new HashMap<>(); 20 | 21 | static { 22 | typeToFieldTypeMap.put(Type.BOOL, ScalarFieldType.BOOL); 23 | 24 | for (ScalarFieldType scalarFieldType : ScalarFieldType.values()) { 25 | for (Type type : Type.values()) { 26 | if (scalarFieldType.name().equals(type.name())) { 27 | typeToFieldTypeMap.put(type, scalarFieldType); 28 | fieldToTypeMap.put(scalarFieldType, type); 29 | } 30 | } 31 | } 32 | 33 | } 34 | 35 | public static FieldType toFieldType(Type type) { 36 | // TODO 没对上的类型怎么处理? 37 | return typeToFieldTypeMap.get(type); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | name: JavaCI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | java: [8, 9, 10, 11 ] 11 | steps: 12 | - uses: actions/checkout@v2 13 | - name: Setup java 14 | uses: actions/setup-java@v1 15 | with: 16 | java-version: ${{ matrix.java }} 17 | - name: Build with Maven 18 | run: mvn clean package 19 | 20 | build_jdk_ge_12: 21 | runs-on: ubuntu-latest 22 | strategy: 23 | matrix: 24 | java: [12, 13, 14 ] 25 | steps: 26 | - uses: actions/checkout@v2 27 | - name: Set up JDK 1.8 28 | uses: actions/setup-java@v1 29 | with: 30 | java-version: 8 31 | - name: save java8 home 32 | run: | 33 | export JAVA8_HOME=$JAVA_HOME && echo $JAVA8_HOME 34 | echo "export JAVA8_HOME=$JAVA_HOME" > ~/.testenv 35 | 36 | - name: Setup java 37 | uses: actions/setup-java@v1 38 | with: 39 | java-version: ${{ matrix.java }} 40 | - name: Build with Maven 41 | run: | 42 | source ~/.testenv 43 | mvn -Dmaven.compiler.fork=true -Dmaven.compiler.executable=$JAVA8_HOME/bin/javac -DJAVA8_HOME=$JAVA8_HOME clean package -------------------------------------------------------------------------------- /protokit-generator/src/main/java/com/alibaba/protokit/annotation/Type.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.protokit.annotation; 2 | 3 | import com.google.protobuf.DescriptorProtos.FieldDescriptorProto; 4 | 5 | /** 6 | * 7 | * 8 | * @see com.google.protobuf.Descriptors.FieldDescriptor.Type 9 | * 10 | * @author hengyunabc 2021-01-18 11 | * 12 | */ 13 | public enum Type { 14 | DOUBLE(JavaType.DOUBLE), FLOAT(JavaType.FLOAT), INT64(JavaType.LONG), UINT64(JavaType.LONG), INT32(JavaType.INT), 15 | FIXED64(JavaType.LONG), FIXED32(JavaType.INT), BOOL(JavaType.BOOLEAN), STRING(JavaType.STRING), 16 | GROUP(JavaType.MESSAGE), MESSAGE(JavaType.MESSAGE), BYTES(JavaType.BYTE_STRING), UINT32(JavaType.INT), 17 | ENUM(JavaType.ENUM), SFIXED32(JavaType.INT), SFIXED64(JavaType.LONG), SINT32(JavaType.INT), SINT64(JavaType.LONG), 18 | UNKNOWN(JavaType.UNKNOWN); 19 | 20 | Type(final JavaType javaType) { 21 | this.javaType = javaType; 22 | } 23 | 24 | private JavaType javaType; 25 | 26 | public FieldDescriptorProto.Type toProto() { 27 | return FieldDescriptorProto.Type.forNumber(ordinal() + 1); 28 | } 29 | 30 | public JavaType getJavaType() { 31 | return javaType; 32 | } 33 | 34 | public static Type valueOf(final FieldDescriptorProto.Type type) { 35 | return values()[type.getNumber() - 1]; 36 | } 37 | } -------------------------------------------------------------------------------- /protokit-demo2/src/main/java/com/demo2/Test.java: -------------------------------------------------------------------------------- 1 | package com.demo2; 2 | 3 | import java.util.Arrays; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | import com.test.demo.Company; 8 | import com.test.demo.CompanyPB; 9 | import com.test.demo.CompanyPbConvertor; 10 | import com.test.demo.User; 11 | import com.test.demo.UserPB; 12 | import com.test.demo.UserPbConvertor; 13 | 14 | public class Test { 15 | 16 | public static void main(String[] args) { 17 | UserPbConvertor userConvertor = new UserPbConvertor(); 18 | 19 | User user = new User(); 20 | user.setId(999); 21 | user.setName("nnn"); 22 | UserPB userPB = userConvertor.convertToPbObject(user); 23 | 24 | System.err.println(userPB); 25 | 26 | CompanyPbConvertor companyConvertor = new CompanyPbConvertor(); 27 | Company company = new Company(); 28 | 29 | company.setIds(Arrays.asList(1, 2, 3)); 30 | Map idToUsers = new HashMap<>(); 31 | idToUsers.put(user.getId(), user); 32 | company.setIdToUsers(idToUsers); 33 | 34 | company.setUsers(Arrays.asList(user)); 35 | company.setName("ccc"); 36 | CompanyPB companyPb = companyConvertor.convertToPbObject(company); 37 | 38 | System.err.println(company); 39 | System.err.println(companyPb); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /protokit-generator/src/main/java/com/alibaba/protokit/model/MetaData.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.protokit.model; 2 | 3 | import java.util.List; 4 | 5 | import io.protostuff.compiler.model.Proto; 6 | 7 | /** 8 | * 9 | * @author hengyunabc 2021-03-10 10 | * 11 | */ 12 | public class MetaData { 13 | 14 | private String className; 15 | private String pbClassName; 16 | private String packageName; 17 | private List imports; 18 | private Proto proto; 19 | 20 | // 要 import 其它的类? 在生成的 java代码里 21 | // 要有一些 field 的信息? 22 | // 可能还有一些转换类的信息! 23 | public String getClassName() { 24 | return className; 25 | } 26 | 27 | public void setClassName(String className) { 28 | this.className = className; 29 | } 30 | 31 | public List getImports() { 32 | return imports; 33 | } 34 | 35 | public void setImports(List imports) { 36 | this.imports = imports; 37 | } 38 | 39 | public Proto getProto() { 40 | return proto; 41 | } 42 | 43 | public void setProto(Proto proto) { 44 | this.proto = proto; 45 | } 46 | 47 | public String getPackageName() { 48 | return packageName; 49 | } 50 | 51 | public void setPackageName(String packageName) { 52 | this.packageName = packageName; 53 | } 54 | 55 | public String getPbClassName() { 56 | return pbClassName; 57 | } 58 | 59 | public void setPbClassName(String pbClassName) { 60 | this.pbClassName = pbClassName; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /protokit-demo/src/main/java/com/test/demo/Company.java: -------------------------------------------------------------------------------- 1 | package com.test.demo; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | 6 | import com.alibaba.protokit.annotation.PbField; 7 | import com.alibaba.protokit.annotation.PbMessage; 8 | 9 | @PbMessage 10 | public class Company { 11 | 12 | @PbField(tag = 1) 13 | private String name; 14 | @PbField(tag = 2) 15 | private List users; 16 | 17 | @PbField(tag = 3) 18 | private Map nameToUsers; 19 | 20 | @PbField(tag = 4) 21 | private Map idToUsers; 22 | 23 | @PbField(tag = 5) 24 | private List ids; 25 | 26 | public String getName() { 27 | return name; 28 | } 29 | 30 | public void setName(String name) { 31 | this.name = name; 32 | } 33 | 34 | public List getUsers() { 35 | return users; 36 | } 37 | 38 | public void setUsers(List users) { 39 | this.users = users; 40 | } 41 | 42 | public Map getNameToUsers() { 43 | return nameToUsers; 44 | } 45 | 46 | public void setNameToUsers(Map nameToUsers) { 47 | this.nameToUsers = nameToUsers; 48 | } 49 | 50 | public Map getIdToUsers() { 51 | return idToUsers; 52 | } 53 | 54 | public void setIdToUsers(Map idToUsers) { 55 | this.idToUsers = idToUsers; 56 | } 57 | 58 | public List getIds() { 59 | return ids; 60 | } 61 | 62 | public void setIds(List ids) { 63 | this.ids = ids; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /protokit-generator/src/test/java/com/aaa/SchoolPbConvertorTest.java: -------------------------------------------------------------------------------- 1 | package com.aaa; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import org.assertj.core.api.Assertions; 9 | import org.junit.jupiter.api.Test; 10 | 11 | import com.abc.Student; 12 | 13 | /** 14 | * 15 | * @author hengyunabc 2021-03-10 16 | * 17 | */ 18 | public class SchoolPbConvertorTest { 19 | 20 | @Test 21 | public void test() { 22 | SchoolPbConvertor convertor = new SchoolPbConvertor(); 23 | 24 | School school = new School(); 25 | 26 | school.setName("sss"); 27 | 28 | Student student1 = new Student(); 29 | student1.setAge(11); 30 | student1.setId(1234); 31 | student1.setName("nnnn"); 32 | student1.setChecked(true); 33 | 34 | List students = new ArrayList<>(); 35 | students.add(student1); 36 | 37 | school.setStudents(students); 38 | 39 | Map idToStudents = new HashMap<>(); 40 | idToStudents.put(student1.getId(), student1); 41 | school.setIdToStudents(idToStudents); 42 | 43 | Map nameToStudents = new HashMap<>(); 44 | nameToStudents.put(student1.getName(), student1); 45 | school.setNameToStudents(nameToStudents); 46 | 47 | List ids = new ArrayList(); 48 | ids.add(1234); 49 | school.setIds(ids); 50 | 51 | SchoolPB pbObject = convertor.convertToPbObject(school); 52 | 53 | School school2 = convertor.fromPbObject(pbObject); 54 | 55 | Student student2 = school2.getStudents().get(0); 56 | 57 | Assertions.assertThat(school.getName()).isEqualTo(school2.getName()); 58 | 59 | Assertions.assertThat(student2).isEqualTo(student1); 60 | 61 | Assertions.assertThat(school).isEqualTo(school2); 62 | 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # protokit 2 | A kit for protobuf. 3 | 4 | 5 | ## 示例 6 | ### protokit-demo 7 | 8 | 在 `protokit-demo` 里可以看到具体示例。 9 | 10 | 用户定义: 11 | 12 | ```java 13 | @PbMessage 14 | public class User { 15 | @PbField(tag = 1) 16 | private long id; 17 | 18 | @PbField(tag = 2) 19 | private String name; 20 | @PbField(tag = 3) 21 | private int age; 22 | 23 | @PbField(tag = 4) 24 | private boolean checked; 25 | ``` 26 | 27 | 在编译之后,会生成 `UserPB.proto`: 28 | 29 | ```js 30 | syntax = "proto3"; 31 | package com.test.demo; 32 | option java_multiple_files = true; 33 | option java_package = 'com.test.demo'; 34 | message UserPB { 35 | int64 id = 1; 36 | string name = 2; 37 | int32 age = 3; 38 | bool checked = 4; 39 | } 40 | ``` 41 | 42 | 还会生成 `UserPbConvertor.java` 43 | 44 | ```java 45 | public class UserPbConvertor implements com.alibaba.protokit.gen.PbConvertor{ 46 | 47 | @Override 48 | public T convertToPbObject(com.test.demo.User object) { 49 | com.test.demo.UserPB.Builder builder = com.test.demo.UserPB.newBuilder(); 50 | builder.setId(object.getId()); 51 | builder.setName(object.getName()); 52 | builder.setAge(object.getAge()); 53 | builder.setChecked(object.isChecked()); 54 | return (T) builder.build(); 55 | } 56 | @Override 57 | public com.test.demo.User fromPbObject(Object pbObject) { 58 | com.test.demo.User object = new com.test.demo.User(); 59 | com.test.demo.UserPB fromPbObject = (com.test.demo.UserPB) pbObject; 60 | object.setId(fromPbObject.getId()); 61 | object.setName(fromPbObject.getName()); 62 | object.setAge(fromPbObject.getAge()); 63 | object.setChecked(fromPbObject.getChecked()); 64 | return object; 65 | } 66 | } 67 | ``` 68 | 69 | ### protokit-demo2 70 | 71 | 在 `protokit-demo2` 里引用 `protokit-demo` 中生成的 `UserPbConvertor`,完成 `User` 到 `UserPB`的相互转换。 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /protokit-generator/src/test/java/com/abc/Student.java: -------------------------------------------------------------------------------- 1 | package com.abc; 2 | 3 | import com.alibaba.protokit.annotation.PbField; 4 | import com.alibaba.protokit.annotation.PbMessage; 5 | 6 | @PbMessage 7 | public class Student { 8 | @PbField(tag = 1) 9 | private long id; 10 | 11 | @PbField(tag = 2) 12 | private String name; 13 | @PbField(tag = 3) 14 | private int age; 15 | 16 | @PbField(tag = 4) 17 | private boolean checked; 18 | 19 | public long getId() { 20 | return id; 21 | } 22 | 23 | public void setId(long id) { 24 | this.id = id; 25 | } 26 | 27 | public String getName() { 28 | return name; 29 | } 30 | 31 | public void setName(String name) { 32 | this.name = name; 33 | } 34 | 35 | public int getAge() { 36 | return age; 37 | } 38 | 39 | public void setAge(int age) { 40 | this.age = age; 41 | } 42 | 43 | public boolean isChecked() { 44 | return checked; 45 | } 46 | 47 | public void setChecked(boolean checked) { 48 | this.checked = checked; 49 | } 50 | 51 | @Override 52 | public int hashCode() { 53 | final int prime = 31; 54 | int result = 1; 55 | result = prime * result + age; 56 | result = prime * result + (checked ? 1231 : 1237); 57 | result = prime * result + (int) (id ^ (id >>> 32)); 58 | result = prime * result + ((name == null) ? 0 : name.hashCode()); 59 | return result; 60 | } 61 | 62 | @Override 63 | public boolean equals(Object obj) { 64 | if (this == obj) 65 | return true; 66 | if (obj == null) 67 | return false; 68 | if (getClass() != obj.getClass()) 69 | return false; 70 | Student other = (Student) obj; 71 | if (age != other.age) 72 | return false; 73 | if (checked != other.checked) 74 | return false; 75 | if (id != other.id) 76 | return false; 77 | if (name == null) { 78 | if (other.name != null) 79 | return false; 80 | } else if (!name.equals(other.name)) 81 | return false; 82 | return true; 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /protokit-generator/src/test/java/com/alibaba/protokit/gen/template/ProtoDumperTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.protokit.gen.template; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | 6 | import org.junit.jupiter.api.Test; 7 | 8 | import com.aaa.School; 9 | import com.abc.Student; 10 | import com.alibaba.protokit.utils.NameUtils; 11 | import com.google.inject.Guice; 12 | import com.google.inject.Injector; 13 | 14 | import io.protostuff.compiler.ParserModule; 15 | import io.protostuff.compiler.model.Message; 16 | import io.protostuff.compiler.model.Proto; 17 | import io.protostuff.compiler.parser.Importer; 18 | import io.protostuff.compiler.parser.LocalFileReader; 19 | import io.protostuff.compiler.parser.ProtoContext; 20 | 21 | /** 22 | * 23 | * @author hengyunabc 2021-01-22 24 | * 25 | */ 26 | public class ProtoDumperTest { 27 | 28 | @Test 29 | public void test() throws IOException { 30 | String file = this.getClass().getProtectionDomain().getCodeSource().getLocation().getFile(); 31 | String outputPath = new File(file, "../test-output").getAbsolutePath(); 32 | 33 | ProtoDumper.dumpMessage(Student.class, outputPath); 34 | ProtoDumper.dumpMessage(School.class, outputPath); 35 | 36 | String studentPbString = ProtoDumper.dumpMessage(Student.class); 37 | 38 | studentPbString = ProtoDumper.dumpMessage(School.class); 39 | 40 | ProtoDumper.dumpMessage(School.class, outputPath); 41 | 42 | Injector injector = Guice.createInjector(new ParserModule()); 43 | Importer importer = injector.getInstance(Importer.class); 44 | 45 | System.err.println(studentPbString); 46 | 47 | LocalFileReader localFileReader = new LocalFileReader(new File(outputPath).toPath()); 48 | 49 | ProtoContext context = importer.importFile(localFileReader, NameUtils.pbFileName(School.class)); 50 | Proto proto = context.getProto(); 51 | 52 | System.err.println(proto); 53 | 54 | Message studentPB = context.resolve(Message.class, "SchoolPB"); 55 | 56 | System.err.println(studentPB); 57 | 58 | System.err.println(proto.getMessage("SchoolPB")); 59 | System.err.println(context.getImports().get(0).getProto().getMessage("StudentPB")); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /protokit-generator/src/main/resources/proto3.stg: -------------------------------------------------------------------------------- 1 | //import "io/protostuff/generator/core.stg" 2 | //import "io/protostuff/generator/proto/TextFormat.stg" 3 | 4 | //proto_compiler_enabled(proto) ::= "true" 5 | //message_compiler_enabled(message) ::= "true" !$ 6 | 7 | proto_compiler_output(proto) ::= << 8 | .proto 9 | >> 10 | 11 | proto_compiler_template(proto) ::= << 12 | 13 | 14 | 15 | 16 | 17 | 18 | >> 19 | 20 | syntax(proto) ::= << 21 | syntax = ""; 22 | >> 23 | 24 | package(proto) ::= << 25 | package ; 26 | >> 27 | 28 | imports(proto) ::= << 29 | 30 | >> 31 | 32 | proto_import(name) ::= << 33 | import ""; 34 | >> 35 | 36 | options(container) ::= << 37 | }; separator="\n"> 39 | >> 40 | 41 | option(key, value) ::= << 42 | <\\> 43 | option = ;<\\> 44 | <\\> 45 | option = ;<\\> 46 | 47 | >> 48 | 49 | text_format_value(value) ::= <% 50 | 51 | '' 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | %> 60 | 61 | messages(container) ::= << 62 | 63 | >> 64 | 65 | // skip map entry message 66 | message(message) ::= << 67 | 68 | 69 | 70 | message { 71 | 72 | 73 | 74 | } 75 | 76 | >> 77 | 78 | comment(str) ::= << 79 | // 80 | >> 81 | 82 | message_fields(message) ::= << 83 | 84 | >> 85 | 86 | message_field(field) ::= <% 87 | ; 88 | %> 89 | 90 | enums(container) ::= << 91 | 92 | >> 93 | 94 | enum(enum) ::= << 95 | enum { 96 | 97 | } 98 | >> 99 | 100 | enum_values(enum) ::= << 101 | 102 | >> 103 | 104 | enum_value(value) ::= << 105 | = ; 106 | >> 107 | 108 | 109 | -------------------------------------------------------------------------------- /protokit-generator/src/test/java/com/aaa/SchoolPbConvertor.java: -------------------------------------------------------------------------------- 1 | package com.aaa; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | 6 | import com.aaa.SchoolPB.Builder; 7 | import com.alibaba.protokit.gen.PbConvertor; 8 | import com.alibaba.protokit.gen.PbConvertorUtils; 9 | 10 | public class SchoolPbConvertor implements PbConvertor { 11 | 12 | @Override 13 | public T convertToPbObject(School object) { 14 | Builder builder = SchoolPB.newBuilder(); 15 | builder.setName(object.getName()); 16 | 17 | com.abc.StudentPbConvertor convertor = new com.abc.StudentPbConvertor(); 18 | 19 | builder.putAllIdToStudents(PbConvertorUtils.convertToPbMap(object.getIdToStudents(), convertor)); 20 | builder.putAllNameToStudents(PbConvertorUtils.convertToPbMap(object.getNameToStudents(), convertor)); 21 | builder.addAllStudents(PbConvertorUtils.convertToPbList(object.getStudents(), convertor)); 22 | builder.addAllIds(PbConvertorUtils.convertToPbList(object.getIds(), new IntegerPbConvertor())); 23 | 24 | return (T) builder.build(); 25 | } 26 | 27 | @Override 28 | public School fromPbObject(Object pbObject) { 29 | School school = new School(); 30 | 31 | com.abc.StudentPbConvertor convertor = new com.abc.StudentPbConvertor(); 32 | 33 | SchoolPB schoolPb = (SchoolPB) pbObject; 34 | 35 | school.setName(schoolPb.getName()); 36 | 37 | Map nameToStudentsMap = schoolPb.getNameToStudentsMap(); 38 | school.setNameToStudents(PbConvertorUtils.fromPbMap(nameToStudentsMap, convertor)); 39 | 40 | Map idToStudentsMap = schoolPb.getIdToStudentsMap(); 41 | school.setIdToStudents(PbConvertorUtils.fromPbMap(idToStudentsMap, convertor)); 42 | 43 | List studentsList = schoolPb.getStudentsList(); 44 | school.setStudents(PbConvertorUtils.fromPbList(studentsList, convertor)); 45 | 46 | List idsList = schoolPb.getIdsList(); 47 | school.setIds(PbConvertorUtils.fromPbList(idsList, new IntegerPbConvertor())); 48 | 49 | return school; 50 | } 51 | 52 | public static class IntegerPbConvertor implements PbConvertor { 53 | 54 | @Override 55 | public T2 convertToPbObject(Integer object) { 56 | return (T2) object; 57 | } 58 | 59 | @Override 60 | public Integer fromPbObject(Object pbObject) { 61 | return (Integer) pbObject; 62 | } 63 | 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /protokit-generator/src/main/java/com/alibaba/protokit/gen/PbConvertorUtils.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.protokit.gen; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.HashMap; 6 | import java.util.Iterator; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.Map.Entry; 10 | import java.util.Set; 11 | 12 | /** 13 | * 14 | * @author hengyunabc 2021-03-10 15 | * 16 | */ 17 | public class PbConvertorUtils { 18 | // List 19 | public static List convertToPbList(java.lang.Iterable values, PbConvertor convertor) { 20 | if (values == null) { 21 | return Collections.emptyList(); 22 | } 23 | List list = new ArrayList<>(); 24 | for (Object object : values) { 25 | list.add(convertor.convertToPbObject(object)); 26 | } 27 | return list; 28 | } 29 | 30 | // List 31 | public static List fromPbList(java.lang.Iterable values, PbConvertor convertor) { 32 | if (values == null) { 33 | return Collections.emptyList(); 34 | } 35 | List list = new ArrayList<>(); 36 | for (Object object : values) { 37 | list.add(convertor.fromPbObject(object)); 38 | } 39 | return list; 40 | } 41 | 42 | // Map 43 | public static Map convertToPbMap(Map map, PbConvertor convertor) { 44 | if (map == null) { 45 | return Collections.emptyMap(); 46 | } 47 | Map result = new HashMap(); 48 | 49 | Set entrySet = map.entrySet(); 50 | Iterator iterator = entrySet.iterator(); 51 | 52 | while (iterator.hasNext()) { 53 | Entry entry = (Entry) iterator.next(); 54 | Object value = entry.getValue(); 55 | Object convertToPbObject = convertor.convertToPbObject(value); 56 | result.put(entry.getKey(), convertToPbObject); 57 | } 58 | 59 | return result; 60 | } 61 | 62 | // Map 63 | public static Map fromPbMap(Map map, PbConvertor convertor) { 64 | if (map == null) { 65 | return Collections.emptyMap(); 66 | } 67 | Map result = new HashMap(); 68 | Set entrySet = map.entrySet(); 69 | Iterator iterator = entrySet.iterator(); 70 | 71 | while (iterator.hasNext()) { 72 | Entry entry = (Entry) iterator.next(); 73 | Object value = entry.getValue(); 74 | Object fromPbObject = convertor.fromPbObject(value); 75 | result.put(entry.getKey(), fromPbObject); 76 | } 77 | return result; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /protokit-generator/src/test/java/aaa/SchoolPbConvertor.java: -------------------------------------------------------------------------------- 1 | package aaa; 2 | import com.aaa.SchoolPB; 3 | import com.aaa.SchoolPB.Builder; 4 | import com.alibaba.protokit.gen.PbConvertor; 5 | public class SchoolPbConvertor implements com.alibaba.protokit.gen.PbConvertor{ 6 | 7 | @Override 8 | public T convertToPbObject(com.aaa.School object) { 9 | com.aaa.SchoolPB.Builder builder = com.aaa.SchoolPB.newBuilder(); 10 | builder.setName(object.getName()); 11 | { 12 | com.abc.StudentPbConvertor convertor = new com.abc.StudentPbConvertor(); 13 | builder.addAllStudents(com.alibaba.protokit.gen.PbConvertorUtils.convertToPbList(object.getStudents(), convertor)); 14 | } 15 | { 16 | com.abc.StudentPbConvertor convertor = new com.abc.StudentPbConvertor(); 17 | builder.putAllNameToStudents(com.alibaba.protokit.gen.PbConvertorUtils.convertToPbMap(object.getNameToStudents(), convertor)); 18 | } 19 | { 20 | com.abc.StudentPbConvertor convertor = new com.abc.StudentPbConvertor(); 21 | builder.putAllIdToStudents(com.alibaba.protokit.gen.PbConvertorUtils.convertToPbMap(object.getIdToStudents(), convertor)); 22 | } 23 | { 24 | com.alibaba.protokit.gen.IntegerPbConvertor convertor = new com.alibaba.protokit.gen.IntegerPbConvertor(); 25 | builder.addAllIds(com.alibaba.protokit.gen.PbConvertorUtils.convertToPbList(object.getIds(), convertor)); 26 | } 27 | return (T) builder.build(); 28 | } 29 | @Override 30 | public com.aaa.School fromPbObject(Object pbObject) { 31 | com.aaa.School object = new com.aaa.School(); 32 | com.aaa.SchoolPB fromPbObject = (com.aaa.SchoolPB) pbObject; 33 | object.setName(fromPbObject.getName()); 34 | { 35 | com.abc.StudentPbConvertor convertor = new com.abc.StudentPbConvertor(); 36 | object.setStudents(com.alibaba.protokit.gen.PbConvertorUtils.fromPbList(fromPbObject.getStudentsList(), convertor)); 37 | } 38 | { 39 | com.abc.StudentPbConvertor convertor = new com.abc.StudentPbConvertor(); 40 | object.setNameToStudents(com.alibaba.protokit.gen.PbConvertorUtils.fromPbMap(fromPbObject.getNameToStudentsMap(), convertor)); 41 | } 42 | { 43 | com.abc.StudentPbConvertor convertor = new com.abc.StudentPbConvertor(); 44 | object.setIdToStudents(com.alibaba.protokit.gen.PbConvertorUtils.fromPbMap(fromPbObject.getIdToStudentsMap(), convertor)); 45 | } 46 | { 47 | com.alibaba.protokit.gen.IntegerPbConvertor convertor = new com.alibaba.protokit.gen.IntegerPbConvertor(); 48 | object.setIds(com.alibaba.protokit.gen.PbConvertorUtils.fromPbList(fromPbObject.getIdsList(), convertor)); 49 | } 50 | return object; 51 | } 52 | } -------------------------------------------------------------------------------- /protokit-generator/src/main/resources/convertor.stg: -------------------------------------------------------------------------------- 1 | 2 | 3 | convertor_compiler_template(meta) ::= << 4 | 5 | 6 | 7 | 8 | >> 9 | 10 | package(meta) ::= << 11 | package ; 12 | >> 13 | 14 | imports(meta) ::= << 15 | 16 | >> 17 | 18 | meta_import(name) ::= << 19 | import ; 20 | >> 21 | 22 | class(meta) ::= << 23 | public class PbConvertor implements com.alibaba.protokit.gen.PbConvertor\<.\>{ 24 | 25 | 26 | 27 | } 28 | >> 29 | 30 | formMethod(meta) ::= << 31 | @Override 32 | public . fromPbObject(Object pbObject) { 33 | . object = new .(); 34 | . fromPbObject = (.) pbObject; 35 | 36 | return object; 37 | } 38 | >> 39 | 40 | formMessages(meta) ::= << 41 | 42 | >> 43 | 44 | fromMessage(message) ::= << 45 | 46 | >> 47 | 48 | fromFields(message) ::=<< 49 | 50 | >> 51 | 52 | fromField(field) ::=<< 53 | 54 | >> 55 | 56 | 57 | 58 | 59 | toMethod(meta) ::= << 60 | @Override 61 | public \ T convertToPbObject(. object) { 62 | ..Builder builder = ..newBuilder(); 63 | 64 | return (T) builder.build(); 65 | } 66 | >> 67 | 68 | toMessages(meta) ::= << 69 | 70 | >> 71 | 72 | toMessage(message) ::= << 73 | 74 | >> 75 | 76 | toFields(message) ::=<< 77 | 78 | >> 79 | 80 | toField(field) ::=<< 81 | 82 | >> 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | messages(container) ::= << 95 | 96 | >> 97 | 98 | // skip map entry message 99 | message(message) ::= << 100 | 101 | 102 | 103 | message { 104 | 105 | 106 | 107 | } 108 | 109 | >> 110 | 111 | comment(str) ::= << 112 | // 113 | >> 114 | 115 | message_fields(message) ::= << 116 | 117 | >> 118 | 119 | message_field(field) ::= <% 120 | 121 | %> 122 | 123 | enums(container) ::= << 124 | 125 | >> 126 | 127 | enum(enum) ::= << 128 | enum { 129 | 130 | } 131 | >> 132 | 133 | enum_values(enum) ::= << 134 | 135 | >> 136 | 137 | enum_value(value) ::= << 138 | = ; 139 | >> 140 | 141 | 142 | -------------------------------------------------------------------------------- /protokit-generator/src/main/java/com/alibaba/protokit/gen/template/ProtoDumper.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.protokit.gen.template; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.util.List; 6 | import java.util.Locale; 7 | import java.util.Optional; 8 | 9 | import org.apache.commons.io.FileUtils; 10 | import org.stringtemplate.v4.AttributeRenderer; 11 | import org.stringtemplate.v4.ST; 12 | import org.stringtemplate.v4.STGroup; 13 | import org.stringtemplate.v4.STGroupFile; 14 | 15 | import com.alibaba.protokit.annotation.PbAnnotationParser; 16 | import com.alibaba.protokit.model.MetaData; 17 | import com.alibaba.protokit.utils.NameUtils; 18 | 19 | import io.protostuff.compiler.model.Field; 20 | import io.protostuff.compiler.model.Message; 21 | import io.protostuff.compiler.model.Proto; 22 | 23 | /** 24 | * 25 | * @author hengyunabc 2021-01-22 26 | * 27 | */ 28 | public class ProtoDumper { 29 | 30 | 31 | public static String dumpMessage(Class clazz) throws IOException { 32 | String filePath = clazz.getCanonicalName().replace(".", "/") + ".proto"; 33 | PbAnnotationParser pbAnnotationParser = new PbAnnotationParser(); 34 | Optional metaDataOptional = pbAnnotationParser.parse(clazz); 35 | 36 | MetaData metaData = metaDataOptional.get(); 37 | Proto proto = metaData.getProto(); 38 | STGroup group = new STGroupFile("proto3.stg"); 39 | group.registerRenderer(Field.class, new FieldRenderer(proto, group)); 40 | 41 | ST st = group.getInstanceOf("proto_compiler_template"); 42 | st.add("proto", proto); 43 | String result = st.render(); 44 | return result; 45 | } 46 | 47 | public static void dumpMessage(Class clazz, String outputDir) throws IOException { 48 | String filePath = NameUtils.pbFileName(clazz); 49 | 50 | String result = dumpMessage(clazz); 51 | 52 | FileUtils.write(new File(outputDir, filePath), result, "utf-8"); 53 | } 54 | 55 | static class FieldRenderer implements AttributeRenderer { 56 | private Proto proto; 57 | private STGroup group; 58 | 59 | public FieldRenderer(Proto proto, STGroup group) { 60 | this.proto = proto; 61 | this.group = group; 62 | } 63 | 64 | @Override 65 | public String toString(Field field, String formatString, Locale locale) { 66 | 67 | String pkg = proto.getPackage().getValue(); 68 | if (field.isRepeated() && (!field.getTypeName().endsWith("_entry"))) { 69 | return String.format("%s %s %s = %d", field.getModifier(), field.getType().getCanonicalName(), field.getName(), 70 | field.getTag()); 71 | } else if (field.isRepeated() && field.getTypeName().endsWith("_entry")) { 72 | Message type = (Message) field.getType(); 73 | 74 | Field keyField = type.getField("key"); 75 | Field valueField = type.getField("value"); 76 | String keyType = keyField.getTypeName(); 77 | String valueType = valueField.getTypeName(); 78 | return String.format("map<%s, %s> %s = %d", keyType, valueType, field.getName(), field.getTag()); 79 | } else { 80 | return String.format("%s %s = %d", field.getTypeName(), field.getName(), field.getTag()); 81 | } 82 | 83 | } 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /protokit-generator/src/main/java/com/alibaba/protokit/utils/NameUtils.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.protokit.utils; 2 | 3 | import com.alibaba.protokit.common.Constants; 4 | 5 | import io.protostuff.compiler.model.Field; 6 | import io.protostuff.compiler.model.FieldType; 7 | 8 | /** 9 | * 10 | * @author hengyunabc 2021-02-08 11 | * 12 | */ 13 | public class NameUtils { 14 | 15 | public static String pbClassName(Class clazz) { 16 | return clazz.getSimpleName() + Constants.PB_MESSAGE_SUFFIX; 17 | } 18 | 19 | public static String pbFieldTypeName(Class clazz) { 20 | return clazz.getCanonicalName() + Constants.PB_MESSAGE_SUFFIX; 21 | } 22 | 23 | public static String originClassName(String pbClassName) { 24 | if (pbClassName.endsWith(Constants.PB_MESSAGE_SUFFIX)) { 25 | return pbClassName.substring(0, pbClassName.length() - Constants.PB_MESSAGE_SUFFIX.length()); 26 | } 27 | return pbClassName; 28 | } 29 | 30 | public static String pbFullyQualifiedName(Class clazz) { 31 | return "." + clazz.getCanonicalName() + Constants.PB_MESSAGE_SUFFIX; 32 | } 33 | 34 | public static String pbFileName(Class clazz) { 35 | return clazz.getCanonicalName().replace(".", "/") + Constants.PB_MESSAGE_SUFFIX + Constants.PB_FILE_EXT; 36 | } 37 | 38 | public static String pbFileName(String pbTypeName) { 39 | return pbTypeName.replace(".", "/") + Constants.PB_FILE_EXT; 40 | } 41 | 42 | public static String convertorFileName(Class clazz) { 43 | return clazz.getCanonicalName().replace(".", "/") + Constants.CONVERTOR_SUFFIX + Constants.JAVA_FILE_EXT; 44 | } 45 | 46 | public static String convertorClassName(String className) { 47 | // 判断原始类型,再返回对应的 48 | if (className.equals("int32")) { 49 | return "com.alibaba.protokit.gen.IntegerPbConvertor"; 50 | } else { 51 | // Student -> StudentPbConvertor 52 | return className + Constants.CONVERTOR_SUFFIX; 53 | } 54 | } 55 | 56 | public static String upperFirstChar(String name) { 57 | if (name.length() == 1) { 58 | return name.toUpperCase(); 59 | } 60 | return name.substring(0, 1).toUpperCase() + name.substring(1); 61 | } 62 | 63 | // pb类里 list field的函数 64 | public static String putAllMethodName(String fieldName) { 65 | return "putAll" + upperFirstChar(fieldName); 66 | } 67 | 68 | // builder.addAllStudents 69 | public static String addAllMethodName(String fieldName) { 70 | return "addAll" + upperFirstChar(fieldName); 71 | } 72 | 73 | // schoolPb.getStudentsList 74 | public static String getPbListMethodName(String fieldName) { 75 | return "get" + upperFirstChar(fieldName) + "List"; 76 | } 77 | 78 | // schoolPb.getIdToStudentsMap(); 79 | public static String getPbMapMethodName(String fieldName) { 80 | return "get" + upperFirstChar(fieldName) + "Map"; 81 | } 82 | 83 | public static String getterMethod(Field field, boolean checkBool) { 84 | String name = field.getName(); 85 | String startPart = name.substring(0, 1).toUpperCase(); 86 | if (checkBool && "bool".equals(field.getTypeName())) { 87 | return "is" + startPart + name.substring(1); 88 | } 89 | return "get" + startPart + name.substring(1); 90 | } 91 | 92 | public static String setterMethod(Field field) { 93 | String name = field.getName(); 94 | String startPart = name.substring(0, 1).toUpperCase(); 95 | return "set" + startPart + name.substring(1); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /protokit-generator/src/test/java/com/aaa/School.java: -------------------------------------------------------------------------------- 1 | package com.aaa; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | 6 | import com.abc.Student; 7 | import com.alibaba.protokit.annotation.PbField; 8 | import com.alibaba.protokit.annotation.PbMessage; 9 | 10 | @PbMessage 11 | public class School { 12 | 13 | @PbField(tag = 1) 14 | private String name; 15 | @PbField(tag = 2) 16 | private List students; 17 | 18 | @PbField(tag = 3) 19 | private Map nameToStudents; 20 | 21 | @PbField(tag = 4) 22 | private Map idToStudents; 23 | 24 | @PbField(tag = 5) 25 | private List ids; 26 | 27 | public String getName() { 28 | return name; 29 | } 30 | 31 | public void setName(String name) { 32 | this.name = name; 33 | } 34 | 35 | public List getStudents() { 36 | return students; 37 | } 38 | 39 | public void setStudents(List students) { 40 | this.students = students; 41 | } 42 | 43 | public Map getNameToStudents() { 44 | return nameToStudents; 45 | } 46 | 47 | public void setNameToStudents(Map nameToStudents) { 48 | this.nameToStudents = nameToStudents; 49 | } 50 | 51 | public Map getIdToStudents() { 52 | return idToStudents; 53 | } 54 | 55 | public void setIdToStudents(Map idToStudents) { 56 | this.idToStudents = idToStudents; 57 | } 58 | 59 | public List getIds() { 60 | return ids; 61 | } 62 | 63 | public void setIds(List ids) { 64 | this.ids = ids; 65 | } 66 | 67 | @Override 68 | public int hashCode() { 69 | final int prime = 31; 70 | int result = 1; 71 | result = prime * result + ((idToStudents == null) ? 0 : idToStudents.hashCode()); 72 | result = prime * result + ((ids == null) ? 0 : ids.hashCode()); 73 | result = prime * result + ((name == null) ? 0 : name.hashCode()); 74 | result = prime * result + ((nameToStudents == null) ? 0 : nameToStudents.hashCode()); 75 | result = prime * result + ((students == null) ? 0 : students.hashCode()); 76 | return result; 77 | } 78 | 79 | @Override 80 | public boolean equals(Object obj) { 81 | if (this == obj) 82 | return true; 83 | if (obj == null) 84 | return false; 85 | if (getClass() != obj.getClass()) 86 | return false; 87 | School other = (School) obj; 88 | if (idToStudents == null) { 89 | if (other.idToStudents != null) 90 | return false; 91 | } else if (!idToStudents.equals(other.idToStudents)) 92 | return false; 93 | if (ids == null) { 94 | if (other.ids != null) 95 | return false; 96 | } else if (!ids.equals(other.ids)) 97 | return false; 98 | if (name == null) { 99 | if (other.name != null) 100 | return false; 101 | } else if (!name.equals(other.name)) 102 | return false; 103 | if (nameToStudents == null) { 104 | if (other.nameToStudents != null) 105 | return false; 106 | } else if (!nameToStudents.equals(other.nameToStudents)) 107 | return false; 108 | if (students == null) { 109 | if (other.students != null) 110 | return false; 111 | } else if (!students.equals(other.students)) 112 | return false; 113 | return true; 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /protokit-maven-plugin/src/main/java/com/alibaba/protokit/plugin/ProtoKitCompileMojo.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.protokit.plugin; 2 | 3 | import static org.apache.maven.plugins.annotations.LifecyclePhase.GENERATE_TEST_SOURCES; 4 | 5 | import java.io.File; 6 | import java.net.URL; 7 | import java.net.URLClassLoader; 8 | import java.util.List; 9 | 10 | import org.apache.maven.plugin.AbstractMojo; 11 | import org.apache.maven.plugin.MojoExecution; 12 | import org.apache.maven.plugin.MojoExecutionException; 13 | import org.apache.maven.plugin.MojoFailureException; 14 | import org.apache.maven.plugins.annotations.LifecyclePhase; 15 | import org.apache.maven.plugins.annotations.Mojo; 16 | import org.apache.maven.plugins.annotations.Parameter; 17 | import org.apache.maven.plugins.annotations.ResolutionScope; 18 | import org.apache.maven.project.MavenProject; 19 | 20 | import com.alibaba.protokit.gen.template.JavaDumper; 21 | import com.alibaba.protokit.gen.template.ProtoDumper; 22 | 23 | /** 24 | * 25 | * @author hengyunabc 2021-01-12 26 | * 27 | */ 28 | 29 | @Mojo(name = "compile", defaultPhase = LifecyclePhase.PROCESS_CLASSES, requiresDependencyResolution = ResolutionScope.COMPILE, threadSafe = true) 30 | public class ProtoKitCompileMojo extends AbstractMojo { 31 | 32 | /** 33 | * The current Maven project. 34 | */ 35 | @Parameter(defaultValue = "${project}", readonly = true) 36 | protected MavenProject project; 37 | @Parameter(defaultValue = "${mojoExecution}", readonly = true) 38 | private MojoExecution execution; 39 | /** 40 | * Biz Pojo Classes 41 | */ 42 | @Parameter(required = false) 43 | private List classNames; 44 | 45 | @Parameter(required = true, defaultValue = "${project.basedir}/src/main/proto") 46 | private File protoOutputDirectory; 47 | 48 | @Parameter(required = true, defaultValue = "${project.build.directory}/generated-sources/protokit/java") 49 | private File javaOutputDirectory; 50 | 51 | @Override 52 | public void execute() throws MojoExecutionException, MojoFailureException { 53 | // TODO 更丰富的指定配置的方式? 54 | 55 | ClassLoader classLoader = getClassLoader(); 56 | 57 | try { 58 | for (String clazz : classNames) { 59 | Class pojoClass = classLoader.loadClass(clazz); 60 | ProtoDumper.dumpMessage(pojoClass, protoOutputDirectory.getAbsolutePath()); 61 | getLog().info("ProtoDumper dump: " + clazz); 62 | JavaDumper.dumpCode(pojoClass, javaOutputDirectory.getAbsolutePath()); 63 | getLog().info("JavaDumper dump: " + clazz + ", path: " + javaOutputDirectory.getAbsolutePath()); 64 | 65 | addGeneratedSourcesToProject(javaOutputDirectory.getAbsolutePath()); 66 | } 67 | } catch (Exception e) { 68 | e.printStackTrace(); 69 | } 70 | 71 | } 72 | 73 | void addGeneratedSourcesToProject(String output) { 74 | // Include generated directory to the list of compilation sources 75 | if (GENERATE_TEST_SOURCES.id().equals(execution.getLifecyclePhase())) { 76 | project.addTestCompileSourceRoot(output); 77 | } else { 78 | project.addCompileSourceRoot(output); 79 | } 80 | } 81 | 82 | /** 83 | * Returns the an isolated classloader. 84 | * 85 | * @return ClassLoader 86 | * @noinspection unchecked 87 | */ 88 | private ClassLoader getClassLoader() { 89 | try { 90 | List classpathElements = project.getCompileClasspathElements(); 91 | classpathElements.add(project.getBuild().getOutputDirectory()); 92 | classpathElements.add(project.getBuild().getTestOutputDirectory()); 93 | URL urls[] = new URL[classpathElements.size()]; 94 | for (int i = 0; i < classpathElements.size(); ++i) { 95 | urls[i] = new File((String) classpathElements.get(i)).toURI().toURL(); 96 | } 97 | return new URLClassLoader(urls, this.getClass().getClassLoader()); 98 | } catch (Exception e) { 99 | getLog().debug("Couldn't get the classloader."); 100 | return this.getClass().getClassLoader(); 101 | } 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /protokit-maven-plugin/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.alibaba 8 | protokit-parent 9 | ${revision} 10 | ../pom.xml 11 | 12 | protokit-maven-plugin 13 | protokit-maven-plugin 14 | maven-plugin 15 | 16 | 17 | 18 | 3.0 19 | 1.7.1 20 | 3.1.0 21 | 3.5.2 22 | 23 | 24 | 25 | 26 | 27 | 28 | com.alibaba 29 | protokit-generator 30 | ${project.version} 31 | 32 | 33 | 34 | org.apache.maven 35 | maven-plugin-api 36 | ${mavenVersion} 37 | 38 | 39 | org.codehaus.plexus 40 | plexus-component-annotations 41 | 42 | 43 | org.codehaus.plexus 44 | plexus-utils 45 | 46 | 47 | 48 | 49 | org.apache.maven.plugin-tools 50 | maven-plugin-annotations 51 | ${pluginToolsVersion} 52 | 53 | 54 | org.codehaus.plexus 55 | plexus-utils 56 | ${plexusUtilsVersion} 57 | 58 | 59 | org.codehaus.plexus 60 | plexus-component-annotations 61 | ${plexusComponentVersion} 62 | 63 | 64 | org.sonatype.plexus 65 | plexus-build-api 66 | 0.0.7 67 | 68 | 69 | org.codehaus.plexus 70 | plexus-utils 71 | 72 | 73 | 74 | 75 | org.apache.maven 76 | maven-core 77 | ${mavenVersion} 78 | 79 | 80 | org.codehaus.plexus 81 | plexus-component-annotations 82 | 83 | 84 | org.codehaus.plexus 85 | plexus-utils 86 | 87 | 88 | 89 | 90 | org.apache.maven 91 | maven-artifact 92 | ${mavenVersion} 93 | 94 | 95 | org.codehaus.plexus 96 | plexus-utils 97 | 98 | 99 | 100 | 101 | org.apache.maven 102 | maven-compat 103 | ${mavenVersion} 104 | 105 | 106 | org.codehaus.plexus 107 | plexus-component-annotations 108 | 109 | 110 | org.codehaus.plexus 111 | plexus-utils 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | org.apache.maven.plugins 121 | maven-plugin-plugin 122 | 3.4 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /protokit-demo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.alibaba 8 | protokit-parent 9 | ${revision} 10 | ../pom.xml 11 | 12 | protokit-demo 13 | protokit-demo 14 | 15 | 16 | 17 | 18 | org.slf4j 19 | slf4j-api 20 | provided 21 | true 22 | 23 | 24 | 25 | com.alibaba 26 | protokit-generator 27 | ${revision} 28 | provided 29 | true 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | org.codehaus.mojo 38 | build-helper-maven-plugin 39 | 40 | 41 | initialize 42 | 43 | add-source 44 | 45 | 46 | 47 | target/generated-sources/proto 48 | target/generated-sources/protokit/java 49 | 50 | 51 | 52 | 53 | 54 | 55 | com.alibaba 56 | protokit-maven-plugin 57 | ${project.version} 58 | 59 | 60 | 61 | compile 62 | 63 | 64 | 65 | com.test.demo.Company 66 | com.test.demo.User 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | kr.motd.maven 77 | os-maven-plugin 78 | 1.6.1 79 | 80 | 81 | initialize 82 | 83 | detect 84 | 85 | 86 | 87 | 88 | 89 | org.xolstice.maven.plugins 90 | protobuf-maven-plugin 91 | 0.6.1 92 | 93 | com.google.protobuf:protoc:3.8.0:exe:${os.detected.classifier} 94 | grpc-java 95 | io.grpc:protoc-gen-grpc-java:1.22.3:exe:${os.detected.classifier} 96 | 97 | 98 | 99 | 100 | compile 101 | compile-custom 102 | 103 | 104 | 105 | 106 | 107 | 108 | org.apache.maven.plugins 109 | maven-compiler-plugin 110 | 111 | 112 | prepare-package 113 | 114 | compile 115 | 116 | 117 | 118 | 119 | 120 | 121 | org.apache.maven.plugins 122 | maven-jar-plugin 123 | 124 | 125 | prepare-package 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /protokit-generator/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.alibaba 8 | protokit-parent 9 | ${revision} 10 | ../pom.xml 11 | 12 | protokit-generator 13 | protokit-generator 14 | 15 | 16 | 17 | 18 | org.slf4j 19 | slf4j-api 20 | provided 21 | true 22 | 23 | 24 | 25 | org.slf4j 26 | slf4j-simple 27 | provided 28 | true 29 | 30 | 31 | 32 | org.antlr 33 | ST4 34 | 4.3.1 35 | 36 | 37 | 38 | io.protostuff 39 | protostuff-parser 40 | 2.2.27 41 | 42 | 43 | 44 | io.protostuff 45 | protostuff-api 46 | 47 | 48 | 49 | com.samskivert 50 | jmustache 51 | true 52 | 53 | 54 | 55 | org.springframework 56 | spring-core 57 | 5.3.3 58 | 59 | 60 | 61 | org.reflections 62 | reflections 63 | 64 | 65 | 66 | javax.annotation 67 | javax.annotation-api 68 | 69 | 70 | 71 | com.google.protobuf 72 | protobuf-java 73 | 3.8.0 74 | 75 | 76 | commons-io 77 | commons-io 78 | 2.8.0 79 | 80 | 81 | org.apache.commons 82 | commons-lang3 83 | 3.9 84 | 85 | 86 | 87 | 88 | 89 | 90 | kr.motd.maven 91 | os-maven-plugin 92 | 1.6.1 93 | 94 | 95 | initialize 96 | 97 | detect 98 | 99 | 100 | 101 | 102 | 103 | org.xolstice.maven.plugins 104 | protobuf-maven-plugin 105 | 0.6.1 106 | 107 | com.google.protobuf:protoc:3.8.0:exe:${os.detected.classifier} 108 | grpc-java 109 | io.grpc:protoc-gen-grpc-java:1.22.3:exe:${os.detected.classifier} 110 | 111 | 112 | 113 | 114 | compile 115 | compile-custom 116 | 117 | 118 | 119 | 120 | 121 | 122 | org.codehaus.mojo 123 | build-helper-maven-plugin 124 | 125 | 126 | generate-sources 127 | 128 | add-source 129 | 130 | 131 | 132 | target/generated-sources/proto 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /protokit-generator/src/main/proto/google/protobuf/any.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option go_package = "google.golang.org/protobuf/types/known/anypb"; 37 | option java_package = "com.google.protobuf"; 38 | option java_outer_classname = "AnyProto"; 39 | option java_multiple_files = true; 40 | option objc_class_prefix = "GPB"; 41 | 42 | // `Any` contains an arbitrary serialized protocol buffer message along with a 43 | // URL that describes the type of the serialized message. 44 | // 45 | // Protobuf library provides support to pack/unpack Any values in the form 46 | // of utility functions or additional generated methods of the Any type. 47 | // 48 | // Example 1: Pack and unpack a message in C++. 49 | // 50 | // Foo foo = ...; 51 | // Any any; 52 | // any.PackFrom(foo); 53 | // ... 54 | // if (any.UnpackTo(&foo)) { 55 | // ... 56 | // } 57 | // 58 | // Example 2: Pack and unpack a message in Java. 59 | // 60 | // Foo foo = ...; 61 | // Any any = Any.pack(foo); 62 | // ... 63 | // if (any.is(Foo.class)) { 64 | // foo = any.unpack(Foo.class); 65 | // } 66 | // 67 | // Example 3: Pack and unpack a message in Python. 68 | // 69 | // foo = Foo(...) 70 | // any = Any() 71 | // any.Pack(foo) 72 | // ... 73 | // if any.Is(Foo.DESCRIPTOR): 74 | // any.Unpack(foo) 75 | // ... 76 | // 77 | // Example 4: Pack and unpack a message in Go 78 | // 79 | // foo := &pb.Foo{...} 80 | // any, err := anypb.New(foo) 81 | // if err != nil { 82 | // ... 83 | // } 84 | // ... 85 | // foo := &pb.Foo{} 86 | // if err := any.UnmarshalTo(foo); err != nil { 87 | // ... 88 | // } 89 | // 90 | // The pack methods provided by protobuf library will by default use 91 | // 'type.googleapis.com/full.type.name' as the type URL and the unpack 92 | // methods only use the fully qualified type name after the last '/' 93 | // in the type URL, for example "foo.bar.com/x/y.z" will yield type 94 | // name "y.z". 95 | // 96 | // 97 | // JSON 98 | // ==== 99 | // The JSON representation of an `Any` value uses the regular 100 | // representation of the deserialized, embedded message, with an 101 | // additional field `@type` which contains the type URL. Example: 102 | // 103 | // package google.profile; 104 | // message Person { 105 | // string first_name = 1; 106 | // string last_name = 2; 107 | // } 108 | // 109 | // { 110 | // "@type": "type.googleapis.com/google.profile.Person", 111 | // "firstName": , 112 | // "lastName": 113 | // } 114 | // 115 | // If the embedded message type is well-known and has a custom JSON 116 | // representation, that representation will be embedded adding a field 117 | // `value` which holds the custom JSON in addition to the `@type` 118 | // field. Example (for message [google.protobuf.Duration][]): 119 | // 120 | // { 121 | // "@type": "type.googleapis.com/google.protobuf.Duration", 122 | // "value": "1.212s" 123 | // } 124 | // 125 | message Any { 126 | // A URL/resource name that uniquely identifies the type of the serialized 127 | // protocol buffer message. This string must contain at least 128 | // one "/" character. The last segment of the URL's path must represent 129 | // the fully qualified name of the type (as in 130 | // `path/google.protobuf.Duration`). The name should be in a canonical form 131 | // (e.g., leading "." is not accepted). 132 | // 133 | // In practice, teams usually precompile into the binary all types that they 134 | // expect it to use in the context of Any. However, for URLs which use the 135 | // scheme `http`, `https`, or no scheme, one can optionally set up a type 136 | // server that maps type URLs to message definitions as follows: 137 | // 138 | // * If no scheme is provided, `https` is assumed. 139 | // * An HTTP GET on the URL must yield a [google.protobuf.Type][] 140 | // value in binary format, or produce an error. 141 | // * Applications are allowed to cache lookup results based on the 142 | // URL, or have them precompiled into a binary to avoid any 143 | // lookup. Therefore, binary compatibility needs to be preserved 144 | // on changes to types. (Use versioned type names to manage 145 | // breaking changes.) 146 | // 147 | // Note: this functionality is not currently available in the official 148 | // protobuf release, and it is not used for type URLs beginning with 149 | // type.googleapis.com. 150 | // 151 | // Schemes other than `http`, `https` (or the empty scheme) might be 152 | // used with implementation specific semantics. 153 | // 154 | string type_url = 1; 155 | 156 | // Must be a valid serialized protocol buffer of the above specified type. 157 | bytes value = 2; 158 | } 159 | -------------------------------------------------------------------------------- /protokit-generator/src/main/java/com/alibaba/protokit/gen/template/JavaDumper.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.protokit.gen.template; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.util.Locale; 6 | import java.util.Optional; 7 | 8 | import org.apache.commons.io.FileUtils; 9 | import org.stringtemplate.v4.AttributeRenderer; 10 | import org.stringtemplate.v4.ST; 11 | import org.stringtemplate.v4.STGroup; 12 | import org.stringtemplate.v4.STGroupFile; 13 | 14 | import com.alibaba.protokit.annotation.PbAnnotationParser; 15 | import com.alibaba.protokit.common.Constants; 16 | import com.alibaba.protokit.model.MetaData; 17 | import com.alibaba.protokit.utils.NameUtils; 18 | 19 | import io.protostuff.compiler.model.Field; 20 | import io.protostuff.compiler.model.Message; 21 | import io.protostuff.compiler.model.Proto; 22 | 23 | /** 24 | * 25 | * @author hengyunabc 2021-03-09 26 | * 27 | */ 28 | public class JavaDumper { 29 | 30 | public static String dumpCode(Class clazz) throws IOException { 31 | String filePath = clazz.getCanonicalName().replace(".", "/") + ".proto"; 32 | PbAnnotationParser pbAnnotationParser = new PbAnnotationParser(); 33 | Optional metaDataOptional = pbAnnotationParser.parse(clazz); 34 | 35 | MetaData metaData = metaDataOptional.get(); 36 | 37 | Proto proto = metaData.getProto(); 38 | STGroup group = new STGroupFile("convertor.stg"); 39 | group.registerRenderer(Field.class, new FieldRenderer(proto, group)); 40 | 41 | ST st = group.getInstanceOf("convertor_compiler_template"); 42 | st.add("meta", metaData); 43 | String result = st.render(); 44 | return result; 45 | } 46 | 47 | public static void dumpCode(Class clazz, String outputDir) throws IOException { 48 | String filePath = NameUtils.convertorFileName(clazz); 49 | 50 | String result = dumpCode(clazz); 51 | 52 | FileUtils.write(new File(outputDir, filePath), result, "utf-8"); 53 | } 54 | 55 | static class FieldRenderer implements AttributeRenderer { 56 | private Proto proto; 57 | private STGroup group; 58 | 59 | public FieldRenderer(Proto proto, STGroup group) { 60 | this.proto = proto; 61 | this.group = group; 62 | } 63 | 64 | @Override 65 | public String toString(Field field, String formatString, Locale locale) { 66 | 67 | if ("to".equals(formatString)) { // to method 68 | String pkg = proto.getPackage().getValue(); 69 | if (field.isRepeated() && (!field.getTypeName().endsWith("_entry"))) { 70 | 71 | // StudentPbConvertor convertor = new StudentPbConvertor(); 72 | // builder.putAllIdToStudents(PbConvertorUtils.convertToPbMap(object.getIdToStudents(), 73 | // convertor)); 74 | 75 | // builder.addAllStudents(PbConvertorUtils.convertToPbList(object.getStudents(), 76 | // convertor)); 77 | 78 | // Field{name=students, modifier=repeated, typeName=StudentPB, tag=2, 79 | // options=DynamicMessage{fields={}}} 80 | 81 | String className = NameUtils.originClassName(field.getTypeName()); 82 | String convertorClassName = NameUtils.convertorClassName(className); 83 | 84 | String createConvertor = String.format(" %s convertor = new %s();\n", convertorClassName, convertorClassName); 85 | String callConvertor = String.format(" builder.%s(com.alibaba.protokit.gen.PbConvertorUtils.convertToPbList(object.%s(), convertor));", 86 | NameUtils.addAllMethodName(field.getName()), NameUtils.getterMethod(field, true)); 87 | return "{\n" + createConvertor + callConvertor + "\n}"; 88 | // return String.format("%s %s %s = %d", field.getModifier(), field.getType().getCanonicalName(), 89 | // field.getName(), field.getTag()); 90 | 91 | } else if (field.isRepeated() && field.getTypeName().endsWith("_entry")) { 92 | Message type = (Message) field.getType(); 93 | 94 | Field keyField = type.getField("key"); 95 | Field valueField = type.getField("value"); 96 | String keyType = keyField.getTypeName(); 97 | String valueType = valueField.getTypeName(); 98 | 99 | String className = NameUtils.originClassName(valueField.getTypeName()); 100 | String convertorClassName = NameUtils.convertorClassName(className); 101 | 102 | String createConvertor = String.format(" %s convertor = new %s();\n", convertorClassName, convertorClassName); 103 | String callConvertor = String.format(" builder.%s(com.alibaba.protokit.gen.PbConvertorUtils.convertToPbMap(object.%s(), convertor));", 104 | NameUtils.putAllMethodName(field.getName()), NameUtils.getterMethod(field, true)); 105 | return "{\n" + createConvertor + callConvertor + "\n}"; 106 | 107 | } else { 108 | String sss = "builder.%s(object.%s());"; 109 | return String.format(sss, NameUtils.setterMethod(field), NameUtils.getterMethod(field, true)); 110 | } 111 | } else if ("from".equals(formatString)) { // from method 112 | String pkg = proto.getPackage().getValue(); 113 | if (field.isRepeated() && (!field.getTypeName().endsWith("_entry"))) { 114 | 115 | // StudentPbConvertor convertor = new StudentPbConvertor(); 116 | // object.setStudents(PbConvertorUtils.fromPbList(fromPbObject.getStudentsList(), convertor)); 117 | 118 | String className = NameUtils.originClassName(field.getTypeName()); 119 | String convertorClassName = NameUtils.convertorClassName(className); 120 | 121 | String createConvertor = String.format(" %s convertor = new %s();\n", convertorClassName, convertorClassName); 122 | String callConvertor = String.format(" object.%s(com.alibaba.protokit.gen.PbConvertorUtils.fromPbList(fromPbObject.%s(), convertor));", 123 | NameUtils.setterMethod(field), NameUtils.getPbListMethodName(field.getName())); 124 | return "{\n" + createConvertor + callConvertor + "\n}"; 125 | } else if (field.isRepeated() && field.getTypeName().endsWith("_entry")) { 126 | Message type = (Message) field.getType(); 127 | 128 | Field keyField = type.getField("key"); 129 | Field valueField = type.getField("value"); 130 | String keyType = keyField.getTypeName(); 131 | String valueType = valueField.getTypeName(); 132 | 133 | String className = NameUtils.originClassName(valueField.getTypeName()); 134 | String convertorClassName = NameUtils.convertorClassName(className); 135 | 136 | String createConvertor = String.format(" %s convertor = new %s();\n", convertorClassName, convertorClassName); 137 | String callConvertor = String.format(" object.%s(com.alibaba.protokit.gen.PbConvertorUtils.fromPbMap(fromPbObject.%s(), convertor));", 138 | NameUtils.setterMethod(field), NameUtils.getPbMapMethodName(field.getName())); 139 | return "{\n" + createConvertor + callConvertor + "\n}"; 140 | } else { 141 | String sss = "object.%s(fromPbObject.%s());"; 142 | return String.format(sss, NameUtils.setterMethod(field), NameUtils.getterMethod(field, false)); 143 | } 144 | } 145 | 146 | return field.toString(); 147 | } 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /protokit-generator/src/main/java/com/alibaba/protokit/annotation/PbAnnotationParser.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.protokit.annotation; 2 | 3 | import java.lang.annotation.Annotation; 4 | import java.lang.reflect.Field; 5 | import java.lang.reflect.ParameterizedType; 6 | import java.util.ArrayList; 7 | import java.util.Arrays; 8 | import java.util.Collection; 9 | import java.util.Collections; 10 | import java.util.Comparator; 11 | import java.util.List; 12 | import java.util.Map; 13 | import java.util.Optional; 14 | import java.util.Set; 15 | 16 | import org.reflections.ReflectionUtils; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | 20 | import com.alibaba.protokit.model.MetaData; 21 | import com.alibaba.protokit.utils.NameUtils; 22 | 23 | import io.protostuff.compiler.model.DynamicMessage.Value; 24 | import io.protostuff.compiler.model.FieldModifier; 25 | import io.protostuff.compiler.model.FieldType; 26 | import io.protostuff.compiler.model.Import; 27 | import io.protostuff.compiler.model.Message; 28 | import io.protostuff.compiler.model.Package; 29 | import io.protostuff.compiler.model.Proto; 30 | import io.protostuff.compiler.model.ScalarFieldType; 31 | import io.protostuff.compiler.model.Syntax; 32 | 33 | /** 34 | * 从传入的类里解析出 具体的 pb 信息 35 | * 36 | * @author hengyunabc 2021-01-20 37 | * 38 | */ 39 | public class PbAnnotationParser { 40 | private static final Logger logger = LoggerFactory.getLogger(PbAnnotationParser.class); 41 | 42 | public Optional parse(Class clazz) { 43 | 44 | MetaData metaData = new MetaData(); 45 | 46 | @SuppressWarnings("unchecked") 47 | Set annotations = ReflectionUtils.getAnnotations(clazz, 48 | a -> a.annotationType().equals(PbMessage.class)); 49 | 50 | if (annotations.isEmpty()) { 51 | logger.debug("class: {} can not find annotation: {}", clazz, PbMessage.class); 52 | return Optional.empty(); 53 | } 54 | 55 | String fileName = NameUtils.pbFileName(clazz); 56 | 57 | String packageName = clazz.getPackage().getName(); 58 | 59 | Proto proto = new Proto(); 60 | proto.setFilename(fileName); 61 | proto.setSyntax(new Syntax(proto, "proto3")); 62 | Package pkg = new Package(proto, packageName); 63 | proto.setPackage(pkg); 64 | 65 | metaData.setClassName(clazz.getSimpleName()); 66 | metaData.setPbClassName(NameUtils.pbClassName(clazz)); 67 | metaData.setPackageName(packageName); 68 | 69 | Message message = new Message(proto); 70 | message.setName(NameUtils.pbClassName(clazz)); 71 | proto.addMessage(message); 72 | 73 | // options 74 | // option java_package = "com.aaa"; 75 | // option java_multiple_files = true; 76 | proto.getOptions().set("java_package", Value.createString(packageName)); 77 | proto.getOptions().set("java_multiple_files", Value.createBoolean(true)); 78 | 79 | Set fields = ReflectionUtils.getFields(clazz, f -> f.getAnnotationsByType(PbField.class).length > 0); 80 | List fieldList = new ArrayList<>(fields); 81 | Collections.sort(fieldList, new Comparator() { 82 | @Override 83 | public int compare(Field f1, Field f2) { 84 | return f1.getAnnotationsByType(PbField.class)[0].tag() 85 | - f2.getAnnotationsByType(PbField.class)[0].tag(); 86 | } 87 | }); 88 | 89 | for (Field field : fieldList) { 90 | Class fieldType = field.getType(); 91 | java.lang.reflect.Type genericType = field.getGenericType(); 92 | 93 | PbField pbFieldAnnotation = field.getAnnotationsByType(PbField.class)[0]; 94 | 95 | if (genericType instanceof ParameterizedType) { 96 | java.lang.reflect.Type[] actualTypes = ((ParameterizedType) genericType).getActualTypeArguments(); 97 | 98 | Class rawType = (Class) ((ParameterizedType) genericType).getRawType(); 99 | 100 | if (Collection.class.isAssignableFrom(rawType)) { 101 | 102 | FieldType pbType = toPbType((Class) actualTypes[0]); 103 | addImport(proto, pbType.getCanonicalName()); 104 | io.protostuff.compiler.model.Field pbField = new io.protostuff.compiler.model.Field(message); 105 | pbField.setTag(pbFieldAnnotation.tag()); 106 | pbField.setName(field.getName()); 107 | pbField.setComments(Arrays.asList(pbFieldAnnotation.comment())); 108 | pbField.setType(pbType); 109 | pbField.setTypeName(pbType.getName()); 110 | pbField.setModifier(FieldModifier.REPEATED); 111 | message.addField(pbField); 112 | 113 | } else if (Map.class.isAssignableFrom(rawType)) { 114 | 115 | Message mapMessage = mapFieldToMessage(field, actualTypes); 116 | io.protostuff.compiler.model.Field pbField = new io.protostuff.compiler.model.Field(message); 117 | pbField.setTag(pbFieldAnnotation.tag()); 118 | pbField.setName(field.getName()); 119 | pbField.setComments(Arrays.asList(pbFieldAnnotation.comment())); 120 | pbField.setType(mapMessage); 121 | pbField.setTypeName(mapMessage.getName()); 122 | pbField.setModifier(FieldModifier.REPEATED); 123 | message.addField(pbField); 124 | 125 | message.addMessage(mapMessage); 126 | } else { 127 | String errMsg = "can not process class: " + clazz.getName() + ", field: " + field.getName(); 128 | throw new UnsupportedOperationException(errMsg); 129 | } 130 | } else { 131 | FieldType pbType = toPbType(fieldType); 132 | addImport(proto, pbType.getCanonicalName()); 133 | 134 | io.protostuff.compiler.model.Field pbField = new io.protostuff.compiler.model.Field(message); 135 | pbField.setTag(pbFieldAnnotation.tag()); 136 | pbField.setName(field.getName()); 137 | pbField.setComments(Arrays.asList(pbFieldAnnotation.comment())); 138 | pbField.setType(pbType); 139 | pbField.setTypeName(pbType.getName()); 140 | message.addField(pbField); 141 | 142 | } 143 | 144 | } 145 | 146 | metaData.setProto(proto); 147 | return Optional.of(metaData); 148 | } 149 | 150 | private FieldType toPbType(Class clazz) { 151 | if (double.class.isAssignableFrom(clazz) || Double.class.isAssignableFrom(clazz)) { 152 | return ScalarFieldType.DOUBLE; 153 | } else if (float.class.isAssignableFrom(clazz) || Float.class.isAssignableFrom(clazz)) { 154 | return ScalarFieldType.FLOAT; 155 | } else if (long.class.isAssignableFrom(clazz) || Long.class.isAssignableFrom(clazz)) { 156 | return ScalarFieldType.INT64; 157 | } else if (int.class.isAssignableFrom(clazz) || Integer.class.isAssignableFrom(clazz)) { 158 | return ScalarFieldType.INT32; 159 | } else if (boolean.class.isAssignableFrom(clazz) || Boolean.class.isAssignableFrom(clazz)) { 160 | return ScalarFieldType.BOOL; 161 | } else if (String.class.isAssignableFrom(clazz)) { 162 | return ScalarFieldType.STRING; 163 | } else if (clazz.isEnum()) { 164 | return null; 165 | } else { 166 | // TODO Message? 167 | // 对于已经是PB的类,要处理,比如 List 168 | Message message = new Message(null); 169 | message.setName(NameUtils.pbFieldTypeName(clazz)); 170 | message.setFullyQualifiedName(NameUtils.pbFullyQualifiedName(clazz)); 171 | return message; 172 | } 173 | } 174 | 175 | private Message mapFieldToMessage(Field field, java.lang.reflect.Type[] actualTypes) { 176 | // messages=[ 177 | // Message{name=nameToStudents_entry, fullyQualifiedName=.com.aaa.SchoolPB.nameToStudents_entry, 178 | // fields=[ 179 | // Field{name=key, modifier=optional, typeName=string, tag=1, options=DynamicMessage{fields={}}}, 180 | // Field{name=value, modifier=optional, typeName=StudentPB, tag=2, options=DynamicMessage{fields={}}}], 181 | // options=DynamicMessage{fields={map_entry=true}}}, 182 | // 183 | Message message = new Message(null); 184 | message.setName(field.getName() + "_entry"); 185 | String fieldPackage = field.getDeclaringClass().getPackage().getName(); 186 | message.setFullyQualifiedName("." + fieldPackage + "." + field.getName() + "_entry"); 187 | io.protostuff.compiler.model.Field key = new io.protostuff.compiler.model.Field(message); 188 | key.setName("key"); 189 | key.setType(toPbType((Class) actualTypes[0])); 190 | key.setTypeName(key.getType().getName()); 191 | key.setTag(1); 192 | io.protostuff.compiler.model.Field value = new io.protostuff.compiler.model.Field(message); 193 | value.setName("value"); 194 | value.setType(toPbType((Class) actualTypes[1])); 195 | value.setTypeName(value.getType().getCanonicalName()); 196 | value.setTag(2); 197 | 198 | message.getOptions().set("map_entry", Value.createBoolean(true)); 199 | 200 | message.addField(key); 201 | message.addField(value); 202 | return message; 203 | } 204 | 205 | private void addImport(Proto proto, String pbTypeName) { 206 | // 排掉pb本身的类型 207 | if (ScalarFieldType.getByName(pbTypeName) != null) { 208 | return; 209 | } 210 | Import imp = new Import(proto, NameUtils.pbFileName(pbTypeName), false); 211 | List imports = proto.getImports(); 212 | if (!imports.contains(imp)) { 213 | imports.add(imp); 214 | } 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | org.sonatype.oss 6 | oss-parent 7 | 9 8 | 9 | 10 | 4.0.0 11 | com.alibaba 12 | protokit-parent 13 | ${revision} 14 | pom 15 | 16 | protokit 17 | A kit for protobuf 18 | 2021 19 | https://github.com/alibaba/protokit 20 | 21 | 22 | 23 | Apache 2 24 | http://www.apache.org/licenses/LICENSE-2.0.txt 25 | repo 26 | 27 | 28 | 29 | 30 | 31 | scm:git:git@github.com:alibaba/protokit.git 32 | scm:git:git@github.com:alibaba/protokit.git 33 | https://github.com/alibaba/protokit 34 | HEAD 35 | 36 | 37 | 38 | hengyunabc 39 | hengyunabc 40 | hengyunabc@gmail.com 41 | 42 | 43 | RobberPhex 44 | luyanbo 45 | robberphex@gmail.com 46 | 47 | 48 | 49 | 50 | 51 | 0.0.1-SNAPSHOT 52 | 1.8 53 | 1.8 54 | 1.8 55 | UTF-8 56 | UTF-8 57 | 58 | 1.0.0 59 | 60 | 1.7.30 61 | 62 | 63 | 5.7.0 64 | 65 | 66 | 67 | 68 | protokit-generator 69 | protokit-maven-plugin 70 | protokit-demo 71 | protokit-demo2 72 | 73 | 74 | 75 | 76 | 77 | org.junit 78 | junit-bom 79 | ${junit.version} 80 | pom 81 | import 82 | 83 | 84 | 85 | io.protostuff 86 | protostuff-api 87 | 1.7.2 88 | 89 | 90 | 91 | com.samskivert 92 | jmustache 93 | 1.14 94 | 95 | 96 | 97 | org.reflections 98 | reflections 99 | 0.9.12 100 | 101 | 102 | 103 | javax.annotation 104 | javax.annotation-api 105 | 1.3.2 106 | 107 | 108 | 109 | org.slf4j 110 | slf4j-api 111 | ${slf4j.version} 112 | 113 | 114 | 115 | org.slf4j 116 | slf4j-simple 117 | ${slf4j.version} 118 | 119 | 120 | 121 | org.mockito 122 | mockito-core 123 | 2.28.2 124 | test 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | org.junit.jupiter 133 | junit-jupiter 134 | test 135 | 136 | 137 | 138 | org.assertj 139 | assertj-core 140 | 141 | 2.9.1 142 | test 143 | true 144 | 145 | 146 | 147 | 148 | 149 | release 150 | 151 | 152 | performRelease 153 | true 154 | 155 | 156 | 157 | 158 | 159 | org.apache.maven.plugins 160 | maven-gpg-plugin 161 | 162 | 163 | sign-artifacts 164 | verify 165 | 166 | sign 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | org.apache.maven.plugins 181 | maven-compiler-plugin 182 | 3.8.0 183 | 184 | 185 | org.apache.maven.plugins 186 | maven-assembly-plugin 187 | 3.2.0 188 | 189 | 190 | org.apache.maven.plugins 191 | maven-release-plugin 192 | 3.0.0-M1 193 | 194 | 195 | org.apache.maven.plugins 196 | maven-antrun-plugin 197 | 1.8 198 | 199 | 200 | 201 | org.codehaus.mojo 202 | build-helper-maven-plugin 203 | 3.2.0 204 | 205 | 206 | 207 | io.protostuff 208 | protostuff-maven-plugin 209 | 2.2.27 210 | 211 | 212 | 214 | 215 | org.eclipse.m2e 216 | lifecycle-mapping 217 | ${lifecycle-mapping.version} 218 | 219 | 220 | 221 | 222 | 223 | 224 | org.apache.maven.plugins 225 | 226 | 227 | maven-invoker-plugin 228 | 229 | 230 | [1.0.0,) 231 | 232 | 233 | 234 | install 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | org.codehaus.mojo 246 | 247 | 248 | flatten-maven-plugin 249 | 250 | 251 | [1.0.0,) 252 | 253 | 254 | flatten 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | org.apache.maven.plugins 271 | maven-jar-plugin 272 | 3.2.0 273 | 274 | 275 | 276 | true 277 | true 278 | 279 | 280 | 281 | 282 | 283 | org.apache.maven.plugins 284 | maven-javadoc-plugin 285 | 3.2.0 286 | 287 | none 288 | 1.8 289 | false 290 | 291 | 292 | 293 | release 294 | package 295 | 296 | jar 297 | 298 | 299 | 300 | 301 | 302 | 303 | org.apache.maven.plugins 304 | maven-deploy-plugin 305 | 2.8.2 306 | 307 | 308 | default-deploy 309 | deploy 310 | 311 | deploy 312 | 313 | 314 | true 315 | 316 | 317 | 318 | release 319 | deploy 320 | 321 | deploy 322 | 323 | 324 | 325 | 326 | 327 | 328 | org.apache.maven.plugins 329 | maven-source-plugin 330 | 3.2.1 331 | 332 | 333 | attach-sources 334 | 335 | jar 336 | 337 | 338 | 339 | 340 | 341 | 342 | org.codehaus.mojo 343 | flatten-maven-plugin 344 | 1.2.2 345 | 346 | 347 | minimum 348 | 349 | 350 | 351 | 352 | flatten 353 | process-resources 354 | 355 | flatten 356 | 357 | 358 | 359 | flatten-clean 360 | clean 361 | 362 | clean 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | -------------------------------------------------------------------------------- /protokit-generator/src/main/proto/google/protobuf/descriptor.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | // Author: kenton@google.com (Kenton Varda) 32 | // Based on original Protocol Buffers design by 33 | // Sanjay Ghemawat, Jeff Dean, and others. 34 | // 35 | // The messages in this file describe the definitions found in .proto files. 36 | // A valid .proto file can be translated directly to a FileDescriptorProto 37 | // without any other information (e.g. without reading its imports). 38 | 39 | 40 | syntax = "proto2"; 41 | 42 | package google.protobuf; 43 | option go_package = "github.com/golang/protobuf/protoc-gen-go/descriptor;descriptor"; 44 | option java_package = "com.google.protobuf"; 45 | option java_outer_classname = "DescriptorProtos"; 46 | option csharp_namespace = "Google.Protobuf.Reflection"; 47 | option objc_class_prefix = "GPB"; 48 | option cc_enable_arenas = true; 49 | 50 | // descriptor.proto must be optimized for speed because reflection-based 51 | // algorithms don't work during bootstrapping. 52 | option optimize_for = SPEED; 53 | 54 | // The protocol compiler can output a FileDescriptorSet containing the .proto 55 | // files it parses. 56 | message FileDescriptorSet { 57 | repeated FileDescriptorProto file = 1; 58 | } 59 | 60 | // Describes a complete .proto file. 61 | message FileDescriptorProto { 62 | optional string name = 1; // file name, relative to root of source tree 63 | optional string package = 2; // e.g. "foo", "foo.bar", etc. 64 | 65 | // Names of files imported by this file. 66 | repeated string dependency = 3; 67 | // Indexes of the public imported files in the dependency list above. 68 | repeated int32 public_dependency = 10; 69 | // Indexes of the weak imported files in the dependency list. 70 | // For Google-internal migration only. Do not use. 71 | repeated int32 weak_dependency = 11; 72 | 73 | // All top-level definitions in this file. 74 | repeated DescriptorProto message_type = 4; 75 | repeated EnumDescriptorProto enum_type = 5; 76 | repeated ServiceDescriptorProto service = 6; 77 | repeated FieldDescriptorProto extension = 7; 78 | 79 | optional FileOptions options = 8; 80 | 81 | // This field contains optional information about the original source code. 82 | // You may safely remove this entire field without harming runtime 83 | // functionality of the descriptors -- the information is needed only by 84 | // development tools. 85 | optional SourceCodeInfo source_code_info = 9; 86 | 87 | // The syntax of the proto file. 88 | // The supported values are "proto2" and "proto3". 89 | optional string syntax = 12; 90 | } 91 | 92 | // Describes a message type. 93 | message DescriptorProto { 94 | optional string name = 1; 95 | 96 | repeated FieldDescriptorProto field = 2; 97 | repeated FieldDescriptorProto extension = 6; 98 | 99 | repeated DescriptorProto nested_type = 3; 100 | repeated EnumDescriptorProto enum_type = 4; 101 | 102 | message ExtensionRange { 103 | optional int32 start = 1; 104 | optional int32 end = 2; 105 | 106 | optional ExtensionRangeOptions options = 3; 107 | } 108 | repeated ExtensionRange extension_range = 5; 109 | 110 | repeated OneofDescriptorProto oneof_decl = 8; 111 | 112 | optional MessageOptions options = 7; 113 | 114 | // Range of reserved tag numbers. Reserved tag numbers may not be used by 115 | // fields or extension ranges in the same message. Reserved ranges may 116 | // not overlap. 117 | message ReservedRange { 118 | optional int32 start = 1; // Inclusive. 119 | optional int32 end = 2; // Exclusive. 120 | } 121 | repeated ReservedRange reserved_range = 9; 122 | // Reserved field names, which may not be used by fields in the same message. 123 | // A given name may only be reserved once. 124 | repeated string reserved_name = 10; 125 | } 126 | 127 | message ExtensionRangeOptions { 128 | // The parser stores options it doesn't recognize here. See above. 129 | repeated UninterpretedOption uninterpreted_option = 999; 130 | 131 | // Clients can define custom options in extensions of this message. See above. 132 | extensions 1000 to max; 133 | } 134 | 135 | // Describes a field within a message. 136 | message FieldDescriptorProto { 137 | enum Type { 138 | // 0 is reserved for errors. 139 | // Order is weird for historical reasons. 140 | TYPE_DOUBLE = 1; 141 | TYPE_FLOAT = 2; 142 | // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if 143 | // negative values are likely. 144 | TYPE_INT64 = 3; 145 | TYPE_UINT64 = 4; 146 | // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if 147 | // negative values are likely. 148 | TYPE_INT32 = 5; 149 | TYPE_FIXED64 = 6; 150 | TYPE_FIXED32 = 7; 151 | TYPE_BOOL = 8; 152 | TYPE_STRING = 9; 153 | // Tag-delimited aggregate. 154 | // Group type is deprecated and not supported in proto3. However, Proto3 155 | // implementations should still be able to parse the group wire format and 156 | // treat group fields as unknown fields. 157 | TYPE_GROUP = 10; 158 | TYPE_MESSAGE = 11; // Length-delimited aggregate. 159 | 160 | // New in version 2. 161 | TYPE_BYTES = 12; 162 | TYPE_UINT32 = 13; 163 | TYPE_ENUM = 14; 164 | TYPE_SFIXED32 = 15; 165 | TYPE_SFIXED64 = 16; 166 | TYPE_SINT32 = 17; // Uses ZigZag encoding. 167 | TYPE_SINT64 = 18; // Uses ZigZag encoding. 168 | }; 169 | 170 | enum Label { 171 | // 0 is reserved for errors 172 | LABEL_OPTIONAL = 1; 173 | LABEL_REQUIRED = 2; 174 | LABEL_REPEATED = 3; 175 | }; 176 | 177 | optional string name = 1; 178 | optional int32 number = 3; 179 | optional Label label = 4; 180 | 181 | // If type_name is set, this need not be set. If both this and type_name 182 | // are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. 183 | optional Type type = 5; 184 | 185 | // For message and enum types, this is the name of the type. If the name 186 | // starts with a '.', it is fully-qualified. Otherwise, C++-like scoping 187 | // rules are used to find the type (i.e. first the nested types within this 188 | // message are searched, then within the parent, on up to the root 189 | // namespace). 190 | optional string type_name = 6; 191 | 192 | // For extensions, this is the name of the type being extended. It is 193 | // resolved in the same manner as type_name. 194 | optional string extendee = 2; 195 | 196 | // For numeric types, contains the original text representation of the value. 197 | // For booleans, "true" or "false". 198 | // For strings, contains the default text contents (not escaped in any way). 199 | // For bytes, contains the C escaped value. All bytes >= 128 are escaped. 200 | // TODO(kenton): Base-64 encode? 201 | optional string default_value = 7; 202 | 203 | // If set, gives the index of a oneof in the containing type's oneof_decl 204 | // list. This field is a member of that oneof. 205 | optional int32 oneof_index = 9; 206 | 207 | // JSON name of this field. The value is set by protocol compiler. If the 208 | // user has set a "json_name" option on this field, that option's value 209 | // will be used. Otherwise, it's deduced from the field's name by converting 210 | // it to camelCase. 211 | optional string json_name = 10; 212 | 213 | optional FieldOptions options = 8; 214 | } 215 | 216 | // Describes a oneof. 217 | message OneofDescriptorProto { 218 | optional string name = 1; 219 | optional OneofOptions options = 2; 220 | } 221 | 222 | // Describes an enum type. 223 | message EnumDescriptorProto { 224 | optional string name = 1; 225 | 226 | repeated EnumValueDescriptorProto value = 2; 227 | 228 | optional EnumOptions options = 3; 229 | 230 | // Range of reserved numeric values. Reserved values may not be used by 231 | // entries in the same enum. Reserved ranges may not overlap. 232 | // 233 | // Note that this is distinct from DescriptorProto.ReservedRange in that it 234 | // is inclusive such that it can appropriately represent the entire int32 235 | // domain. 236 | message EnumReservedRange { 237 | optional int32 start = 1; // Inclusive. 238 | optional int32 end = 2; // Inclusive. 239 | } 240 | 241 | // Range of reserved numeric values. Reserved numeric values may not be used 242 | // by enum values in the same enum declaration. Reserved ranges may not 243 | // overlap. 244 | repeated EnumReservedRange reserved_range = 4; 245 | 246 | // Reserved enum value names, which may not be reused. A given name may only 247 | // be reserved once. 248 | repeated string reserved_name = 5; 249 | } 250 | 251 | // Describes a value within an enum. 252 | message EnumValueDescriptorProto { 253 | optional string name = 1; 254 | optional int32 number = 2; 255 | 256 | optional EnumValueOptions options = 3; 257 | } 258 | 259 | // Describes a service. 260 | message ServiceDescriptorProto { 261 | optional string name = 1; 262 | repeated MethodDescriptorProto method = 2; 263 | 264 | optional ServiceOptions options = 3; 265 | } 266 | 267 | // Describes a method of a service. 268 | message MethodDescriptorProto { 269 | optional string name = 1; 270 | 271 | // Input and output type names. These are resolved in the same way as 272 | // FieldDescriptorProto.type_name, but must refer to a message type. 273 | optional string input_type = 2; 274 | optional string output_type = 3; 275 | 276 | optional MethodOptions options = 4; 277 | 278 | // Identifies if client streams multiple client messages 279 | optional bool client_streaming = 5 [default = false]; 280 | // Identifies if server streams multiple server messages 281 | optional bool server_streaming = 6 [default = false]; 282 | } 283 | 284 | // =================================================================== 285 | // Options 286 | 287 | // Each of the definitions above may have "options" attached. These are 288 | // just annotations which may cause code to be generated slightly differently 289 | // or may contain hints for code that manipulates protocol messages. 290 | // 291 | // Clients may define custom options as extensions of the *Options messages. 292 | // These extensions may not yet be known at parsing time, so the parser cannot 293 | // store the values in them. Instead it stores them in a field in the *Options 294 | // message called uninterpreted_option. This field must have the same name 295 | // across all *Options messages. We then use this field to populate the 296 | // extensions when we build a descriptor, at which point all protos have been 297 | // parsed and so all extensions are known. 298 | // 299 | // Extension numbers for custom options may be chosen as follows: 300 | // * For options which will only be used within a single application or 301 | // organization, or for experimental options, use field numbers 50000 302 | // through 99999. It is up to you to ensure that you do not use the 303 | // same number for multiple options. 304 | // * For options which will be published and used publicly by multiple 305 | // independent entities, e-mail protobuf-global-extension-registry@google.com 306 | // to reserve extension numbers. Simply provide your project name (e.g. 307 | // Objective-C plugin) and your project website (if available) -- there's no 308 | // need to explain how you intend to use them. Usually you only need one 309 | // extension number. You can declare multiple options with only one extension 310 | // number by putting them in a sub-message. See the Custom Options section of 311 | // the docs for examples: 312 | // https://developers.google.com/protocol-buffers/docs/proto#options 313 | // If this turns out to be popular, a web service will be set up 314 | // to automatically assign option numbers. 315 | 316 | 317 | message FileOptions { 318 | 319 | // Sets the Java package where classes generated from this .proto will be 320 | // placed. By default, the proto package is used, but this is often 321 | // inappropriate because proto packages do not normally start with backwards 322 | // domain names. 323 | optional string java_package = 1; 324 | 325 | // If set, all the classes from the .proto file are wrapped in a single 326 | // outer class with the given name. This applies to both Proto1 327 | // (equivalent to the old "--one_java_file" option) and Proto2 (where 328 | // a .proto always translates to a single class, but you may want to 329 | // explicitly choose the class name). 330 | optional string java_outer_classname = 8; 331 | 332 | // If set true, then the Java code generator will generate a separate .java 333 | // file for each top-level message, enum, and service defined in the .proto 334 | // file. Thus, these types will *not* be nested inside the outer class 335 | // named by java_outer_classname. However, the outer class will still be 336 | // generated to contain the file's getDescriptor() method as well as any 337 | // top-level extensions defined in the file. 338 | optional bool java_multiple_files = 10 [default = false]; 339 | 340 | // This option does nothing. 341 | optional bool java_generate_equals_and_hash = 20 [deprecated = true]; 342 | 343 | // If set true, then the Java2 code generator will generate code that 344 | // throws an exception whenever an attempt is made to assign a non-UTF-8 345 | // byte sequence to a string field. 346 | // Message reflection will do the same. 347 | // However, an extension field still accepts non-UTF-8 byte sequences. 348 | // This option has no effect on when used with the lite runtime. 349 | optional bool java_string_check_utf8 = 27 [default = false]; 350 | 351 | // Generated classes can be optimized for speed or code size. 352 | enum OptimizeMode { 353 | SPEED = 1; // Generate complete code for parsing, serialization, 354 | // etc. 355 | CODE_SIZE = 2; // Use ReflectionOps to implement these methods. 356 | LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime. 357 | } 358 | optional OptimizeMode optimize_for = 9 [default = SPEED]; 359 | 360 | // Sets the Go package where structs generated from this .proto will be 361 | // placed. If omitted, the Go package will be derived from the following: 362 | // - The basename of the package import path, if provided. 363 | // - Otherwise, the package statement in the .proto file, if present. 364 | // - Otherwise, the basename of the .proto file, without extension. 365 | optional string go_package = 11; 366 | 367 | // Should generic services be generated in each language? "Generic" services 368 | // are not specific to any particular RPC system. They are generated by the 369 | // main code generators in each language (without additional plugins). 370 | // Generic services were the only kind of service generation supported by 371 | // early versions of google.protobuf. 372 | // 373 | // Generic services are now considered deprecated in favor of using plugins 374 | // that generate code specific to your particular RPC system. Therefore, 375 | // these default to false. Old code which depends on generic services should 376 | // explicitly set them to true. 377 | optional bool cc_generic_services = 16 [default = false]; 378 | optional bool java_generic_services = 17 [default = false]; 379 | optional bool py_generic_services = 18 [default = false]; 380 | optional bool php_generic_services = 42 [default = false]; 381 | 382 | // Is this file deprecated? 383 | // Depending on the target platform, this can emit Deprecated annotations 384 | // for everything in the file, or it will be completely ignored; in the very 385 | // least, this is a formalization for deprecating files. 386 | optional bool deprecated = 23 [default = false]; 387 | 388 | // Enables the use of arenas for the proto messages in this file. This applies 389 | // only to generated classes for C++. 390 | optional bool cc_enable_arenas = 31 [default = false]; 391 | 392 | // Sets the objective c class prefix which is prepended to all objective c 393 | // generated classes from this .proto. There is no default. 394 | optional string objc_class_prefix = 36; 395 | 396 | // Namespace for generated classes; defaults to the package. 397 | optional string csharp_namespace = 37; 398 | 399 | // By default Swift generators will take the proto package and CamelCase it 400 | // replacing '.' with underscore and use that to prefix the types/symbols 401 | // defined. When this options is provided, they will use this value instead 402 | // to prefix the types/symbols defined. 403 | optional string swift_prefix = 39; 404 | 405 | // Sets the php class prefix which is prepended to all php generated classes 406 | // from this .proto. Default is empty. 407 | optional string php_class_prefix = 40; 408 | 409 | // Use this option to change the namespace of php generated classes. Default 410 | // is empty. When this option is empty, the package name will be used for 411 | // determining the namespace. 412 | optional string php_namespace = 41; 413 | 414 | // Use this option to change the namespace of php generated metadata classes. 415 | // Default is empty. When this option is empty, the proto file name will be used 416 | // for determining the namespace. 417 | optional string php_metadata_namespace = 44; 418 | 419 | // Use this option to change the package of ruby generated classes. Default 420 | // is empty. When this option is not set, the package name will be used for 421 | // determining the ruby package. 422 | optional string ruby_package = 45; 423 | 424 | // The parser stores options it doesn't recognize here. 425 | // See the documentation for the "Options" section above. 426 | repeated UninterpretedOption uninterpreted_option = 999; 427 | 428 | // Clients can define custom options in extensions of this message. 429 | // See the documentation for the "Options" section above. 430 | extensions 1000 to max; 431 | 432 | reserved 38; 433 | } 434 | 435 | message MessageOptions { 436 | // Set true to use the old proto1 MessageSet wire format for extensions. 437 | // This is provided for backwards-compatibility with the MessageSet wire 438 | // format. You should not use this for any other reason: It's less 439 | // efficient, has fewer features, and is more complicated. 440 | // 441 | // The message must be defined exactly as follows: 442 | // message Foo { 443 | // option message_set_wire_format = true; 444 | // extensions 4 to max; 445 | // } 446 | // Note that the message cannot have any defined fields; MessageSets only 447 | // have extensions. 448 | // 449 | // All extensions of your type must be singular messages; e.g. they cannot 450 | // be int32s, enums, or repeated messages. 451 | // 452 | // Because this is an option, the above two restrictions are not enforced by 453 | // the protocol compiler. 454 | optional bool message_set_wire_format = 1 [default = false]; 455 | 456 | // Disables the generation of the standard "descriptor()" accessor, which can 457 | // conflict with a field of the same name. This is meant to make migration 458 | // from proto1 easier; new code should avoid fields named "descriptor". 459 | optional bool no_standard_descriptor_accessor = 2 [default = false]; 460 | 461 | // Is this message deprecated? 462 | // Depending on the target platform, this can emit Deprecated annotations 463 | // for the message, or it will be completely ignored; in the very least, 464 | // this is a formalization for deprecating messages. 465 | optional bool deprecated = 3 [default = false]; 466 | 467 | // Whether the message is an automatically generated map entry type for the 468 | // maps field. 469 | // 470 | // For maps fields: 471 | // map map_field = 1; 472 | // The parsed descriptor looks like: 473 | // message MapFieldEntry { 474 | // option map_entry = true; 475 | // optional KeyType key = 1; 476 | // optional ValueType value = 2; 477 | // } 478 | // repeated MapFieldEntry map_field = 1; 479 | // 480 | // Implementations may choose not to generate the map_entry=true message, but 481 | // use a native map in the target language to hold the keys and values. 482 | // The reflection APIs in such implementions still need to work as 483 | // if the field is a repeated message field. 484 | // 485 | // NOTE: Do not set the option in .proto files. Always use the maps syntax 486 | // instead. The option should only be implicitly set by the proto compiler 487 | // parser. 488 | optional bool map_entry = 7; 489 | 490 | reserved 8; // javalite_serializable 491 | reserved 9; // javanano_as_lite 492 | 493 | // The parser stores options it doesn't recognize here. See above. 494 | repeated UninterpretedOption uninterpreted_option = 999; 495 | 496 | // Clients can define custom options in extensions of this message. See above. 497 | extensions 1000 to max; 498 | } 499 | 500 | message FieldOptions { 501 | // The ctype option instructs the C++ code generator to use a different 502 | // representation of the field than it normally would. See the specific 503 | // options below. This option is not yet implemented in the open source 504 | // release -- sorry, we'll try to include it in a future version! 505 | optional CType ctype = 1 [default = STRING]; 506 | enum CType { 507 | // Default mode. 508 | STRING = 0; 509 | 510 | CORD = 1; 511 | 512 | STRING_PIECE = 2; 513 | } 514 | // The packed option can be enabled for repeated primitive fields to enable 515 | // a more efficient representation on the wire. Rather than repeatedly 516 | // writing the tag and type for each element, the entire array is encoded as 517 | // a single length-delimited blob. In proto3, only explicit setting it to 518 | // false will avoid using packed encoding. 519 | optional bool packed = 2; 520 | 521 | // The jstype option determines the JavaScript type used for values of the 522 | // field. The option is permitted only for 64 bit integral and fixed types 523 | // (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING 524 | // is represented as JavaScript string, which avoids loss of precision that 525 | // can happen when a large value is converted to a floating point JavaScript. 526 | // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to 527 | // use the JavaScript "number" type. The behavior of the default option 528 | // JS_NORMAL is implementation dependent. 529 | // 530 | // This option is an enum to permit additional types to be added, e.g. 531 | // goog.math.Integer. 532 | optional JSType jstype = 6 [default = JS_NORMAL]; 533 | enum JSType { 534 | // Use the default type. 535 | JS_NORMAL = 0; 536 | 537 | // Use JavaScript strings. 538 | JS_STRING = 1; 539 | 540 | // Use JavaScript numbers. 541 | JS_NUMBER = 2; 542 | } 543 | 544 | // Should this field be parsed lazily? Lazy applies only to message-type 545 | // fields. It means that when the outer message is initially parsed, the 546 | // inner message's contents will not be parsed but instead stored in encoded 547 | // form. The inner message will actually be parsed when it is first accessed. 548 | // 549 | // This is only a hint. Implementations are free to choose whether to use 550 | // eager or lazy parsing regardless of the value of this option. However, 551 | // setting this option true suggests that the protocol author believes that 552 | // using lazy parsing on this field is worth the additional bookkeeping 553 | // overhead typically needed to implement it. 554 | // 555 | // This option does not affect the public interface of any generated code; 556 | // all method signatures remain the same. Furthermore, thread-safety of the 557 | // interface is not affected by this option; const methods remain safe to 558 | // call from multiple threads concurrently, while non-const methods continue 559 | // to require exclusive access. 560 | // 561 | // 562 | // Note that implementations may choose not to check required fields within 563 | // a lazy sub-message. That is, calling IsInitialized() on the outer message 564 | // may return true even if the inner message has missing required fields. 565 | // This is necessary because otherwise the inner message would have to be 566 | // parsed in order to perform the check, defeating the purpose of lazy 567 | // parsing. An implementation which chooses not to check required fields 568 | // must be consistent about it. That is, for any particular sub-message, the 569 | // implementation must either *always* check its required fields, or *never* 570 | // check its required fields, regardless of whether or not the message has 571 | // been parsed. 572 | optional bool lazy = 5 [default = false]; 573 | 574 | // Is this field deprecated? 575 | // Depending on the target platform, this can emit Deprecated annotations 576 | // for accessors, or it will be completely ignored; in the very least, this 577 | // is a formalization for deprecating fields. 578 | optional bool deprecated = 3 [default = false]; 579 | 580 | // For Google-internal migration only. Do not use. 581 | optional bool weak = 10 [default = false]; 582 | 583 | // The parser stores options it doesn't recognize here. See above. 584 | repeated UninterpretedOption uninterpreted_option = 999; 585 | 586 | // Clients can define custom options in extensions of this message. See above. 587 | extensions 1000 to max; 588 | 589 | reserved 4; // removed jtype 590 | } 591 | 592 | message OneofOptions { 593 | // The parser stores options it doesn't recognize here. See above. 594 | repeated UninterpretedOption uninterpreted_option = 999; 595 | 596 | // Clients can define custom options in extensions of this message. See above. 597 | extensions 1000 to max; 598 | } 599 | 600 | message EnumOptions { 601 | 602 | // Set this option to true to allow mapping different tag names to the same 603 | // value. 604 | optional bool allow_alias = 2; 605 | 606 | // Is this enum deprecated? 607 | // Depending on the target platform, this can emit Deprecated annotations 608 | // for the enum, or it will be completely ignored; in the very least, this 609 | // is a formalization for deprecating enums. 610 | optional bool deprecated = 3 [default = false]; 611 | 612 | reserved 5; // javanano_as_lite 613 | 614 | // The parser stores options it doesn't recognize here. See above. 615 | repeated UninterpretedOption uninterpreted_option = 999; 616 | 617 | // Clients can define custom options in extensions of this message. See above. 618 | extensions 1000 to max; 619 | } 620 | 621 | message EnumValueOptions { 622 | // Is this enum value deprecated? 623 | // Depending on the target platform, this can emit Deprecated annotations 624 | // for the enum value, or it will be completely ignored; in the very least, 625 | // this is a formalization for deprecating enum values. 626 | optional bool deprecated = 1 [default = false]; 627 | 628 | // The parser stores options it doesn't recognize here. See above. 629 | repeated UninterpretedOption uninterpreted_option = 999; 630 | 631 | // Clients can define custom options in extensions of this message. See above. 632 | extensions 1000 to max; 633 | } 634 | 635 | message ServiceOptions { 636 | 637 | // Note: Field numbers 1 through 32 are reserved for Google's internal RPC 638 | // framework. We apologize for hoarding these numbers to ourselves, but 639 | // we were already using them long before we decided to release Protocol 640 | // Buffers. 641 | 642 | // Is this service deprecated? 643 | // Depending on the target platform, this can emit Deprecated annotations 644 | // for the service, or it will be completely ignored; in the very least, 645 | // this is a formalization for deprecating services. 646 | optional bool deprecated = 33 [default = false]; 647 | 648 | // The parser stores options it doesn't recognize here. See above. 649 | repeated UninterpretedOption uninterpreted_option = 999; 650 | 651 | // Clients can define custom options in extensions of this message. See above. 652 | extensions 1000 to max; 653 | } 654 | 655 | message MethodOptions { 656 | 657 | // Note: Field numbers 1 through 32 are reserved for Google's internal RPC 658 | // framework. We apologize for hoarding these numbers to ourselves, but 659 | // we were already using them long before we decided to release Protocol 660 | // Buffers. 661 | 662 | // Is this method deprecated? 663 | // Depending on the target platform, this can emit Deprecated annotations 664 | // for the method, or it will be completely ignored; in the very least, 665 | // this is a formalization for deprecating methods. 666 | optional bool deprecated = 33 [default = false]; 667 | 668 | // Is this method side-effect-free (or safe in HTTP parlance), or idempotent, 669 | // or neither? HTTP based RPC implementation may choose GET verb for safe 670 | // methods, and PUT verb for idempotent methods instead of the default POST. 671 | enum IdempotencyLevel { 672 | IDEMPOTENCY_UNKNOWN = 0; 673 | NO_SIDE_EFFECTS = 1; // implies idempotent 674 | IDEMPOTENT = 2; // idempotent, but may have side effects 675 | } 676 | optional IdempotencyLevel idempotency_level = 34 [default = IDEMPOTENCY_UNKNOWN]; 677 | 678 | // The parser stores options it doesn't recognize here. See above. 679 | repeated UninterpretedOption uninterpreted_option = 999; 680 | 681 | // Clients can define custom options in extensions of this message. See above. 682 | extensions 1000 to max; 683 | } 684 | 685 | // A message representing a option the parser does not recognize. This only 686 | // appears in options protos created by the compiler::Parser class. 687 | // DescriptorPool resolves these when building Descriptor objects. Therefore, 688 | // options protos in descriptor objects (e.g. returned by Descriptor::options(), 689 | // or produced by Descriptor::CopyTo()) will never have UninterpretedOptions 690 | // in them. 691 | message UninterpretedOption { 692 | // The name of the uninterpreted option. Each string represents a segment in 693 | // a dot-separated name. is_extension is true iff a segment represents an 694 | // extension (denoted with parentheses in options specs in .proto files). 695 | // E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents 696 | // "foo.(bar.baz).qux". 697 | message NamePart { 698 | required string name_part = 1; 699 | required bool is_extension = 2; 700 | } 701 | repeated NamePart name = 2; 702 | 703 | // The value of the uninterpreted option, in whatever type the tokenizer 704 | // identified it as during parsing. Exactly one of these should be set. 705 | optional string identifier_value = 3; 706 | optional uint64 positive_int_value = 4; 707 | optional int64 negative_int_value = 5; 708 | optional double double_value = 6; 709 | optional bytes string_value = 7; 710 | optional string aggregate_value = 8; 711 | } 712 | 713 | // =================================================================== 714 | // Optional source code info 715 | 716 | // Encapsulates information about the original source file from which a 717 | // FileDescriptorProto was generated. 718 | message SourceCodeInfo { 719 | // A Location identifies a piece of source code in a .proto file which 720 | // corresponds to a particular definition. This information is intended 721 | // to be useful to IDEs, code indexers, documentation generators, and similar 722 | // tools. 723 | // 724 | // For example, say we have a file like: 725 | // message Foo { 726 | // optional string foo = 1; 727 | // } 728 | // Let's look at just the field definition: 729 | // optional string foo = 1; 730 | // ^ ^^ ^^ ^ ^^^ 731 | // a bc de f ghi 732 | // We have the following locations: 733 | // span path represents 734 | // [a,i) [ 4, 0, 2, 0 ] The whole field definition. 735 | // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). 736 | // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). 737 | // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). 738 | // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). 739 | // 740 | // Notes: 741 | // - A location may refer to a repeated field itself (i.e. not to any 742 | // particular index within it). This is used whenever a set of elements are 743 | // logically enclosed in a single code segment. For example, an entire 744 | // extend block (possibly containing multiple extension definitions) will 745 | // have an outer location whose path refers to the "extensions" repeated 746 | // field without an index. 747 | // - Multiple locations may have the same path. This happens when a single 748 | // logical declaration is spread out across multiple places. The most 749 | // obvious example is the "extend" block again -- there may be multiple 750 | // extend blocks in the same scope, each of which will have the same path. 751 | // - A location's span is not always a subset of its parent's span. For 752 | // example, the "extendee" of an extension declaration appears at the 753 | // beginning of the "extend" block and is shared by all extensions within 754 | // the block. 755 | // - Just because a location's span is a subset of some other location's span 756 | // does not mean that it is a descendent. For example, a "group" defines 757 | // both a type and a field in a single declaration. Thus, the locations 758 | // corresponding to the type and field and their components will overlap. 759 | // - Code which tries to interpret locations should probably be designed to 760 | // ignore those that it doesn't understand, as more types of locations could 761 | // be recorded in the future. 762 | repeated Location location = 1; 763 | message Location { 764 | // Identifies which part of the FileDescriptorProto was defined at this 765 | // location. 766 | // 767 | // Each element is a field number or an index. They form a path from 768 | // the root FileDescriptorProto to the place where the definition. For 769 | // example, this path: 770 | // [ 4, 3, 2, 7, 1 ] 771 | // refers to: 772 | // file.message_type(3) // 4, 3 773 | // .field(7) // 2, 7 774 | // .name() // 1 775 | // This is because FileDescriptorProto.message_type has field number 4: 776 | // repeated DescriptorProto message_type = 4; 777 | // and DescriptorProto.field has field number 2: 778 | // repeated FieldDescriptorProto field = 2; 779 | // and FieldDescriptorProto.name has field number 1: 780 | // optional string name = 1; 781 | // 782 | // Thus, the above path gives the location of a field name. If we removed 783 | // the last element: 784 | // [ 4, 3, 2, 7 ] 785 | // this path refers to the whole field declaration (from the beginning 786 | // of the label to the terminating semicolon). 787 | repeated int32 path = 1 [packed = true]; 788 | 789 | // Always has exactly three or four elements: start line, start column, 790 | // end line (optional, otherwise assumed same as start line), end column. 791 | // These are packed into a single field for efficiency. Note that line 792 | // and column numbers are zero-based -- typically you will want to add 793 | // 1 to each before displaying to a user. 794 | repeated int32 span = 2 [packed = true]; 795 | 796 | // If this SourceCodeInfo represents a complete declaration, these are any 797 | // comments appearing before and after the declaration which appear to be 798 | // attached to the declaration. 799 | // 800 | // A series of line comments appearing on consecutive lines, with no other 801 | // tokens appearing on those lines, will be treated as a single comment. 802 | // 803 | // leading_detached_comments will keep paragraphs of comments that appear 804 | // before (but not connected to) the current element. Each paragraph, 805 | // separated by empty lines, will be one comment element in the repeated 806 | // field. 807 | // 808 | // Only the comment content is provided; comment markers (e.g. //) are 809 | // stripped out. For block comments, leading whitespace and an asterisk 810 | // will be stripped from the beginning of each line other than the first. 811 | // Newlines are included in the output. 812 | // 813 | // Examples: 814 | // 815 | // optional int32 foo = 1; // Comment attached to foo. 816 | // // Comment attached to bar. 817 | // optional int32 bar = 2; 818 | // 819 | // optional string baz = 3; 820 | // // Comment attached to baz. 821 | // // Another line attached to baz. 822 | // 823 | // // Comment attached to qux. 824 | // // 825 | // // Another line attached to qux. 826 | // optional double qux = 4; 827 | // 828 | // // Detached comment for corge. This is not leading or trailing comments 829 | // // to qux or corge because there are blank lines separating it from 830 | // // both. 831 | // 832 | // // Detached comment for corge paragraph 2. 833 | // 834 | // optional string corge = 5; 835 | // /* Block comment attached 836 | // * to corge. Leading asterisks 837 | // * will be removed. */ 838 | // /* Block comment attached to 839 | // * grault. */ 840 | // optional int32 grault = 6; 841 | // 842 | // // ignored detached comments. 843 | optional string leading_comments = 3; 844 | optional string trailing_comments = 4; 845 | repeated string leading_detached_comments = 6; 846 | } 847 | } 848 | 849 | // Describes the relationship between generated code and its original source 850 | // file. A GeneratedCodeInfo message is associated with only one generated 851 | // source file, but may contain references to different source .proto files. 852 | message GeneratedCodeInfo { 853 | // An Annotation connects some span of text in generated code to an element 854 | // of its generating .proto file. 855 | repeated Annotation annotation = 1; 856 | message Annotation { 857 | // Identifies the element in the original source .proto file. This field 858 | // is formatted the same as SourceCodeInfo.Location.path. 859 | repeated int32 path = 1 [packed = true]; 860 | 861 | // Identifies the filesystem path to the original source .proto. 862 | optional string source_file = 2; 863 | 864 | // Identifies the starting offset in bytes in the generated code 865 | // that relates to the identified object. 866 | optional int32 begin = 3; 867 | 868 | // Identifies the ending offset in bytes in the generated code that 869 | // relates to the identified offset. The end offset should be one past 870 | // the last relevant byte (so the length of the text = end - begin). 871 | optional int32 end = 4; 872 | } 873 | } --------------------------------------------------------------------------------