2323import io .opentelemetry .javaagent .instrumentation .hypertrace .com .google .protobuf .Descriptors .FileDescriptor ;
2424import io .opentelemetry .javaagent .instrumentation .hypertrace .com .google .protobuf .DynamicMessage ;
2525import io .opentelemetry .javaagent .instrumentation .hypertrace .com .google .protobuf .util .JsonFormat ;
26+ import java .util .ArrayList ;
27+ import java .util .HashMap ;
28+ import java .util .List ;
29+ import java .util .Map ;
2630import org .slf4j .Logger ;
2731import org .slf4j .LoggerFactory ;
2832
2933public class ProtobufMessageConverter {
3034 private static final Logger log = LoggerFactory .getLogger (ProtobufMessageConverter .class );
35+ private static final Map <String , FileDescriptor > fileDescriptorCache = new HashMap <>();
36+
3137 /**
3238 * Converts an unrelocated protobuf message into a relocated DynamicMessage via a byte-array
3339 * round-trip.
@@ -43,31 +49,64 @@ public static DynamicMessage convertToRelocatedDynamicMessage(Message message) t
4349 // 2. Obtain the original (unrelocated) message descriptor.
4450 Descriptors .Descriptor originalDescriptor = message .getDescriptorForType ();
4551
46- // 3. Get the unrelocated file descriptor and its proto representation.
52+ // 3. Build the relocated descriptor with all dependencies
53+ Descriptor relocatedDescriptor = getRelocatedDescriptor (originalDescriptor );
54+ if (relocatedDescriptor == null ) {
55+ throw new IllegalStateException (
56+ "Could not find relocated descriptor for message type: "
57+ + originalDescriptor .getFullName ());
58+ }
59+
60+ // 4. Parse the original message bytes using the relocated descriptor.
61+ try {
62+ return DynamicMessage .parseFrom (relocatedDescriptor , messageBytes );
63+ } catch (Exception e ) {
64+ log .debug ("Failed to parse message bytes using relocated descriptor: {}" , e .getMessage ());
65+ throw e ;
66+ }
67+ }
68+
69+ /** Recursively builds relocated file descriptors with all dependencies. */
70+ private static Descriptor getRelocatedDescriptor (Descriptors .Descriptor originalDescriptor )
71+ throws Exception {
4772 Descriptors .FileDescriptor unrelocatedFileDescriptor = originalDescriptor .getFile ();
73+
74+ // Check if we've already processed this file descriptor
75+ String fileKey = unrelocatedFileDescriptor .getName ();
76+ if (fileDescriptorCache .containsKey (fileKey )) {
77+ FileDescriptor relocatedFileDescriptor = fileDescriptorCache .get (fileKey );
78+ return relocatedFileDescriptor .findMessageTypeByName (originalDescriptor .getName ());
79+ }
80+
81+ // Process all dependencies first
82+ List <FileDescriptor > dependencies = new ArrayList <>();
83+ for (Descriptors .FileDescriptor dependency : unrelocatedFileDescriptor .getDependencies ()) {
84+ String depKey = dependency .getName ();
85+ if (!fileDescriptorCache .containsKey (depKey )) {
86+ // Convert the dependency file descriptor
87+ com .google .protobuf .DescriptorProtos .FileDescriptorProto depProto = dependency .toProto ();
88+ byte [] depBytes = depProto .toByteArray ();
89+ FileDescriptorProto relocatedDepProto = FileDescriptorProto .parseFrom (depBytes );
90+
91+ // Build with empty dependencies first (we'll fill them in later)
92+ FileDescriptor relocatedDep =
93+ FileDescriptor .buildFrom (relocatedDepProto , new FileDescriptor [] {});
94+ fileDescriptorCache .put (depKey , relocatedDep );
95+ }
96+ dependencies .add (fileDescriptorCache .get (depKey ));
97+ }
98+
99+ // Now build the current file descriptor with its dependencies
48100 com .google .protobuf .DescriptorProtos .FileDescriptorProto unrelocatedFileProto =
49101 unrelocatedFileDescriptor .toProto ();
50102 byte [] fileProtoBytes = unrelocatedFileProto .toByteArray ();
51-
52- // 4. Parse the file descriptor proto using relocated classes.
53- // This converts the unrelocated FileDescriptorProto into your relocated FileDescriptorProto.
54103 FileDescriptorProto relocatedFileProto = FileDescriptorProto .parseFrom (fileProtoBytes );
55104
56- // 5. Build the relocated FileDescriptor.
57105 FileDescriptor relocatedFileDescriptor =
58- FileDescriptor .buildFrom (relocatedFileProto , new FileDescriptor [] {});
59-
60- // 6. Find the relocated message descriptor by name.
61- Descriptor relocatedDescriptor =
62- relocatedFileDescriptor .findMessageTypeByName (originalDescriptor .getName ());
63- if (relocatedDescriptor == null ) {
64- throw new IllegalStateException (
65- "Could not find relocated descriptor for message type: " + originalDescriptor .getName ());
66- }
106+ FileDescriptor .buildFrom (relocatedFileProto , dependencies .toArray (new FileDescriptor [0 ]));
107+ fileDescriptorCache .put (fileKey , relocatedFileDescriptor );
67108
68- // 7. Parse the original message bytes using the relocated descriptor.
69- DynamicMessage relocatedMessage = DynamicMessage .parseFrom (relocatedDescriptor , messageBytes );
70- return relocatedMessage ;
109+ return relocatedFileDescriptor .findMessageTypeByName (originalDescriptor .getName ());
71110 }
72111
73112 /**
@@ -77,17 +116,25 @@ public static DynamicMessage convertToRelocatedDynamicMessage(Message message) t
77116 * @param message The incoming (unrelocated) protobuf message.
78117 */
79118 public static String getMessage (Message message ) {
119+ if (message == null ) {
120+ log .debug ("Cannot convert null message to JSON" );
121+ return "" ;
122+ }
123+
80124 try {
81125 // Convert the unrelocated message into a relocated DynamicMessage.
82126 DynamicMessage relocatedMessage = convertToRelocatedDynamicMessage (message );
83127
84128 // Use the relocated JsonFormat to print the message as JSON.
85- JsonFormat .Printer relocatedPrinter = JsonFormat .printer ();
86- String jsonOutput = relocatedPrinter .print (relocatedMessage );
87-
88- return jsonOutput ;
129+ JsonFormat .Printer relocatedPrinter =
130+ JsonFormat .printer ().includingDefaultValueFields ().preservingProtoFieldNames ();
131+ return relocatedPrinter .print (relocatedMessage );
89132 } catch (Exception e ) {
90- log .error ("Failed to convert message with relocated protobuf message: {}" , e .getMessage ());
133+ log .error ("Failed to convert message to JSON: {}" , e .getMessage (), e );
134+ if (log .isDebugEnabled ()) {
135+ log .debug ("Message type: {}" , message .getClass ().getName ());
136+ log .debug ("Message descriptor: {}" , message .getDescriptorForType ().getFullName ());
137+ }
91138 }
92139 return "" ;
93140 }
0 commit comments