Skip to content

Graceful degradation when a referenced builder has no copy function #310

Description

@igel-devin-ai

Sub-task of #301.

Goal

When a referenced builder has no dedicated copy function (B(T) ctor or create(T)/of(T) factory), the generated consumer builder seeds the empty builder itself: create it via the builder's empty-instantiation path, then call each field function to copy the source value's properties.

How it works

  • The seeded path is emitted as a block lambda, e.g. source -> { B b = B.create(); b.name(source.name()); ...; return b; } — a method reference cannot express a sequence, so BuilderInstantiation gains a FieldSeedingCall variant (empty call + ordered (method, accessor) pairs).
  • Empty builder required: the builder's own empty-instantiation path (ctor or static factory) is reused — already part of the contract.
  • Field function detection: per readable property of T, find an accessible single-param method on B whose name matches a ranked convention — name(v) first (Lombok / Immutables / our own style), then setName(v) (JavaBeans / FreeBuilder / protobuf). Return type does not matter (fluent or void) since calls are emitted as statements.
  • Safety rule: this path only qualifies when every readable property of T has a matching field function. A partially covered property set would silently drop values — the same data-loss issue as an empty-builder fallback. On partial coverage, fall back to the previous plan: skip the helpers that need a seeded path, with a debug log line, and use the plain setter.
  • Side effect: FreeBuilder and AutoValue generated shapes resolve through this path (per-property setters, no copy ctor or toBuilder).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions