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
The generated controller excluded ObjectField from read (rowToEntity), create,
and PATCH — VO jsonb columns were invisible. Now included everywhere:
- patchSettableFields drops the ObjectField exclusion (MapField + jsonb-open-bag
stay excluded — staged out); rowToEntity + the create insert loop include VO
columns (the Exposed Column<VO> codec / shared Jackson metaJsonbMapper handles
the jsonb text <-> VO record / List<VO>).
- PATCH binds a present VO via objectMapper.treeToValue (Jackson, NOT the
decorative kotlinx serializer) into the VO record / List<VO>, resolved by a new
voElementTypeFqn helper, then validates: keeps validateValue for own constraints
and ADDS explicit validator.validate(voElement) per present element (spec
section 0 — validateValue does not cascade @Valid). FR-035 tristate preserved.
- KotlinEntityGenerator stamps @field:jakarta.validation.Valid on nested VO members
so validate(dto) cascades on POST (golden snapshot User.kt reconciled).
Both lanes green (reference Exposed + generated MockMvc, over Testcontainers PG);
codegen-kotlin 280/0; typed-jsonb roundtrip 1/1 — no regression. field.map and the
Kotlin open-bag PATCH remain staged-out follow-ups.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NGQ7oSuNcjhsMHWwZzhBwr
Copy file name to clipboardExpand all lines: server/java/codegen-kotlin/src/main/kotlin/com/metaobjects/generator/kotlin/KotlinSpringControllerGenerator.kt
+66-22Lines changed: 66 additions & 22 deletions
Original file line number
Diff line number
Diff line change
@@ -151,15 +151,16 @@ open class KotlinSpringControllerGenerator : MultiFileDirectGeneratorBase<MetaOb
151
151
val pkFieldName = primary?.fields?.firstOrNull() ?:DEFAULT_PK_FIELD
152
152
val pkParamType = primaryKeyParamType(entity, pkFieldName)
153
153
154
-
// FR-035: the PATCH-settable columns = scalar fields minus the PK. ObjectField / MapField
155
-
// (jsonb value-objects) and the `field.string @dbColumnType=jsonb` open bag are excluded:
156
-
// their in-process type is a kotlinx JsonElement / VO with no clean Jackson treeToValue
157
-
// bind on the raw-JsonNode patch path. (create DOES write the open bag from the DTO;
158
-
// an open bag is thus a create-only CRUD column — see KNOWN_GAPS.)
159
-
// When this is EMPTY (a PK + only object/map/jsonb columns) the controller emits no
val ktType =if (field.isArrayType) "kotlin.collections.List<$elem>"else elem
434
448
val fn = field.name
435
449
val cap = capitalizeFirst(fn)
436
450
append(" val has$cap = body.has(\"$fn\")\n")
@@ -443,6 +457,17 @@ open class KotlinSpringControllerGenerator : MultiFileDirectGeneratorBase<MetaOb
443
457
append(" val v$cap: $ktType? = if (has$cap && !null$cap) objectMapper.treeToValue(body.get(\"$fn\"), object : TypeReference<$ktType>() {}) else null\n")
444
458
append(" if (has$cap && !null$cap && validator.validateValue(${shortName}::class.java, \"$fn\", v$cap).isNotEmpty()) return@transaction ResponseEntity.badRequest().body(mapOf(\"error\" to \"validation\") as Any)\n")
445
459
}
460
+
// Program D (spec §0): jakarta validateValue does NOT cascade @Valid into a nested
461
+
// value-object's constraints, so a present VO is validated EXPLICITLY —
462
+
// validator.validate(voElement) per element (single VO whole; array VO per element),
463
+
// 400 on any violation. (A present-null / cleared value is already handled above.)
464
+
if (field isObjectField) {
465
+
if (field.isArrayType) {
466
+
append(" if (v$cap != null && v$cap.any { validator.validate(it).isNotEmpty() }) return@transaction ResponseEntity.badRequest().body(mapOf(\"error\" to \"validation\") as Any)\n")
467
+
} else {
468
+
append(" if (v$cap != null && validator.validate(v$cap).isNotEmpty()) return@transaction ResponseEntity.badRequest().body(mapOf(\"error\" to \"validation\") as Any)\n")
469
+
}
470
+
}
446
471
}
447
472
// Apply the already-bound + validated values. Columns are qualified (`Table.col`)
448
473
// so a field named like the `body`/`id` params can't shadow them.
@@ -1279,6 +1304,25 @@ open class KotlinSpringControllerGenerator : MultiFileDirectGeneratorBase<MetaOb
1279
1304
}
1280
1305
}
1281
1306
1307
+
/** Read the `@objectRef` attr off a value-object [field] (resolving); null when absent. */
0 commit comments