Skip to content

Commit 2df4df8

Browse files
FHIR Teamcopybara-github
authored andcommitted
Support protobuf editions.
PiperOrigin-RevId: 763844143
1 parent ee5402b commit 2df4df8

File tree

7 files changed

+71
-35
lines changed

7 files changed

+71
-35
lines changed

bazel/protogen.bzl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ def gen_fhir_protos(
7575
package_deps = [],
7676
additional_proto_imports = [],
7777
disable_test = False,
78+
edition = "",
7879
golden_java_proto_rules = []):
7980
"""Generates a proto file from a fhir_package
8081
@@ -119,6 +120,9 @@ def gen_fhir_protos(
119120

120121
flags.append("--directory_in_source " + src_dir)
121122

123+
if edition != "":
124+
flags.append("--edition " + edition)
125+
122126
all_fhir_pkgs = package_deps + [
123127
package,
124128
R4_PACKAGE_DEP,
@@ -178,6 +182,7 @@ def gen_fhir_definitions_and_protos(
178182
additional_proto_imports = [],
179183
disable_test = False,
180184
golden_java_proto_rules = [],
185+
edition = "",
181186
package_json = None):
182187
"""Generates structure definitions and protos based on Extensions and Profiles protos.
183188
@@ -285,6 +290,7 @@ def gen_fhir_definitions_and_protos(
285290
additional_proto_imports = additional_proto_imports,
286291
disable_test = disable_test,
287292
golden_java_proto_rules = golden_java_proto_rules,
293+
edition = edition,
288294
)
289295

290296
def _get_zip_for_pkg(pkg):

java/com/google/fhir/protogen/ProtoFilePrinter.java

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import com.google.fhir.proto.ProtoGeneratorAnnotations;
3030
import com.google.fhir.proto.ProtogenConfig;
3131
import com.google.protobuf.DescriptorProtos.DescriptorProto;
32+
import com.google.protobuf.DescriptorProtos.Edition;
3233
import com.google.protobuf.DescriptorProtos.EnumDescriptorProto;
3334
import com.google.protobuf.DescriptorProtos.EnumOptions;
3435
import com.google.protobuf.DescriptorProtos.EnumValueDescriptorProto;
@@ -50,12 +51,6 @@
5051
/** A utility to turn protocol message descriptors into .proto files. */
5152
public class ProtoFilePrinter {
5253

53-
/** Enum represting the proto Syntax */
54-
public static enum Syntax {
55-
PROTO2,
56-
PROTO3
57-
};
58-
5954
private static final String APACHE_LICENSE =
6055
"// Copyright %1$s Google Inc.\n"
6156
+ "//\n"
@@ -77,8 +72,6 @@ public static enum Syntax {
7772
private final PackageInfo.License license;
7873
private final String licenseDate;
7974

80-
private final Syntax syntax;
81-
8275
// All Message options in this list will appear in this order, before any options not in this
8376
// list. The remainder will be alphabetized.
8477
// This list exists largely to maintain backwards compatibility in ordering.
@@ -105,27 +98,19 @@ public static enum Syntax {
10598

10699
/** Creates a ProtoFilePrinter with default parameters. */
107100
public ProtoFilePrinter(PackageInfo packageInfo) {
108-
this(packageInfo, Syntax.PROTO3);
109-
}
110-
111-
/** Creates a ProtoFilePrinter with default parameters. */
112-
public ProtoFilePrinter(PackageInfo packageInfo, Syntax syntax) {
113101
license = packageInfo.getLicense();
114102
licenseDate = packageInfo.getLicenseDate();
115-
this.syntax = syntax;
116103
}
117104

118105
/** Creates a ProtoFilePrinter with default parameters. */
119106
public ProtoFilePrinter(ProtogenConfig protogenConfig) {
120107
license = PackageInfo.License.APACHE;
121108
licenseDate = protogenConfig.getLicenseDate();
122-
this.syntax = Syntax.PROTO3;
123109
}
124110

125111
public ProtoFilePrinter(String licenseDate) {
126112
license = PackageInfo.License.APACHE;
127113
this.licenseDate = licenseDate;
128-
this.syntax = Syntax.PROTO3;
129114
}
130115

131116
/** Generate a .proto file corresponding to the provided FileDescriptorProto. */
@@ -151,7 +136,17 @@ public String print(FileDescriptorProto fileDescriptor) {
151136
private String printHeader(FileDescriptorProto fileDescriptor) {
152137
StringBuilder header = new StringBuilder();
153138
if (fileDescriptor.hasSyntax()) {
154-
header.append("syntax = \"").append(fileDescriptor.getSyntax()).append("\";\n\n");
139+
if (fileDescriptor.getSyntax().equals("editions")) {
140+
if (fileDescriptor.getEdition().equals(Edition.EDITION_2023)) {
141+
header.append("edition = \"2023\";\n\n");
142+
} else if (fileDescriptor.getEdition().equals(Edition.EDITION_2024)) {
143+
header.append("edition = \"2024\";\n\n");
144+
} else {
145+
header.append("edition = \"unknown\";\n\n");
146+
}
147+
} else {
148+
header.append("syntax = \"").append(fileDescriptor.getSyntax()).append("\";\n\n");
149+
}
155150
}
156151
if (fileDescriptor.hasPackage()) {
157152
header.append("package ").append(fileDescriptor.getPackage()).append(";\n");
@@ -170,6 +165,9 @@ private String printImports(FileDescriptorProto fileDescriptor) {
170165
private String printOptions(FileDescriptorProto fileDescriptor, String packageName) {
171166
StringBuilder options = new StringBuilder();
172167
FileOptions fileOptions = fileDescriptor.getOptions();
168+
if (fileDescriptor.getSyntax().equals("editions")) {
169+
options.append("option features.field_presence = IMPLICIT;\n");
170+
}
173171
if (fileOptions.hasJavaMultipleFiles()) {
174172
options
175173
.append("option java_multiple_files = ")
@@ -279,7 +277,7 @@ private String printMessage(DescriptorProto descriptor, String typePrefix, Strin
279277
descriptor, field, typePrefix, packageName, printedNestedTypeDefinitions));
280278
message.append(
281279
printField(
282-
fieldBuilder.build(), fullName, fieldIndent, packageName, /* inOneof= */ false));
280+
fieldBuilder.build(), fullName, fieldIndent, packageName));
283281
if (i != descriptor.getFieldCount() - 1) {
284282
message.append("\n");
285283
}
@@ -327,7 +325,7 @@ private String printMessage(DescriptorProto descriptor, String typePrefix, Strin
327325
}
328326
message.append(
329327
printField(
330-
fieldBuilder.build(), fullName, oneofIndent, packageName, /* inOneof= */ true));
328+
fieldBuilder.build(), fullName, oneofIndent, packageName));
331329
// If this oneof field had a description, and is not the last field, add a newline after.
332330
if (field.getOptions().hasExtension(ProtoGeneratorAnnotations.fieldDescription)
333331
&& i != descriptor.getFieldCount() - 1) {
@@ -441,20 +439,14 @@ private String printField(
441439
FieldDescriptorProto field,
442440
String containingType,
443441
String indent,
444-
String packageName,
445-
boolean inOneof) {
442+
String packageName) {
446443
StringBuilder message = new StringBuilder();
447444
message.append(indent);
448445

449-
// Add the "repeated" or "optional" keywords, if necessary.
446+
// Add the "repeated" keyword, if necessary.
450447
if (field.getLabel() == FieldDescriptorProto.Label.LABEL_REPEATED) {
451448
message.append("repeated ");
452449
}
453-
if (!inOneof
454-
&& field.getLabel() == FieldDescriptorProto.Label.LABEL_OPTIONAL
455-
&& syntax == Syntax.PROTO2) {
456-
message.append("optional ");
457-
}
458450

459451
// Add the type of the field.
460452
if ((field.getType() == FieldDescriptorProto.Type.TYPE_MESSAGE

java/com/google/fhir/protogen/ProtoGenerator.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
import com.google.fhir.r4.core.StructureDefinitionKindCode;
6060
import com.google.fhir.r4.core.TypeDerivationRuleCode;
6161
import com.google.protobuf.DescriptorProtos.DescriptorProto;
62+
import com.google.protobuf.DescriptorProtos.Edition;
6263
import com.google.protobuf.DescriptorProtos.EnumDescriptorProto;
6364
import com.google.protobuf.DescriptorProtos.EnumValueDescriptorProto;
6465
import com.google.protobuf.DescriptorProtos.FieldDescriptorProto;
@@ -214,6 +215,8 @@ public class ProtoGenerator {
214215

215216
private final ImmutableMap<String, Set<String>> coreTypeDefinitionsByFile;
216217

218+
private final String edition;
219+
217220
private static Set<String> getTypesDefinedInFile(FileDescriptor file) {
218221
return file.getMessageTypes().stream()
219222
.flatMap(desc -> getTypesDefinedInType(desc).stream())
@@ -261,19 +264,21 @@ private static class StructureDefinitionData {
261264
public ProtoGenerator(
262265
PackageInfo packageInfo, String codesProtoImport, Set<FhirPackage> fhirPackages)
263266
throws InvalidFhirException {
264-
this(packageInfo, codesProtoImport, fhirPackages, null);
267+
this(packageInfo, codesProtoImport, fhirPackages, null, "");
265268
}
266269

267270
public ProtoGenerator(
268271
PackageInfo packageInfo,
269272
String codesProtoImport,
270273
Set<FhirPackage> fhirPackages,
271-
ValueSetGenerator valueSetGenerator)
274+
ValueSetGenerator valueSetGenerator,
275+
String edition)
272276
throws InvalidFhirException {
273277
this.packageInfo = packageInfo;
274278
this.codesProtoImport = codesProtoImport;
275279
this.fhirVersion = FhirVersion.fromAnnotation(packageInfo.getFhirVersion());
276280
this.valueSetGenerator = valueSetGenerator;
281+
this.edition = edition;
277282

278283
ImmutableMap.Builder<String, Set<String>> coreTypeBuilder = new ImmutableMap.Builder<>();
279284
for (Map.Entry<String, FileDescriptor> entry : fhirVersion.coreTypeMap.entrySet()) {
@@ -1834,7 +1839,16 @@ public FileDescriptorProto generateFileDescriptor(List<StructureDefinition> defs
18341839
public FileDescriptorProto generateFileDescriptor(
18351840
List<StructureDefinition> defs, List<String> additionalImports) throws InvalidFhirException {
18361841
FileDescriptorProto.Builder builder = FileDescriptorProto.newBuilder();
1837-
builder.setPackage(packageInfo.getProtoPackage()).setSyntax("proto3");
1842+
builder.setPackage(packageInfo.getProtoPackage());
1843+
if (this.edition.equals("2023")) {
1844+
builder.setSyntax("editions");
1845+
builder.setEdition(Edition.EDITION_2023);
1846+
} else if (this.edition.equals("2024")) {
1847+
builder.setSyntax("editions");
1848+
builder.setEdition(Edition.EDITION_2024);
1849+
} else {
1850+
builder.setSyntax("proto3");
1851+
}
18381852
FileOptions.Builder options = FileOptions.newBuilder();
18391853
if (!packageInfo.getJavaProtoPackage().isEmpty()) {
18401854
options.setJavaPackage(packageInfo.getJavaProtoPackage()).setJavaMultipleFiles(true);

java/com/google/fhir/protogen/ProtoGeneratorMain.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,11 @@ private static class Args {
109109
+ " will output ${output_name}_extensions.proto.")
110110
private String outputName = "output";
111111

112+
@Parameter(
113+
names = {"--edition"},
114+
description = "proto edition")
115+
private String edition = "";
116+
112117
@Parameter(
113118
names = {"--input_package"},
114119
description = "Input FHIR package",
@@ -160,13 +165,15 @@ void run() throws IOException, InvalidFhirException {
160165
// Generate the proto file.
161166
System.out.println("Generating proto descriptors...");
162167

163-
ValueSetGenerator valueSetGenerator = new ValueSetGenerator(packageInfo, fhirPackages);
168+
ValueSetGenerator valueSetGenerator =
169+
new ValueSetGenerator(packageInfo, fhirPackages, args.edition);
164170
ProtoGenerator generator =
165171
new ProtoGenerator(
166172
packageInfo,
167173
args.directoryInSource + "/" + args.outputName + "_codes.proto",
168174
fhirPackages,
169-
valueSetGenerator);
175+
valueSetGenerator,
176+
args.edition);
170177
ProtoFilePrinter printer = new ProtoFilePrinter(packageInfo);
171178

172179
try (ZipOutputStream zipOutputStream =

java/com/google/fhir/protogen/ValueSetGenerator.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import com.google.fhir.r4.core.ValueSet;
4141
import com.google.fhir.r4.core.ValueSet.Compose.ConceptSet.Filter;
4242
import com.google.protobuf.DescriptorProtos.DescriptorProto;
43+
import com.google.protobuf.DescriptorProtos.Edition;
4344
import com.google.protobuf.DescriptorProtos.EnumDescriptorProto;
4445
import com.google.protobuf.DescriptorProtos.EnumValueDescriptorProto;
4546
import com.google.protobuf.DescriptorProtos.FieldDescriptorProto;
@@ -67,9 +68,11 @@ public class ValueSetGenerator {
6768
private final Map<String, CodeSystem> codeSystemsByUrl;
6869
private final Map<String, ValueSet> valueSetsByUrl;
6970
private final Map<String, String> protoTypesByUrl;
71+
private final String edition;
7072

71-
public ValueSetGenerator(PackageInfo packageInfo, Set<FhirPackage> fhirPackages) {
73+
public ValueSetGenerator(PackageInfo packageInfo, Set<FhirPackage> fhirPackages, String edition) {
7274
this.packageInfo = packageInfo;
75+
this.edition = edition;
7376
this.fhirVersion = FhirVersion.fromAnnotation(packageInfo.getFhirVersion());
7477

7578
this.codeSystemsByUrl =
@@ -161,7 +164,16 @@ public FileDescriptorProto generateCodeSystemFile(FhirPackage fhirPackage) {
161164

162165
private FileDescriptorProto generateCodeSystemFile(Collection<CodeSystem> codeSystemsToGenerate) {
163166
FileDescriptorProto.Builder builder = FileDescriptorProto.newBuilder();
164-
builder.setPackage(packageInfo.getProtoPackage()).setSyntax("proto3");
167+
builder.setPackage(packageInfo.getProtoPackage());
168+
if (this.edition.equals("2023")) {
169+
builder.setSyntax("editions");
170+
builder.setEdition(Edition.EDITION_2023);
171+
} else if (this.edition.equals("2024")) {
172+
builder.setSyntax("editions");
173+
builder.setEdition(Edition.EDITION_2024);
174+
} else {
175+
builder.setSyntax("proto3");
176+
}
165177
builder.addDependency(new File(GeneratorUtils.ANNOTATION_PATH, "annotations.proto").toString());
166178
FileOptions.Builder options = FileOptions.newBuilder();
167179
if (!packageInfo.getJavaProtoPackage().isEmpty()) {

javatests/com/google/fhir/protogen/GeneratedProtoTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ public void testGeneratedProto() throws Exception {
6666
}
6767

6868
for (String filename : generatedContentsByFilename.keySet()) {
69+
if (filename.startsWith(".")) {
70+
continue;
71+
}
72+
System.out.println("testing " + filename);
6973
assertThat(goldenContentsByFilename).containsKey(filename);
7074
assertThat(cleanProtoFile(generatedContentsByFilename.get(filename)))
7175
.isEqualTo(cleanProtoFile(goldenContentsByFilename.get(filename)));

javatests/com/google/fhir/protogen/ProtoGeneratorTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ private static ProtoGenerator makeProtoGenerator(
7979
packageInfo,
8080
codesProtoImport,
8181
ImmutableSet.copyOf(packages),
82-
new ValueSetGenerator(packageInfo, packages));
82+
new ValueSetGenerator(packageInfo, packages, "2023"),
83+
"2023");
8384
}
8485

8586
public ProtoGeneratorTest() throws Exception {

0 commit comments

Comments
 (0)