I noticed AbstractEnvironment has a reference to one of its parent interface ConfigurablePropertyResolver (inherited through ConfigurableEnvironment)

It also has a propertyResolver which is of type ConfigurablePropertyResolver.

This seems to enable delegating common interface methods to another PropertyResolver method. Attested, for example, in the following method, where the method getProperty, common to both AbstractEnvironment and ConfigurablePropertyResolver, is delegated to propertyResolver: =Java public String getProperty(String key) { return this.propertyResolver.getProperty(key); } (This seems to be an example of the Proxy Pattern, but that is beside the point.) I noticed the delegation only happens to methods defined in the PropertyResolver and ConfigurablePropertyResolver interfaces, which makes sense because only resolver-related methods should be decoupled into propertyResolver and delegated. However, propertyResolver having the type ConfigurablePropertyResolver means anything of type ConfigurableEnvironment can be assigned to it too and that any method defined in ConfigurableEnvironment is also common to both AbstractEnvironment and ConfigurablePropertyResolver.

I wonder whether it's the original authors' intention for ConfigurableEnvironment methods to be accessible, or even to be delegated to, through propertyResolver? I am asking that because I cannot find any instance of that in the code base. If that's not an intended purpose, is it perhaps better to set propertyResolver to be of another type extended from ConfigurablePropertyResolver as a Marker Interface?

Here is the class diagrams to illustrate the change:

Spring AbstractEnvironment is Capable of Recursive Reference : Is it Intended?

Comment From: snicoll

I wonder whether it's the original authors' intention for ConfigurableEnvironment methods to be accessible, or even to be delegated to, through propertyResolver?

Yes. ConfigurableEnvironment (or Environment rather) is a special object type, at the same level as the ApplicationContext or the BeanFactory and being to configure things like placeholder settings must be accessible. Implementing the interface makes sure that we are consistent with the underlying feature and we don't duplicate contracts.