Java中未知类型ProtocolBuffer序列化文件反序列化方法咨询
Got it, let's break down how to tackle this problem—this is super common when dealing with legacy Protobuf data or third-party jars that lack clear documentation. Here's a step-by-step approach to deserialize your sample.dat even without knowing the exact message type upfront:
First, you need to uncover the hidden Protobuf message definitions in the compiled .class files:
- Use a Java decompiler like JD-GUI or FernFlower to unpack the jar and decompile classes. Focus on classes that extend
com.google.protobuf.GeneratedMessageV3(orGeneratedMessagefor older Protobuf versions)—these are definitely the compiled Protobuf message classes. - In each decompiled class, look for field number constants (like
public static final int USER_ID_FIELD_NUMBER = 3;) and type hints (e.g.,intmaps to Protobuf'svarint,Stringmaps tolength-delimited). Many classes also retain comments or structure details from the original.protofile. - Run Protobuf's built-in
decode_rawtool to get a raw view of yoursample.datdata. This will show you the field numbers and data types present in the serialized data:
The output will look something like this, giving you a blueprint to match against the decompiled classes:protoc --decode_raw < sample.dat1: varint 2: length-delimited 4: fixed32
Now cross-reference the decode_raw output with the decompiled classes:
- Compare the field numbers and data types from the raw output to the constants and types in each Protobuf class. The class that has a matching set of field numbers and corresponding types is almost certainly your target message type.
- If you have multiple candidates, don’t stress—you can test each one programmatically (more on that next) to find the right fit.
Once you have a candidate class, write a quick Java program to verify:
import com.google.protobuf.GeneratedMessageV3; import java.io.FileInputStream; import java.io.IOException; public class ProtobufDeserializer { public static void main(String[] args) throws Exception { // Replace with the fully qualified name of your candidate class Class<? extends GeneratedMessageV3> messageClass = (Class<? extends GeneratedMessageV3>) Class.forName("com.example.MyTargetMessage"); // Read the sample.dat file into a byte array byte[] data = readFileToBytes("sample.dat"); // Invoke the parseFrom method to deserialize GeneratedMessageV3 message = (GeneratedMessageV3) messageClass .getMethod("parseFrom", byte[].class) .invoke(null, data); // Print the deserialized message to confirm System.out.println("Success! Deserialized message:\n" + message); } private static byte[] readFileToBytes(String filePath) throws IOException { try (FileInputStream fis = new FileInputStream(filePath)) { byte[] buffer = new byte[fis.available()]; fis.read(buffer); return buffer; } } }
Just add the jar to your project's classpath and run this. If it prints a readable message without throwing an exception, you’ve found the right type.
If you want a more automated approach or can’t narrow down the class manually:
- Auto-scan and test: Write a program that scans all classes in the jar that extend
GeneratedMessageV3, then tries to deserializesample.datwith each one. Catch exceptions for mismatched types and stop when you find a class that works. - DynamicMessage: Use Protobuf's
DynamicMessageclass to deserialize without knowing the exact compile-time class. You’ll need to fetch theDescriptorfrom the candidate class (via thegetDescriptor()method) and use it to parse the raw data:import com.google.protobuf.DynamicMessage; import com.google.protobuf.Descriptors; import java.io.FileInputStream; public class DynamicDeserializer { public static void main(String[] args) throws Exception { // Get the descriptor from your candidate class Class<?> protoClass = Class.forName("com.example.MyTargetMessage"); Descriptors.Descriptor descriptor = (Descriptors.Descriptor) protoClass .getMethod("getDescriptor") .invoke(null); // Parse the data using DynamicMessage try (FileInputStream fis = new FileInputStream("sample.dat")) { DynamicMessage message = DynamicMessage.parseFrom(descriptor, fis); System.out.println("Deserialized message:\n" + message); } } }
内容的提问来源于stack exchange,提问作者Santhosh Tpixler

