Skip to content

Commit 43486ef

Browse files
committed
Derive the java class name for CelLiteDescriptor
PiperOrigin-RevId: 755424324
1 parent 92dcc34 commit 43486ef

File tree

7 files changed

+164
-93
lines changed

7 files changed

+164
-93
lines changed

java_lite_proto_cel_library.bzl

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,17 @@ load("@com_google_protobuf//bazel:java_lite_proto_library.bzl", "java_lite_proto
1919

2020
def java_lite_proto_cel_library(
2121
name,
22-
java_descriptor_class_name,
2322
proto_src,
23+
java_descriptor_class_name = None,
2424
debug = False):
2525
"""Generates a CelLiteDescriptor
2626
2727
Args:
2828
name: name of this target.
29-
java_descriptor_class_name: Name of the generated descriptor java class.
3029
proto_src: Name of the proto_library target.
30+
java_descriptor_class_name (optional): Java class name for the generated CEL lite descriptor.
31+
By default, CEL will use the first encountered message name in proto_src with "CelLiteDescriptor"
32+
suffixed as the class name. Use this field to override this name.
3133
debug: (optional) If true, prints additional information during codegen for debugging purposes.
3234
"""
3335
java_proto_library_dep = name + "_java_lite_proto_dep"
@@ -37,9 +39,9 @@ def java_lite_proto_cel_library(
3739
)
3840

3941
java_lite_proto_cel_library_impl(
40-
name,
41-
java_descriptor_class_name,
42-
proto_src,
43-
java_proto_library_dep,
44-
debug,
42+
name = name,
43+
proto_src = proto_src,
44+
java_descriptor_class_name = java_descriptor_class_name,
45+
java_proto_library_dep = java_proto_library_dep,
46+
debug = debug,
4547
)

java_lite_proto_cel_library_impl.bzl

Lines changed: 56 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -18,39 +18,39 @@ This is an implementation detail. Clients should use 'java_lite_proto_cel_librar
1818
"""
1919

2020
load("@rules_java//java:defs.bzl", "java_library")
21-
load("@rules_proto//proto:defs.bzl", "proto_descriptor_set")
2221
load("//publish:cel_version.bzl", "CEL_VERSION")
2322
load("@com_google_protobuf//bazel:java_lite_proto_library.bzl", "java_lite_proto_library")
23+
load("@rules_proto//proto:defs.bzl", "ProtoInfo")
2424

2525
def java_lite_proto_cel_library_impl(
2626
name,
27-
java_descriptor_class_name,
2827
proto_src,
2928
java_proto_library_dep,
29+
java_descriptor_class_name = None,
3030
debug = False):
3131
"""Generates a CelLiteDescriptor
3232
3333
Args:
3434
name: name of this target.
35-
java_descriptor_class_name: Name of the generated descriptor java class.
3635
proto_src: Name of the proto_library target.
37-
java_proto_library_dep: (optional) Uses the provided java_lite_proto_library or java_proto_library to generate the lite descriptors. If none is provided, java_lite_proto_library is used by default behind the scenes. Most use cases should not need to provide this.
36+
java_descriptor_class_name (optional): Java class name for the generated CEL lite descriptor.
37+
By default, CEL will use the first encountered message name in proto_src with "CelLiteDescriptor"
38+
suffixed as the class name. Use this field to override this name.
39+
java_proto_library_dep: (optional) Uses the provided java_lite_proto_library or java_proto_library to generate the lite descriptors.
40+
If none is provided, java_lite_proto_library is used by default behind the scenes. Most use cases should not need to provide this.
3841
debug: (optional) If true, prints additional information during codegen for debugging purposes.
3942
"""
4043
if not name:
4144
fail("You must provide a name.")
4245

43-
if not java_descriptor_class_name:
44-
fail("You must provide a descriptor_class_prefix.")
45-
4646
if not proto_src:
4747
fail("You must provide a proto_library dependency.")
4848

49-
_generate_cel_lite_descriptor_class(
50-
name,
51-
java_descriptor_class_name,
52-
proto_src,
53-
debug,
49+
generated = name + "_cel_lite_descriptor"
50+
java_lite_proto_cel_library_rule(
51+
name = generated,
52+
descriptor = proto_src,
53+
java_descriptor_class_name = java_descriptor_class_name,
5454
)
5555

5656
if not java_proto_library_dep:
@@ -67,44 +67,52 @@ def java_lite_proto_cel_library_impl(
6767

6868
java_library(
6969
name = name,
70-
srcs = [":" + name + "_cel_lite_descriptor"],
70+
srcs = [":" + generated],
7171
deps = descriptor_codegen_deps,
7272
)
7373

74-
def _generate_cel_lite_descriptor_class(
75-
name,
76-
descriptor_class_name,
77-
proto_src,
78-
debug):
79-
outfile = "%s.java" % descriptor_class_name
80-
81-
transitive_descriptor_set_name = "%s_transitive_descriptor_set" % name
82-
proto_descriptor_set(
83-
name = transitive_descriptor_set_name,
84-
deps = [proto_src],
74+
def _generate_cel_lite_descriptor_class(ctx):
75+
srcjar_output = ctx.actions.declare_file(ctx.attr.name + ".srcjar")
76+
java_file_path = srcjar_output.path
77+
78+
proto_info = ctx.attr.descriptor[ProtoInfo]
79+
transitive_descriptors = proto_info.transitive_descriptor_sets
80+
81+
args = ctx.actions.args()
82+
args.add("--version", CEL_VERSION)
83+
args.add("--descriptor", proto_info.direct_descriptor_set)
84+
args.add_joined("--transitive_descriptor_set", transitive_descriptors, join_with = ",")
85+
args.add("--out", java_file_path)
86+
87+
if ctx.attr.java_descriptor_class_name:
88+
args.add("--overridden_descriptor_class_name", ctx.attr.java_descriptor_class_name)
89+
if ctx.attr.debug:
90+
args.add("--debug")
91+
92+
ctx.actions.run(
93+
mnemonic = "CelLiteDescriptorGenerator",
94+
arguments = [args],
95+
inputs = transitive_descriptors,
96+
outputs = [srcjar_output],
97+
progress_message = "Generating CelLiteDescriptor for: " + ctx.attr.name,
98+
executable = ctx.executable._tool,
8599
)
86100

87-
direct_descriptor_set_name = proto_src
88-
89-
debug_flag = "--debug" if debug else ""
90-
91-
cmd = (
92-
"$(location //protobuf:cel_lite_descriptor_generator) " +
93-
"--descriptor $(location %s) " % direct_descriptor_set_name +
94-
"--transitive_descriptor_set $(location %s) " % transitive_descriptor_set_name +
95-
"--descriptor_class_name %s " % descriptor_class_name +
96-
"--out $(location %s) " % outfile +
97-
"--version %s " % CEL_VERSION +
98-
debug_flag
99-
)
100-
101-
native.genrule(
102-
name = name + "_cel_lite_descriptor",
103-
srcs = [
104-
transitive_descriptor_set_name,
105-
direct_descriptor_set_name,
106-
],
107-
cmd = cmd,
108-
outs = [outfile],
109-
tools = ["//protobuf:cel_lite_descriptor_generator"],
110-
)
101+
return [DefaultInfo(files = depset([srcjar_output]))]
102+
103+
java_lite_proto_cel_library_rule = rule(
104+
implementation = _generate_cel_lite_descriptor_class,
105+
attrs = {
106+
"java_descriptor_class_name": attr.string(),
107+
"descriptor": attr.label(
108+
providers = [ProtoInfo],
109+
),
110+
"debug": attr.bool(),
111+
"_tool": attr.label(
112+
executable = True,
113+
cfg = "exec",
114+
allow_files = True,
115+
default = Label("//protobuf:cel_lite_descriptor_generator"),
116+
),
117+
},
118+
)

protobuf/src/main/java/dev/cel/protobuf/CelLiteDescriptorGenerator.java

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,17 @@
2525
import dev.cel.protobuf.JavaFileGenerator.JavaFileGeneratorOption;
2626
import java.io.File;
2727
import java.io.IOException;
28+
import java.util.ArrayList;
29+
import java.util.List;
2830
import java.util.concurrent.Callable;
2931
import picocli.CommandLine;
3032
import picocli.CommandLine.Model.OptionSpec;
3133
import picocli.CommandLine.Option;
3234

3335
final class CelLiteDescriptorGenerator implements Callable<Integer> {
3436

37+
private static final String DEFAULT_CEL_LITE_DESCRIPTOR_CLASS_SUFFIX = "CelLiteDescriptor";
38+
3539
@Option(
3640
names = {"--out"},
3741
description = "Outpath for the CelLiteDescriptor")
@@ -46,13 +50,14 @@ final class CelLiteDescriptorGenerator implements Callable<Integer> {
4650

4751
@Option(
4852
names = {"--transitive_descriptor_set"},
53+
split = ",",
4954
description = "Path to the transitive set of descriptors")
50-
private String transitiveDescriptorSetPath = "";
55+
private List<String> transitiveDescriptorSetPath = new ArrayList<>();
5156

5257
@Option(
53-
names = {"--descriptor_class_name"},
54-
description = "Class name for the CelLiteDescriptor")
55-
private String descriptorClassName = "";
58+
names = {"--overridden_descriptor_class_name"},
59+
description = "Java class name for the CelLiteDescriptor")
60+
private String overriddenDescriptorClassName = "";
5661

5762
@Option(
5863
names = {"--version"},
@@ -70,14 +75,13 @@ final class CelLiteDescriptorGenerator implements Callable<Integer> {
7075
public Integer call() throws Exception {
7176
String targetDescriptorProtoPath = extractProtoPath(targetDescriptorPath);
7277
debugPrinter.print("Target descriptor proto path: " + targetDescriptorProtoPath);
78+
FileDescriptorSet transitiveDescriptorSet = combineFileDescriptors(transitiveDescriptorSetPath);
7379

7480
FileDescriptor targetFileDescriptor = null;
7581
ImmutableSet<FileDescriptor> transitiveFileDescriptors =
76-
CelDescriptorUtil.getFileDescriptorsFromFileDescriptorSet(
77-
load(transitiveDescriptorSetPath));
82+
CelDescriptorUtil.getFileDescriptorsFromFileDescriptorSet(transitiveDescriptorSet);
7883
for (FileDescriptor fd : transitiveFileDescriptors) {
7984
if (fd.getFullName().equals(targetDescriptorProtoPath)) {
80-
debugPrinter.print("Transitive Descriptor Path: " + fd.getFullName());
8185
targetFileDescriptor = fd;
8286
break;
8387
}
@@ -97,17 +101,34 @@ public Integer call() throws Exception {
97101

98102
private void codegenCelLiteDescriptor(FileDescriptor targetFileDescriptor) throws Exception {
99103
String javaPackageName = ProtoJavaQualifiedNames.getJavaPackageName(targetFileDescriptor);
104+
String javaClassName = overriddenDescriptorClassName;
105+
if (javaClassName.isEmpty()) {
106+
// Derive the java class name. Use first encountered message/enum in the FDS as a default,
107+
// with a suffix applied for uniqueness (we don't want to collide with java protoc default
108+
// generated class name).
109+
if (!targetFileDescriptor.getMessageTypes().isEmpty()) {
110+
javaClassName = targetFileDescriptor.getMessageTypes().get(0).getName();
111+
} else if (!targetFileDescriptor.getEnumTypes().isEmpty()) {
112+
javaClassName = targetFileDescriptor.getEnumTypes().get(0).getName();
113+
} else {
114+
throw new IllegalArgumentException(
115+
"File descriptor does not contain any messages or enums!");
116+
}
117+
118+
javaClassName += DEFAULT_CEL_LITE_DESCRIPTOR_CLASS_SUFFIX;
119+
}
100120
ProtoDescriptorCollector descriptorCollector =
101121
ProtoDescriptorCollector.newInstance(debugPrinter);
102122

103123
debugPrinter.print(
104-
String.format("Descriptor Java class name: %s.%s", javaPackageName, descriptorClassName));
124+
String.format(
125+
"Fully qualified descriptor java class name: %s.%s", javaPackageName, javaClassName));
105126

106127
JavaFileGenerator.createFile(
107128
outPath,
108129
JavaFileGeneratorOption.newBuilder()
109130
.setVersion(version)
110-
.setDescriptorClassName(descriptorClassName)
131+
.setDescriptorClassName(javaClassName)
111132
.setPackageName(javaPackageName)
112133
.setDescriptorMetadataList(
113134
descriptorCollector.collectCodegenMetadata(targetFileDescriptor))
@@ -127,7 +148,18 @@ private String extractProtoPath(String descriptorPath) {
127148
return fileDescriptorProto.getName();
128149
}
129150

130-
private FileDescriptorSet load(String descriptorSetPath) {
151+
private FileDescriptorSet combineFileDescriptors(List<String> descriptorPaths) {
152+
FileDescriptorSet.Builder combinedDescriptorBuilder = FileDescriptorSet.newBuilder();
153+
154+
for (String descriptorPath : descriptorPaths) {
155+
FileDescriptorSet loadedFds = load(descriptorPath);
156+
combinedDescriptorBuilder.addAllFile(loadedFds.getFileList());
157+
}
158+
159+
return combinedDescriptorBuilder.build();
160+
}
161+
162+
private static FileDescriptorSet load(String descriptorSetPath) {
131163
try {
132164
byte[] descriptorBytes = Files.toByteArray(new File(descriptorSetPath));
133165
return FileDescriptorSet.parseFrom(descriptorBytes, ExtensionRegistry.getEmptyRegistry());

protobuf/src/main/java/dev/cel/protobuf/JavaFileGenerator.java

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,22 @@
1919
import com.google.auto.value.AutoValue;
2020
import com.google.common.collect.ImmutableList;
2121
import com.google.common.collect.ImmutableMap;
22-
import com.google.common.io.Files;
22+
import com.google.common.io.ByteStreams;
2323
// CEL-Internal-5
2424
import freemarker.template.Configuration;
2525
import freemarker.template.DefaultObjectWrapperBuilder;
2626
import freemarker.template.Template;
2727
import freemarker.template.TemplateException;
2828
import freemarker.template.Version;
29-
import java.io.File;
29+
import java.io.ByteArrayInputStream;
30+
import java.io.FileOutputStream;
3031
import java.io.IOException;
32+
import java.io.InputStream;
3133
import java.io.StringWriter;
3234
import java.io.Writer;
35+
import java.util.Locale;
36+
import java.util.zip.ZipEntry;
37+
import java.util.zip.ZipOutputStream;
3338

3439
final class JavaFileGenerator {
3540

@@ -50,10 +55,27 @@ public static void createFile(String filePath, JavaFileGeneratorOption option)
5055

5156
Template template = cfg.getTemplate(HELPER_CLASS_TEMPLATE_FILE);
5257
Writer out = new StringWriter();
53-
5458
template.process(option.getTemplateMap(), out);
5559

56-
Files.asCharSink(new File(filePath), UTF_8).write(out.toString());
60+
writeSrcJar(filePath, option.descriptorClassName(), out.toString());
61+
}
62+
63+
private static void writeSrcJar(
64+
String srcjarFilePath, String javaClassName, String javaClassContent) throws IOException {
65+
if (!srcjarFilePath.toLowerCase(Locale.getDefault()).endsWith(".srcjar")) {
66+
throw new IllegalArgumentException("File must end with .srcjar, provided: " + srcjarFilePath);
67+
}
68+
try (FileOutputStream fos = new FileOutputStream(srcjarFilePath);
69+
ZipOutputStream zos = new ZipOutputStream(fos)) {
70+
ZipEntry entry = new ZipEntry(javaClassName + ".java");
71+
zos.putNextEntry(entry);
72+
73+
try (InputStream inputStream = new ByteArrayInputStream(javaClassContent.getBytes(UTF_8))) {
74+
ByteStreams.copy(inputStream, zos);
75+
}
76+
77+
zos.closeEntry();
78+
}
5779
}
5880

5981
@AutoValue

protobuf/src/test/java/dev/cel/protobuf/CelLiteDescriptorTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import static com.google.common.truth.Truth.assertThat;
1818

1919
import com.google.testing.junit.testparameterinjector.TestParameterInjector;
20-
import dev.cel.expr.conformance.proto3.TestAllTypesProto3LiteCelDescriptor;
20+
import dev.cel.expr.conformance.proto3.TestAllTypesCelLiteDescriptor;
2121
import dev.cel.protobuf.CelLiteDescriptor.FieldLiteDescriptor;
2222
import dev.cel.protobuf.CelLiteDescriptor.FieldLiteDescriptor.EncodingType;
2323
import dev.cel.protobuf.CelLiteDescriptor.FieldLiteDescriptor.JavaType;
@@ -29,8 +29,8 @@
2929
@RunWith(TestParameterInjector.class)
3030
public class CelLiteDescriptorTest {
3131

32-
private static final TestAllTypesProto3LiteCelDescriptor TEST_ALL_TYPES_CEL_LITE_DESCRIPTOR =
33-
TestAllTypesProto3LiteCelDescriptor.getDescriptor();
32+
private static final TestAllTypesCelLiteDescriptor TEST_ALL_TYPES_CEL_LITE_DESCRIPTOR =
33+
TestAllTypesCelLiteDescriptor.getDescriptor();
3434

3535
@Test
3636
public void getProtoTypeNamesToDescriptors_containsAllMessages() {

0 commit comments

Comments
 (0)