Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions bazel/protogen.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ def gen_fhir_protos(
package_deps = [],
additional_proto_imports = [],
disable_test = False,
edition = "",
golden_java_proto_rules = []):
"""Generates a proto file from a fhir_package

Expand Down Expand Up @@ -119,6 +120,9 @@ def gen_fhir_protos(

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

if edition != "":
flags.append("--edition " + edition)

all_fhir_pkgs = package_deps + [
package,
R4_PACKAGE_DEP,
Expand Down Expand Up @@ -178,6 +182,7 @@ def gen_fhir_definitions_and_protos(
additional_proto_imports = [],
disable_test = False,
golden_java_proto_rules = [],
edition = "",
package_json = None):
"""Generates structure definitions and protos based on Extensions and Profiles protos.

Expand Down Expand Up @@ -285,6 +290,7 @@ def gen_fhir_definitions_and_protos(
additional_proto_imports = additional_proto_imports,
disable_test = disable_test,
golden_java_proto_rules = golden_java_proto_rules,
edition = edition,
)

def _get_zip_for_pkg(pkg):
Expand Down
44 changes: 17 additions & 27 deletions java/com/google/fhir/protogen/ProtoFilePrinter.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.google.fhir.proto.ProtoGeneratorAnnotations;
import com.google.fhir.proto.ProtogenConfig;
import com.google.protobuf.DescriptorProtos.DescriptorProto;
import com.google.protobuf.DescriptorProtos.Edition;
import com.google.protobuf.DescriptorProtos.EnumDescriptorProto;
import com.google.protobuf.DescriptorProtos.EnumOptions;
import com.google.protobuf.DescriptorProtos.EnumValueDescriptorProto;
Expand All @@ -50,12 +51,6 @@
/** A utility to turn protocol message descriptors into .proto files. */
public class ProtoFilePrinter {

/** Enum represting the proto Syntax */
public static enum Syntax {
PROTO2,
PROTO3
};

private static final String APACHE_LICENSE =
"// Copyright %1$s Google Inc.\n"
+ "//\n"
Expand All @@ -77,8 +72,6 @@ public static enum Syntax {
private final PackageInfo.License license;
private final String licenseDate;

private final Syntax syntax;

// All Message options in this list will appear in this order, before any options not in this
// list. The remainder will be alphabetized.
// This list exists largely to maintain backwards compatibility in ordering.
Expand All @@ -105,27 +98,19 @@ public static enum Syntax {

/** Creates a ProtoFilePrinter with default parameters. */
public ProtoFilePrinter(PackageInfo packageInfo) {
this(packageInfo, Syntax.PROTO3);
}

/** Creates a ProtoFilePrinter with default parameters. */
public ProtoFilePrinter(PackageInfo packageInfo, Syntax syntax) {
license = packageInfo.getLicense();
licenseDate = packageInfo.getLicenseDate();
this.syntax = syntax;
}

/** Creates a ProtoFilePrinter with default parameters. */
public ProtoFilePrinter(ProtogenConfig protogenConfig) {
license = PackageInfo.License.APACHE;
licenseDate = protogenConfig.getLicenseDate();
this.syntax = Syntax.PROTO3;
}

public ProtoFilePrinter(String licenseDate) {
license = PackageInfo.License.APACHE;
this.licenseDate = licenseDate;
this.syntax = Syntax.PROTO3;
}

/** Generate a .proto file corresponding to the provided FileDescriptorProto. */
Expand All @@ -151,7 +136,15 @@ public String print(FileDescriptorProto fileDescriptor) {
private String printHeader(FileDescriptorProto fileDescriptor) {
StringBuilder header = new StringBuilder();
if (fileDescriptor.hasSyntax()) {
header.append("syntax = \"").append(fileDescriptor.getSyntax()).append("\";\n\n");
if (fileDescriptor.getSyntax().equals("editions")) {
if (fileDescriptor.getEdition().equals(Edition.EDITION_2023)) {
header.append("edition = \"2023\";\n\n");
} else {
header.append("edition = \"unknown\";\n\n");
}
} else {
header.append("syntax = \"").append(fileDescriptor.getSyntax()).append("\";\n\n");
}
}
if (fileDescriptor.hasPackage()) {
header.append("package ").append(fileDescriptor.getPackage()).append(";\n");
Expand All @@ -170,6 +163,9 @@ private String printImports(FileDescriptorProto fileDescriptor) {
private String printOptions(FileDescriptorProto fileDescriptor, String packageName) {
StringBuilder options = new StringBuilder();
FileOptions fileOptions = fileDescriptor.getOptions();
if (fileDescriptor.getSyntax().equals("editions")) {
options.append("option features.field_presence = IMPLICIT;\n");
}
if (fileOptions.hasJavaMultipleFiles()) {
options
.append("option java_multiple_files = ")
Expand Down Expand Up @@ -279,7 +275,7 @@ private String printMessage(DescriptorProto descriptor, String typePrefix, Strin
descriptor, field, typePrefix, packageName, printedNestedTypeDefinitions));
message.append(
printField(
fieldBuilder.build(), fullName, fieldIndent, packageName, /* inOneof= */ false));
fieldBuilder.build(), fullName, fieldIndent, packageName));
if (i != descriptor.getFieldCount() - 1) {
message.append("\n");
}
Expand Down Expand Up @@ -327,7 +323,7 @@ private String printMessage(DescriptorProto descriptor, String typePrefix, Strin
}
message.append(
printField(
fieldBuilder.build(), fullName, oneofIndent, packageName, /* inOneof= */ true));
fieldBuilder.build(), fullName, oneofIndent, packageName));
// If this oneof field had a description, and is not the last field, add a newline after.
if (field.getOptions().hasExtension(ProtoGeneratorAnnotations.fieldDescription)
&& i != descriptor.getFieldCount() - 1) {
Expand Down Expand Up @@ -441,20 +437,14 @@ private String printField(
FieldDescriptorProto field,
String containingType,
String indent,
String packageName,
boolean inOneof) {
String packageName) {
StringBuilder message = new StringBuilder();
message.append(indent);

// Add the "repeated" or "optional" keywords, if necessary.
// Add the "repeated" keyword, if necessary.
if (field.getLabel() == FieldDescriptorProto.Label.LABEL_REPEATED) {
message.append("repeated ");
}
if (!inOneof
&& field.getLabel() == FieldDescriptorProto.Label.LABEL_OPTIONAL
&& syntax == Syntax.PROTO2) {
message.append("optional ");
}

// Add the type of the field.
if ((field.getType() == FieldDescriptorProto.Type.TYPE_MESSAGE
Expand Down
17 changes: 14 additions & 3 deletions java/com/google/fhir/protogen/ProtoGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
import com.google.fhir.r4.core.StructureDefinitionKindCode;
import com.google.fhir.r4.core.TypeDerivationRuleCode;
import com.google.protobuf.DescriptorProtos.DescriptorProto;
import com.google.protobuf.DescriptorProtos.Edition;
import com.google.protobuf.DescriptorProtos.EnumDescriptorProto;
import com.google.protobuf.DescriptorProtos.EnumValueDescriptorProto;
import com.google.protobuf.DescriptorProtos.FieldDescriptorProto;
Expand Down Expand Up @@ -214,6 +215,8 @@ public class ProtoGenerator {

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

private final String edition;

private static Set<String> getTypesDefinedInFile(FileDescriptor file) {
return file.getMessageTypes().stream()
.flatMap(desc -> getTypesDefinedInType(desc).stream())
Expand Down Expand Up @@ -261,19 +264,21 @@ private static class StructureDefinitionData {
public ProtoGenerator(
PackageInfo packageInfo, String codesProtoImport, Set<FhirPackage> fhirPackages)
throws InvalidFhirException {
this(packageInfo, codesProtoImport, fhirPackages, null);
this(packageInfo, codesProtoImport, fhirPackages, null, "");
}

public ProtoGenerator(
PackageInfo packageInfo,
String codesProtoImport,
Set<FhirPackage> fhirPackages,
ValueSetGenerator valueSetGenerator)
ValueSetGenerator valueSetGenerator,
String edition)
throws InvalidFhirException {
this.packageInfo = packageInfo;
this.codesProtoImport = codesProtoImport;
this.fhirVersion = FhirVersion.fromAnnotation(packageInfo.getFhirVersion());
this.valueSetGenerator = valueSetGenerator;
this.edition = edition;

ImmutableMap.Builder<String, Set<String>> coreTypeBuilder = new ImmutableMap.Builder<>();
for (Map.Entry<String, FileDescriptor> entry : fhirVersion.coreTypeMap.entrySet()) {
Expand Down Expand Up @@ -1834,7 +1839,13 @@ public FileDescriptorProto generateFileDescriptor(List<StructureDefinition> defs
public FileDescriptorProto generateFileDescriptor(
List<StructureDefinition> defs, List<String> additionalImports) throws InvalidFhirException {
FileDescriptorProto.Builder builder = FileDescriptorProto.newBuilder();
builder.setPackage(packageInfo.getProtoPackage()).setSyntax("proto3");
builder.setPackage(packageInfo.getProtoPackage());
if (this.edition.equals("2023")) {
builder.setSyntax("editions");
builder.setEdition(Edition.EDITION_2023);
} else {
builder.setSyntax("proto3");
}
FileOptions.Builder options = FileOptions.newBuilder();
if (!packageInfo.getJavaProtoPackage().isEmpty()) {
options.setJavaPackage(packageInfo.getJavaProtoPackage()).setJavaMultipleFiles(true);
Expand Down
11 changes: 9 additions & 2 deletions java/com/google/fhir/protogen/ProtoGeneratorMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ private static class Args {
+ " will output ${output_name}_extensions.proto.")
private String outputName = "output";

@Parameter(
names = {"--edition"},
description = "proto edition")
private String edition = "";

@Parameter(
names = {"--input_package"},
description = "Input FHIR package",
Expand Down Expand Up @@ -160,13 +165,15 @@ void run() throws IOException, InvalidFhirException {
// Generate the proto file.
System.out.println("Generating proto descriptors...");

ValueSetGenerator valueSetGenerator = new ValueSetGenerator(packageInfo, fhirPackages);
ValueSetGenerator valueSetGenerator =
new ValueSetGenerator(packageInfo, fhirPackages, args.edition);
ProtoGenerator generator =
new ProtoGenerator(
packageInfo,
args.directoryInSource + "/" + args.outputName + "_codes.proto",
fhirPackages,
valueSetGenerator);
valueSetGenerator,
args.edition);
ProtoFilePrinter printer = new ProtoFilePrinter(packageInfo);

try (ZipOutputStream zipOutputStream =
Expand Down
13 changes: 11 additions & 2 deletions java/com/google/fhir/protogen/ValueSetGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import com.google.fhir.r4.core.ValueSet;
import com.google.fhir.r4.core.ValueSet.Compose.ConceptSet.Filter;
import com.google.protobuf.DescriptorProtos.DescriptorProto;
import com.google.protobuf.DescriptorProtos.Edition;
import com.google.protobuf.DescriptorProtos.EnumDescriptorProto;
import com.google.protobuf.DescriptorProtos.EnumValueDescriptorProto;
import com.google.protobuf.DescriptorProtos.FieldDescriptorProto;
Expand Down Expand Up @@ -67,9 +68,11 @@ public class ValueSetGenerator {
private final Map<String, CodeSystem> codeSystemsByUrl;
private final Map<String, ValueSet> valueSetsByUrl;
private final Map<String, String> protoTypesByUrl;
private final String edition;

public ValueSetGenerator(PackageInfo packageInfo, Set<FhirPackage> fhirPackages) {
public ValueSetGenerator(PackageInfo packageInfo, Set<FhirPackage> fhirPackages, String edition) {
this.packageInfo = packageInfo;
this.edition = edition;
this.fhirVersion = FhirVersion.fromAnnotation(packageInfo.getFhirVersion());

this.codeSystemsByUrl =
Expand Down Expand Up @@ -161,7 +164,13 @@ public FileDescriptorProto generateCodeSystemFile(FhirPackage fhirPackage) {

private FileDescriptorProto generateCodeSystemFile(Collection<CodeSystem> codeSystemsToGenerate) {
FileDescriptorProto.Builder builder = FileDescriptorProto.newBuilder();
builder.setPackage(packageInfo.getProtoPackage()).setSyntax("proto3");
builder.setPackage(packageInfo.getProtoPackage());
if (this.edition.equals("2023")) {
builder.setSyntax("editions");
builder.setEdition(Edition.EDITION_2023);
} else {
builder.setSyntax("proto3");
}
builder.addDependency(new File(GeneratorUtils.ANNOTATION_PATH, "annotations.proto").toString());
FileOptions.Builder options = FileOptions.newBuilder();
if (!packageInfo.getJavaProtoPackage().isEmpty()) {
Expand Down
3 changes: 3 additions & 0 deletions javatests/com/google/fhir/protogen/GeneratedProtoTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ public void testGeneratedProto() throws Exception {
}

for (String filename : generatedContentsByFilename.keySet()) {
if (filename.startsWith(".")) {
continue;
}
assertThat(goldenContentsByFilename).containsKey(filename);
assertThat(cleanProtoFile(generatedContentsByFilename.get(filename)))
.isEqualTo(cleanProtoFile(goldenContentsByFilename.get(filename)));
Expand Down
3 changes: 2 additions & 1 deletion javatests/com/google/fhir/protogen/ProtoGeneratorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ private static ProtoGenerator makeProtoGenerator(
packageInfo,
codesProtoImport,
ImmutableSet.copyOf(packages),
new ValueSetGenerator(packageInfo, packages));
new ValueSetGenerator(packageInfo, packages, "2023"),
"2023");
}

public ProtoGeneratorTest() throws Exception {
Expand Down