Skip to content

Flamingock dependency injection fails for custom typed dependencies when Spring Boot DevTools restart support is enabled. #951

Description

@craigflichel

Bug description

A dependency can be successfully added to the target system context, but Flamingock later fails to resolve the same type as a migration method parameter:

Wrong parameter[MigrationConfiguration]. Dependency not found.

The underlying problem appears to be that dependency lookup uses Class<?> identity as the key. With Spring Boot DevTools, the registered dependency type and the migration method parameter type can have the same fully-qualified class name but be loaded by different classloaders.

As a result, they are different Class<?> instances and the type lookup fails.

Example

Custom dependency:

public record MigrationConfiguration(
        String configCollection,
        String environment) {
}

Registered with the Mongo target system:

MigrationConfiguration migrationConfiguration =
        new MigrationConfiguration(configCollection, environment);

targetSystem.addDependency(migrationConfiguration);

Migration:

@Apply
public void apply(
        MongoDatabase db,
        MigrationConfiguration migrationConfiguration) {
    ...
}

With Spring Boot DevTools restart enabled, Flamingock throws:

Wrong parameter[MigrationConfiguration]. Dependency not found.

Debugging findings

Stepping through Flamingock shows that the dependency is successfully added to a SimpleContext.

The dependency is stored by type in a structure such as:

Map<Class<?>, Dependency> dependenciesByExactType;

Later, migration parameter resolution occurs through a PriorityContext.

The MigrationConfiguration class used as the map key when the dependency is registered and the MigrationConfiguration class requested during parameter resolution have:

  • the same fully-qualified class name
  • different classloaders
  • different Class<?> identities/hash codes

One is loaded through Spring Boot's RestartClassLoader.

Because Class<?> equality includes the defining classloader, lookup by exact type fails even though logically this is the same application type.

Workaround

Completely disabling the Spring Boot DevTools restart classloader fixes the issue. This is not feasible for local developer environments.

It was necessary to disable it before application startup, for example using:

-Dspring.devtools.restart.enabled=false

With the restart classloader disabled, the same Flamingock dependency registration and migration parameter injection work correctly.

Expected behaviour

Flamingock should support dependency resolution when application classes are loaded across any classloader boundaries

The current Dependency not found message is misleading because the dependency was in fact registered.

Environment

  • Flamingock: 1.4.4
  • Spring Boot application
  • Spring Boot DevTools enabled
  • MongoDB Sync Target System

Relevant exception:

io.flamingock.internal.core.runtime.MissingInjectedParameterException

Source:

public class MissingInjectedParameterException extends FlamingockException {

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions