fix: http server codegen#3944
Conversation
Sibling fields in result types were sharing the same AttributeExpr pointer during projection, causing metadata (descriptions and JSON tags) to leak between them. Added field name to the `seen` key in `projectRecursive` to be ensured each sibling gets its own isolated entry. Signed-off-by: Adam Bocim <adam.bocim@seznam.cz>
|
Thank you for this! The clear repro in the description and the golden tests made this a pleasure to review — much appreciated. 🙏 The fix is correct for the sibling case and I'm happy to merge it. While reviewing I dug a bit deeper into the projection cache and found something worth sharing: the same leak survives one nesting level deeper. The new key ( var UserType = Type("UserType", func() {
Attribute("u", Int)
})
var Wrapper = Type("Wrapper", func() {
Attribute("a", UserType, "Inner A", func() {
Meta("struct:tag:json", "inner_a")
})
})
var RT = ResultType("ResultTypeNested", func() {
Attribute("a", UserType, "Outer A", func() {
Meta("struct:tag:json", "outer_a")
})
Attribute("nested", Wrapper)
})still generates (with this PR applied): // WrapperResponseBody is used to define fields on response body types.
type WrapperResponseBody struct {
// Outer A
A *UserTypeResponseBody `json:"outer_a"`
}The root cause is that the I think the complete fix is to keep the original Would you like to take a stab at that? No pressure at all — happy to merge this as-is and follow up myself if you'd rather. Either way, thanks again for tracking this down and for the excellent test coverage! |
|
The original I know it's kind of a hack. I can try to dig into it more later and fix If you could merge the current fix for now, I'd really appreciate it. |
The projection cache stored entire field attributes, so any two fields hashing to the same (type, view) key aliased one AttributeExpr and leaked per-field metadata (descriptions, struct tags) across fields. Keying by field name only narrowed the collisions: same-named fields of the same type under different parent types still aliased. Cache the projected types instead and give every field its own attribute wrapping the shared projection. Single result types register their projection before computing their fields so that recursive references resolve to the in-flight projection and terminate.
|
No worries — I went ahead and pushed the follow-up to your branch so everything lands together. The Thanks again for tracking this down — will merge once CI is green. |
|
Thanks a lot for the fix, Raphael! |
This PR fixes a bug we have hit within http server code generator.
Sibling fields in result types were sharing the same AttributeExpr pointer during projection, causing metadata (descriptions and JSON tags) to leak between them. Added field name to the
seenkey inprojectRecursiveto be ensured each sibling gets its own isolated entry.Goa design code:
Incorrectly generated code with leaked descriptions (comments) and JSON tags (gen/http/v2/server/types.go):