Commit 58a7fdf
fix: Resolve Any to AnyWeaver in Weaver.fromSurface instead of the lossy empty-object fallback (#633)
## Summary
Fixes #632.
`Weaver.fromSurface` mapped the `Any` surface to the private
`emptyObjectWeaver`, so any `Any`-typed value reached via the
Surface-driven derivation path silently decoded to `null`. The visible
symptom: a case class field like `properties: Map[String, Any]` inside a
nested structure round-tripped every value in the map to `null` with no
error, unless the caller hand-built a given chain down to
`Weaver[Map[String, Any]]`.
## Fix
Add an `anyFactory` to `Weaver.fromSurface`'s factory list, ahead of
`emptyObjectFallbackFactory`, that resolves surfaces with `rawType ==
classOf[AnyRef]` to `AnyWeaver.default` — the generic codec already
exposed as `given anyWeaver: Weaver[Any]` in `PrimitiveWeaver`. This
covers the `scala.Any` alias, `AnyRef`/`java.lang.Object`, and the
`AnyRefSurface` placeholders Surface uses for erased type parameters
(per review feedback). Case classes and other concrete types are
unaffected because `complexTypeFactory` matches first, and the
empty-object fallback remains in place for genuinely open abstract
types.
As a consequence, `Weaver.fromSurfaceOpt` now returns `Some` for
`Any`-containing types (e.g. `Map[String, Any]`), so `RouterHandler`
routes returning such types use the weaver path (structural JSON)
instead of the toString fallback.
## Tests
- `fromSurface(Surface.of[Any])` round-trips primitives via `AnyWeaver`
(was: decodes to `null`)
- Same for `AnyRef` and `java.lang.Object`
- The exact issue repro: `Map[String, Any]` field decoding from JSON
- The nested variant (`List[ConfigWithAnyMap]`) that exercises the
Surface-driven fallback path in the derivation macro, with no per-level
givens (was: `Map("useSSL" -> null)`)
- `fromSurfaceOpt` returns `Some` for `Any`-containing types
All `uniJVM` and `netty` tests pass.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>1 parent b6b72f2 commit 58a7fdf
2 files changed
Lines changed: 55 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
387 | 387 | | |
388 | 388 | | |
389 | 389 | | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
390 | 401 | | |
391 | 402 | | |
392 | 403 | | |
| |||
415 | 426 | | |
416 | 427 | | |
417 | 428 | | |
| 429 | + | |
418 | 430 | | |
419 | 431 | | |
420 | 432 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
636 | 636 | | |
637 | 637 | | |
638 | 638 | | |
| 639 | + | |
| 640 | + | |
| 641 | + | |
| 642 | + | |
| 643 | + | |
| 644 | + | |
| 645 | + | |
| 646 | + | |
| 647 | + | |
| 648 | + | |
| 649 | + | |
| 650 | + | |
| 651 | + | |
| 652 | + | |
| 653 | + | |
| 654 | + | |
| 655 | + | |
| 656 | + | |
| 657 | + | |
| 658 | + | |
| 659 | + | |
| 660 | + | |
| 661 | + | |
| 662 | + | |
| 663 | + | |
| 664 | + | |
| 665 | + | |
| 666 | + | |
| 667 | + | |
| 668 | + | |
| 669 | + | |
| 670 | + | |
| 671 | + | |
| 672 | + | |
| 673 | + | |
| 674 | + | |
| 675 | + | |
| 676 | + | |
| 677 | + | |
| 678 | + | |
| 679 | + | |
639 | 680 | | |
640 | 681 | | |
641 | 682 | | |
| |||
651 | 692 | | |
652 | 693 | | |
653 | 694 | | |
| 695 | + | |
| 696 | + | |
0 commit comments