Skip to main content
  1. blog/

Spring overwrites map keys with bean name from value

·2 mins

Overview #

I recently encountered a strange behavior in Spring where it overwrites map keys with the value bean names. In this article, I’ll demonstrate how this issue happens and how to solve it.


Code Example #

OrderType.java #

public enum OrderType {
    ONLINE, STORE, WAREHOUSE;
}

OrderSubmissionStrategy.java #

public interface OrderSubmissionStrategy {}

OnlineOrderSubmissionStrategy.java #

public class OnlineOrderSubmissionStrategy implements OrderSubmissionStrategy {}

WarehouseOrderSubmissionStrategy.java #

public class WarehouseOrderSubmissionStrategy implements OrderSubmissionStrategy {}

Let’s define a Map bean by annotating a method that returns our map with @Bean.

@Configuration
public class AppConfiguration {

    @Bean
    public Map<OrderType, OrderSubmissionStrategy> strategyMap() {
        Map<OrderType, OrderSubmissionStrategy> strategyMap = new HashMap<>();
        strategyMap.put(OrderType.ONLINE, onlineOrderSubmissionStrategy());
        strategyMap.put(OrderType.WAREHOUSE, warehouseOrderSubmissionStrategy());
        return strategyMap;
    }

    @Bean
    public OrderSubmissionStrategy onlineOrderSubmissionStrategy() {
        return new OnlineOrderSubmissionStrategy();
    }

    @Bean
    public OrderSubmissionStrategy warehouseOrderSubmissionStrategy() {
        return new WarehouseOrderSubmissionStrategy();
    }
}

Now, let’s use this inject bean into another class using @Autowired.

@Component
public class OrderSubmissionStrategyFactory {

    @Autowired
    private Map<OrderType, OrderSubmissionStrategy> strategyMap;

    public void printStrategyMap() {
        strategyMap.entrySet().forEach(entry-> {
            System.out.println(entry.getKey() + " " + entry.getValue());
        });
    }
}

When we invoke the printStrategyMap() method, notice that the map keys have been overwritten with the bean names from the values:

[onlineOrderSubmissionStrategy, onlineOrderSubmissionStrategy]
[warehouseOrderSubmissionStrategy, warehouseOrderSubmissionStrategy]

Solution #

It turns out that using @Autowired for injecting a map causes this strange behavior so the solution is to use @Resource instead.

@Component
public class OrderSubmissionStrategyFactory {

    @Resource
    private Map<OrderType, OrderSubmissionStrategy> strategyMap;

    public void printStrategyMap() {
        strategyMap.entrySet().forEach(entry-> {
            System.out.println(entry.getKey() + " " + entry.getValue());
        });
    }
}

Now the output is what we expect.

[ONLINE, onlineOrderSubmissionStrategy]
[WAREHOUSE, warehouseOrderSubmissionStrategy]