@@ -55,6 +55,7 @@ public class ResultSetSerializer {
5555
5656 // This is a helper enum to satisfy the type constraints of {@link StructReader#getProtoEnum}.
5757 private static class DummyEnum implements ProtocolMessageEnum {
58+
5859 private final int value ;
5960 private final EnumDescriptor descriptor ;
6061
@@ -110,76 +111,44 @@ private void populateDescriptorMapsRecursively(Descriptor descriptor) {
110111 * useful for handling PROTO or ENUM types that require schema lookup.
111112 *
112113 * @param descriptorSet A set containing one or more .proto file definitions and all their
113- * non-standard dependencies.
114+ * non-standard dependencies. All .proto file must be provided in dependency order.
114115 * @throws IllegalArgumentException if the descriptorSet contains unresolvable dependencies.
115116 */
116117 public ResultSetSerializer (FileDescriptorSet descriptorSet ) throws IllegalArgumentException {
117118 this .messageDescriptorMap = new HashMap <>();
118119 this .enumDescriptorMap = new HashMap <>();
119-
120- // Java's dynamic descriptor loading requires manual dependency resolution.
121- // We must build a DAG and build files only after their dependencies are built.
122- java .util .Map <String , FileDescriptorProto > pendingProtos = new HashMap <>();
123120 java .util .Map <String , FileDescriptor > builtDescriptors = new HashMap <>();
124- for (FileDescriptorProto fileDescriptorProto : descriptorSet .getFileList ()) {
125- pendingProtos .put (fileDescriptorProto .getName (), fileDescriptorProto );
126- }
127-
128- // Keep looping as long as we are making progress.
129- int filesBuiltThisPass ;
130- do {
131- filesBuiltThisPass = 0 ;
132- // Use a copy of the values, to avoid modifying the pendingProtos map while iterating it.
133- List <FileDescriptorProto > protosToBuild = new ArrayList <>(pendingProtos .values ());
134-
135- for (FileDescriptorProto proto : protosToBuild ) {
136- boolean allDependenciesMet = true ;
137- List <FileDescriptor > dependencies = new ArrayList <>();
138121
139- for (String dependencyName : proto .getDependencyList ()) {
140- FileDescriptor dependency = builtDescriptors .get (dependencyName );
141- if (dependency != null ) {
142- // Dependency is already built, add it.
143- dependencies .add (dependency );
144- } else if (pendingProtos .containsKey (dependencyName )) {
145- // Dependency is not yet built, we must wait.
146- allDependenciesMet = false ;
147- break ;
148- } else {
149- // Dependency is not in our set. We assume it's a well-known type (e.g.,
150- // google/protobuf/timestamp.proto) that buildFrom() can find and link automatically.
151- }
122+ for (FileDescriptorProto fileDescriptorProto : descriptorSet .getFileList ()) {
123+ // Collect dependencies. This code require files inside the descriptor set to be sorted
124+ // according to the dependency order.
125+ List <FileDescriptor > dependencies = new ArrayList <>();
126+ for (String dependencyName : fileDescriptorProto .getDependencyList ()) {
127+ FileDescriptor dependency = builtDescriptors .get (dependencyName );
128+ if (dependency != null ) {
129+ // Dependency is already built, add it.
130+ dependencies .add (dependency );
152131 }
132+ // Dependency is not in our set. We assume it's a well-known type (e.g.,
133+ // google/protobuf/timestamp.proto) that buildFrom() can find and link automatically.
134+ }
153135
154- if (allDependenciesMet ) {
155- try {
156- // All dependencies are met, we can build this file.
157- FileDescriptor fileDescriptor =
158- FileDescriptor .buildFrom (proto , dependencies .toArray (new FileDescriptor [0 ]));
159-
160- builtDescriptors .put (fileDescriptor .getName (), fileDescriptor );
161- pendingProtos .remove (proto .getName ());
162- filesBuiltThisPass ++;
163-
164- // Now, populate both message and enum maps with all messages/enums in this file.
165- for (EnumDescriptor enumDescriptor : fileDescriptor .getEnumTypes ()) {
166- enumDescriptorMap .put (enumDescriptor .getFullName (), enumDescriptor );
167- }
168- for (Descriptor messageDescriptor : fileDescriptor .getMessageTypes ()) {
169- populateDescriptorMapsRecursively (messageDescriptor );
170- }
171- } catch (DescriptorValidationException e ) {
172- throw new IllegalArgumentException (
173- "Failed to build descriptor for " + proto .getName (), e );
174- }
136+ try {
137+ FileDescriptor fileDescriptor =
138+ FileDescriptor .buildFrom (
139+ fileDescriptorProto , dependencies .toArray (new FileDescriptor [0 ]));
140+ builtDescriptors .put (fileDescriptor .getName (), fileDescriptor );
141+ // Now, populate both message and enum maps with all messages/enums in this file.
142+ for (EnumDescriptor enumDescriptor : fileDescriptor .getEnumTypes ()) {
143+ enumDescriptorMap .put (enumDescriptor .getFullName (), enumDescriptor );
144+ }
145+ for (Descriptor messageDescriptor : fileDescriptor .getMessageTypes ()) {
146+ populateDescriptorMapsRecursively (messageDescriptor );
175147 }
148+ } catch (DescriptorValidationException e ) {
149+ throw new IllegalArgumentException (
150+ "Failed to build descriptor for " + fileDescriptorProto .getName (), e );
176151 }
177- } while (filesBuiltThisPass > 0 );
178-
179- // Throw if we finished looping but still have pending protos.
180- if (!pendingProtos .isEmpty ()) {
181- throw new IllegalArgumentException (
182- "Unresolvable or circular dependencies found for: " + pendingProtos .keySet ());
183152 }
184153 }
185154
0 commit comments