Skip to content

feat(SimpleBuilderFor): generate builders for all classes of a package #323

Description

@igel-devin-ai

Motivation

@SimpleBuilderFor requires every external type to be listed explicitly in value. For libraries exposing many DTOs this means a long, manually maintained list that drifts out of date whenever the library adds a type. It should be possible to point the annotation at a package (or several packages) and generate builders for every top-level class found there.

@SimpleBuilderFor(
    packages = {"com.thirdparty.users", "com.thirdparty.orders"},
    options = @SimpleBuilder.Options(packageName = "com.example.generated"))
public class ExternalBuildersProvider { }

API design: additional property vs. new annotation

Option A — additional property on @SimpleBuilderFor (e.g. String[] packages() default {}):

  • Scanning plays the same role as value - it selects which external types get builders, just in bulk. Keeping both on one annotation avoids a parallel API for the same purpose.
  • Each repeat of the (now @Repeatable) annotation composes its packages with its own options, so different packages can still be routed to different output packages.
  • Cost: value loses its "required" status and becomes default {}, plus validation that at least one of value/packages is non-empty.

Option B — a separate annotation (e.g. @SimpleBuilderForPackage("com.thirdparty.users")):

  • Keeps value mandatory on @SimpleBuilderFor and gives scanning its own obvious name.
  • Cost: a second annotation to document and maintain for the same job, and it would need its own repeatability story and options member duplicated (or a nested options object shared between the two).

Recommendation: Option A. Package scanning is a bulk form of the existing value list, not a different feature; the option-level composition already introduced by repeatability makes packages a natural fit on the same annotation. A sensible name avoiding confusion with packageName (the output package) would be packages or scanPackages.

Implementation notes / open questions

  • Discovery via Elements.getPackageElement(name).getEnclosedElements() gives only top-level types - nested classes keep requiring an explicit value entry.
  • Filter policy for non-constructible members of a package (interfaces, abstract classes, enums, annotation types): skip silently, or report per type? A skip-with-debug default plus strict-mode escalation seems reasonable.
  • On the module path, scanning is limited to packages readable/exported to the compiling module.
  • Deterministic output ordering should sort discovered types (e.g. by qualified name).

Raised while discussing #306 (multiple packages for generated builders).

Written by Devin

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