Spring Boot – Using Spring Boot’s @ConfigurationProperties Without Violating Law of Demeter

designlaw-of-demeterspringspring-boot

My apps commonly have one or more prop holders. These holders contain config data used in the app such as:

@Component
@ConfigurationProperties(prefix="app.orders")
@Data //lombok
public class OrderProps {

     private int maxItems;
     // other order props
}

Various components that use one or more of these props get injected with the prop holder:

@Service
public class OrderService {

    private int maxSize;

    public OrderService(OrderProps props) {
         maxSize = props.getMaxSize();
    }

 }

In this example, OrderService is only dependent on maxSize. Other classes may have also a varying number of properties needed from OrderProps.

Doesn't injecting @ConfigurationProperties classes violate the Law of Demeter. Specifically, doesn't it mask the real dependency (in this case an int) as described here?

Is there way to design without violating? Littering code with @Value("${order.maxItems}") or perhaps less problematic @Value("#{orderProps.maxItems}") seems to have its own set of problems especially when refactoring / maintenance.

Best Answer

Doesn't injecting @ConfigurationProperties classes violate the Law of Demeter. Specifically, doesn't it mask the real dependency (in this case an int) as described here?

Yes and yes. If OrderService only requires an int, then that's all you should be injecting. OrderProps is a bag of properties that only exists as a convenient injection point for Spring, and you should never design your domain classes around a specific framework.

Littering code with @Value ... seems to have its own set of problems especially when refactoring / maintenance.

This is precisely why I'm not a fan of Spring component scan for larger projects. I find it cleaner and more maintainable to limit configuration and auto-wiring responsibilities to @Configuration classes:

@Configuration
public class OrderServiceConfiguration {
    @Autowired
    private OrderProps orderProps;

    @Bean
    public OrderService orderService() {
      return new OrderService(orderProps.getMaxItems());
    }
}
Related Topic