What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
You can generate a Protobuf message without knowing its type at compile time by loading its descriptor, creating a dynamic message, and walking its fields through the runtime’s reflection API. But descriptors describe structure, not plausible business data. A useful generator pairs that schema traversal with explicit policies for values, recursion, collection sizes, and application rules.
What a descriptor gives you—and what it does not
A Protobuf descriptor describes a message’s schema: its fields, declared types, and options. The official documentation puts the boundary plainly: “Protocol Buffers do not contain descriptions of their own types.” (Protocol Buffers Documentation: Self-describing Messages) A descriptor lets a runtime discover how a message is shaped; it does not provide the message’s own type definition as embedded data or tell a generator what realistic values mean.
For example, a descriptor can tell you that a field is a string. It cannot, by itself, say whether that string should look like an email address, customer identifier, URL, or sentence. Nor does it define realistic value distributions, relationships between fields, sensitive-data rules, or which combination of fields represents a valid business state. Those are generator policies, fixtures, or application-specific annotations—not generic Protobuf defaults.
Custom options or external annotations can carry some of that intent, but their definitions and consumers must be available. Their presence is not guaranteed. A descriptor set also cannot reveal schema definitions that were never included.
#1 Best Overall
How runtime generation works
Protobuf’s self-describing-message approach combines a serialized FileDescriptorSet with a dynamic message implementation. The descriptor set must include the files needed to resolve imported and referenced types. The runtime resolves the fully qualified root message name in a descriptor pool, then creates a message from that descriptor. The official guide notes that this technique requires dynamic-message support and that support depends on the platform (Self-describing Messages).
This differs from using generated classes: generated code knows message types at compile time, while a dynamic message represents a type discovered at runtime. In C++, DynamicMessageFactory builds prototypes from descriptors; the descriptors used with a factory must outlive it (C++ DynamicMessage API). Java provides DynamicMessage for arbitrary types represented by a Descriptors.Descriptor (Java DynamicMessage API). Check the documentation for the language and runtime you deploy rather than assuming identical APIs or support across platforms.
A practical generator design
- Load a complete schema. Obtain a
FileDescriptorSetcontaining the root message’s file and the dependencies needed to resolve its referenced types. Build or populate a descriptor pool, then look up the requested fully qualified message name. Handle a missing file, unresolved dependency, or unknown message name as a schema-loading error rather than silently generating an incomplete object. - Create a dynamic message. Use the language’s runtime API with the resolved message descriptor. Keep descriptor-pool, descriptor, factory, and generated-prototype lifetimes coherent; in C++, descriptors used by
DynamicMessageFactorymust remain alive for the factory’s lifetime. - Walk fields using reflection. For each field descriptor, dispatch according to the declared type and use the runtime’s dynamic field operations. Reflection APIs differ by language. In C++, a field descriptor passed to reflection must belong to the message’s type; using an unrelated descriptor is invalid (C++ Descriptor API; C++ Reflection API).
- Generate values by type. Choose scalar values with a policy for each declared type. Select enum values from the values declared by that enum. For nested messages, recurse into the nested descriptor. For repeated fields and maps, apply explicit size policies rather than allowing unbounded growth.
- Respect oneofs. A oneof represents mutually exclusive alternatives, so select no more than one member of each oneof group for a generated message. The schema defines the group and its members; your policy decides whether and which member to set.
- Apply value and shape policies separately. Shape policy controls recursion depth, repeated-field counts, and overall message size. Value policy controls seeded randomness, boundary cases, and domain-specific providers—for example, producing a timestamp that agrees with another field or an identifier in the format your application expects. These controls are generator design choices, not built-in Protobuf behavior.
- Validate the result. Where required fields apply, check initialization. Test serialization and parsing round trips, deterministic output for fixed seeds, bounded recursion and collection sizes, and application invariants such as correlated amounts. Protobuf documentation does not prescribe a standard generic mock-generation algorithm, so these checks should reflect your use case.
Reflection exposes field types and operations for working with values dynamically; it does not choose the values on your behalf (C++ Descriptor API; C++ Reflection API). Keep fallback values visibly synthetic so consumers do not mistake structurally valid test data for realistic or production-safe data.
Recommended Free Tools
Decide how to handle extensions
Extensions require deliberate support. In proto2 and editions, extension definitions can exist outside the message that they extend; proto3 does not support message extensions other than custom options. An extension declaration advertises allocation metadata, but is not a full field descriptor returned by ordinary field lookup. To populate actual extension fields, the runtime needs the extension definitions and extension-aware lookup or registry support (Proto2 Language Guide; Editions Language Guide; Extension Declarations). Verify the schema syntax and runtime behavior in use.
Choose an explicit unknown-field policy
Unknown wire fields are different from descriptor-known fields. A runtime that does not know a field’s schema cannot infer its meaning or generate a semantically informed value for it. In C++, reflection’s ListFields lists known populated fields and omits unknown ones (C++ Reflection API).
If you are creating a fresh mock, there is no descriptor basis for inventing unknown values. If you are copying a real message and need to preserve opaque fields, use binary message operations or message-oriented copying. Converting through JSON or copying only the fields returned by reflection can lose unknown data (Proto2 Language Guide). Text representations that show an unknown field only by number do not provide enough type information to reliably reconstruct its wire value (Text Format Language Specification). Preservation is not the same as understanding: retaining opaque data does not make it part of the generator’s semantic model.
Rank #4
Keep recursion and output bounded
Recursive message definitions and repeated fields can produce very large or non-terminating generation paths unless the generator sets limits. Choose a maximum recursion depth and collection sizes that fit the consuming test or tool, and define what happens when a limit is reached—for example, omit an optional nested value or stop adding repeated elements. Protobuf’s published parsing and message-size limits do not establish a universally safe generator limit for every application (Self-describing Messages). Treat limits as workload-specific configuration.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Quick Recap
Best Value
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

