Skip to content

Serializer::Mutable calls Dancer2::Core::DSL functions without requiring it #1820

Description

@bigpresh

Status: confirmed against main @ 21bc21d9 · Found incidentally while investigating something else.

lib/Dancer2/Serializer/Mutable.pm:14-27 builds its dispatch table from functions in Dancer2::Core::DSL:

my $serializer = {
    'YAML'   => {
        to      => sub { Dancer2::Core::DSL::to_yaml(@_)   },
        from    => sub { Dancer2::Core::DSL::from_yaml(@_) },
    },
    'Dumper' => { ... Dancer2::Core::DSL::to_dumper / from_dumper ... },
    'JSON'   => { ... Dancer2::Core::DSL::to_json   / from_json   ... },
};

...but the module never requires Dancer2::Core::DSL. It works in a real application only because the DSL is always loaded by the time a request is served.

Reproduction

Using Dancer2::Serializer::Mutable standalone — without loading the DSL — fails at deserialization time, and the error is swallowed by Role::Serializer's around deserialize, surfacing only through log_cb:

LOG[core]: Failed to deserialize content: Undefined subroutine
&Dancer2::Core::DSL::from_yaml called at lib/Dancer2/Serializer/Mutable.pm line 17.

...and deserialize quietly returns undef.

Impact

  • Mutable cannot be unit-tested in isolation, which is presumably why this has gone unnoticed.
  • It is a latent load-order dependency: any future refactor that stops loading the DSL eagerly turns this into a runtime failure that returns undef rather than raising.
  • The silent-undef failure mode makes it hard to diagnose.

Suggested fix

Add an explicit use Dancer2::Core::DSL; (or require_module at the point of use — Module::Runtime is already imported at line 7, and the module already uses require_module for serializer classes in the mapping builder).

Also worth considering whether the dispatch table should call the serializer classes directly rather than routing through DSL keywords, which is a slightly odd layering — the mapping builder at lines 40-47 already constructs serializer objects directly for the non-default case.

Suggested test

A Dancer2::Serializer::Mutable round-trip in a test that does not load Dancer2 or the DSL.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions