In this tutorial, we will explore how a Protocol Buffers (Protobuf) generated Person object behaves in Java, especially in terms of:
- Clearing fields
- Object comparison
- Immutability
- Builder usage
- Handling null values
1. Reusing the Existing Person Class
Assume you already generated a Person class from a .proto file and created a helper method to build a person object.
For example:
private Person createPerson() {
return Person.newBuilder()
.setName("Sam")
.setAge(12)
.build();
}
Moving creation logic into a method improves:
- Reusability
- Readability
- Testability
Now we can easily create multiple Person instances.
2. Creating Two Person Objects
Let’s create two separate instances:
Person person1 = createPerson(); Person person2 = createPerson();
Even though both have identical values, they are still two different objects in memory.
3. Comparing Objects: equals() vs ==
Using equals()
log.info("Equals: {}", person1.equals(person2));
Protobuf overrides equals() to compare:
- Field values
- Not memory references
So if all field values are the same, equals() returns:
true
Because Protobuf treats messages like value objects, similar to Java records.
4. Using == (Reference Comparison)
log.info("Double Equals: {}", person1 == person2);
== checks whether both references point to the same object in memory. Since these are two separate objects:
false
5. Are Protobuf Objects Mutable?
Let’s try to modify:
person1.setName("Mike"); // Not possible
You will notice:
- No setters exist
- Only getters are available
Example:
person1.getName(); person1.getAge();
Once built:
- You cannot change field values
- The object becomes read-only
Why Immutability is Good
- Thread-safe
- Predictable behavior
- No accidental state changes
- Safe to share across components
6. Modifying an Existing Object Using toBuilder()
What if you want to change just one field? Instead of rebuilding from scratch:
Person person3 = person1.toBuilder()
.setName("Mike")
.build();
What Happens Here?
toBuilder()copies existing values- You modify only what you want
build()creates a new object
So:
person1remains unchangedperson3is a new instance
7. Comparing Modified Object
person1.equals(person3);
Since name differs:
false
And reference comparison:
person1 == person3;
Also:
false
8. Setting Fields to null
Suppose you try:
Person person4 = person1.toBuilder()
.setName(null)
.build();
You get:
NullPointerException
Protobuf does not allow null values.
Internally it enforces:
- Non-null fields
- Strict validation
This avoids many runtime bugs.
9. Correct Way: Clearing a Field
Instead of setting null, use:
Person person4 = person1.toBuilder()
.clearName()
.build();
What clearName() Does
- Removes the field value
- Treats it as “not set”
- Not the same as null
10. Printing Objects
With Name Set
System.out.println(person3);
Output:
name: "Mike" age: 12
With Name Cleared
System.out.println(person4);
Output:
age: 12
Notice:
- Name is completely absent
- Protobuf only prints set fields
