You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit bc591b7
Browse filesBrowse the repository at this point in the historyBrowse files
feat(codegen-kotlin): a generated entity/value object is now constructible from Java
Kotlin default arguments are a COMPILER feature, not a bytecode one. A generated
data class whose properties are all defaulted offered Java exactly three
constructors — the full N-arg one, a synthetic bitmask one Java cannot call, and
(because every parameter is defaulted) a no-arg one yielding an all-null instance
of an IMMUTABLE class. Nothing in between, and no setters to fill in afterwards.
So a Java caller setting 3 of 14 properties had to pass 14 arguments with 11
nulls. An adopter converting an untyped jsonb bag to an `object.value` per the
authoring skill's ladder found the generated VO replacing a hand-written Lombok
`@Builder` made four Java call sites strictly worse, and reverted the conversion.
The ladder's promise is a better handle than the cast; here the handle was worse.
Emits a nested `Builder` plus a `@JvmStatic builder()`:
ItemEffect.builder().name("Restore HP").value(10).build();
A builder rather than `@JvmOverloads`: overloads are positional, so they only
help a caller whose omissions are all TRAILING, and a 14-member class would emit
15 constructors to say so. Deliberately NOT Lombok — generated code must not
force a third-party annotation processor on an adopter — so it is a plain nested
class with no new dependency.
Every backing field is nullable even where the property is not: a builder fills
incrementally and cannot hold the constructor's non-null guarantee. `build()`
restores it with `requireNotNull`, naming the property. The data-class
constructor remains the real enforcement point.
NOT on `object.projection`. A projection is a derived read-only representation —
it arrives from a view query and nothing constructs one, so a builder would
advertise something callers must not do. That exclusion was FOUND, not reasoned
about: KotlinProjectionCompileTest requires projection data classes to be
immutable and my `var` backing fields tripped it. The stored-proc fixture now
demonstrates the split cleanly — `OrderReportArgs` (object.value, the input a
caller builds) gets a builder; `OrderReport` (object.projection, the result)
does not.
The new test is the point of the change as much as the generator is: every other
test in this module is Kotlin-side, where named arguments hide the problem
completely, which is exactly why the Java-interop face of this output was free to
be bad. KotlinValueObjectJavaConstructionTest compiles real JAVA against the
generated class through kotlin-compile-testing and sets 2 of 5 properties.
Verified by reverting the generator: `error: cannot find symbol`.
13 snapshots re-cut. The only removed line in that whole diff is `)` becoming
`) {` — everything else is additive. No vocabulary change, so metamodelVersion
does not move (`check-metamodel-version`: none change since v1.0.1).
373/373 in codegen-kotlin; java+kotlin conformance green; gates lane green.
codegen-spring emits Java `record`s, which have the same all-args problem and no
defaults at all — tracked in #365 as a follow-on, deliberately out of scope here.
Closes#365
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NTcEKXTQMYt84fAjuw5A2M
0 commit comments