35

I want to make a small change, deep in tree of Java protocol buffer objects.

I can use the .getBuilder() method to make a new object that is a clone of an old one with some changes.

When this is done at a deep level, the code becomes ugly:

Quux.Builder quuxBuilder = foo.getBar().getBaz().getQuux().toBuilder()
Baz.Builder bazBuilder = foo.getBar().getBaz().toBuilder()
Bar.Builder barBuilder = foo.getBar().toBuilder()
Foo.Builder fooBuilder = foo.toBuilder()

quuxBuilder.setNewThing(newThing);
bazBuilder.setQuux(quuxBuilder);
barBuilder.setBaz(bazBuilder);
fooBuilder.setBar(barBuilder);

Foo newFoo = fooBuilder.build();

(This is just 4 levels, I'm routinely dealing with 5-8 levels.)

Is there a better way?

fadedbee
  • 42,671
  • 44
  • 178
  • 308

1 Answers1

42

Another option is (I think; it's been a while):

Foo.Builder fooBuilder = foo.toBuilder();
fooBuilder.getBarBuilder().getBazBuilder().getQuuxBuilder()
    .setNewThing(newThing);
newFoo = fooBuilder.build();

Note that this isn't any more efficient; you're still making copies of foo, bar, baz, and quux.

Kenton Varda
  • 41,353
  • 8
  • 121
  • 105
  • 2
    Thanks, I was really surprised that this worked. I didn't realise that `fooBuilder.getBarBuilder()` returned a Bar.Builder *in the context of fooBuilder*. The test suite shows no errors, so it works. The amount of code still grows linearly with the depth, but at least it's three times smaller. – fadedbee Mar 25 '15 at 16:26
  • 5
    If you prefer, you can always keep your objects in `Builder` form long-term rather than immutable message form, and then you can keep a pointer to the particular sub-builder you wish to modify and modify it repeatedly. But watch out for the usual design issues with mutable objects. – Kenton Varda Mar 26 '15 at 08:50