0

Good day experts, I want to figure out why my case is not working properly.
Situation:
There is a class called AbstractCheckoutStepValidator and here is it's xml configuration:

<bean id="abstractCheckoutStepValidator" class="...checkout.steps.validation.AbstractCheckoutStepValidator" abstract="true">
  <property name="checkoutFlowFacade" ref="checkoutFlowFacade"/>
  <property name="checkoutFacade" ref="checkoutFacade"/>
</bean>

and code:

public abstract class AbstractCheckoutStepValidator implements CheckoutStepValidator
{
    private CheckoutFacade checkoutFacade;
    private CheckoutFlowFacade checkoutFlowFacade;

    @Override
    public abstract ValidationResults validateOnEnter(final RedirectAttributes redirectAttributes);

    @Override
    public ValidationResults validateOnExit()
    {
        return ValidationResults.SUCCESS;
    }

    public CheckoutFacade getCheckoutFacade()
    {
        return checkoutFacade;
    }

    @Required
    public void setCheckoutFacade(final CheckoutFacade checkoutFacade)
    {
        this.checkoutFacade = checkoutFacade;
    }

    public CheckoutFlowFacade getCheckoutFlowFacade()
    {
        return checkoutFlowFacade;
    }

    @Required
    public void setCheckoutFlowFacade(final CheckoutFlowFacade checkoutFlowFacade)
    {
        this.checkoutFlowFacade = checkoutFlowFacade;
    }

}

and here is DefaultMultiStepCheckoutStepValidator class that extends AbstractCheckoutStepValidator and overrides it's getter

public class DefaultMultiStepCheckoutStepValidator extends AbstractCheckoutStepValidator {
    private static final Logger LOGGER = Logger.getLogger(DefaultMultiStepCheckoutStepValidator.class);

    @Resource(name = "companyCheckoutFacade")
    private CompanyCheckoutFacade companyCheckoutFacade;


    // omitted code


    @Override
    public CompanyCheckoutFacade getCheckoutFacade() {
        return companyCheckoutFacade;
    }
}

xml configuration for this class:

<bean id="defaultMultiStepCheckoutValidator" class="...checkout.steps.validation.impl.DefaultMultiStepCheckoutStepValidator" parent="abstractCheckoutStepValidator" />

From technical perspective it should be fine, if getter returns parent class then I can use one of it's subclasses in my case it is CompanyCheckoutFacade extends CheckoutFacade. ( I have a similar examples of it, like here:

@Override
protected CompanyCartFacade getCartFacade() {
    return (CompanyCartFacade) super.getCartFacade();
}

but here I'm sure that returned bean can be casted to this subclass and that's why i'm calling getter from parent class and this getter works fine either in parent class or in subclass)
Also in the code, I'm injecting dependency via annotation and this field is not related to checkoutFacade field in parent class... If I'm starting the server with the code above then I got the following error:

Error creating bean with name 'defaultMultiStepCheckoutValidator' defined in ServletContext resource [/WEB-INF/config/multi-step-checkout-config.xml]: Initialization of bean failed; nested exception is org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type '...order.impl.DefaultCheckoutFacade' to required type '...facades.order.CompanyCheckoutFacade' for property 'checkoutFacade'; nested exception is java.lang.IllegalStateException: Cannot convert value of type '...order.impl.DefaultCheckoutFacade' to required type '...facades.order.CompanyCheckoutFacade' for property 'checkoutFacade': no matching editors or conversion strategy found
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:342) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:113) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.lambda$resolveManagedMap$1(BeanDefinitionValueResolver.java:453) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at java.util.LinkedHashMap.forEach(LinkedHashMap.java:684) ~[?:?]
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveManagedMap(BeanDefinitionValueResolver.java:451) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:181) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1697) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1442) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:324) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:330) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:113) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.lambda$resolveManagedMap$1(BeanDefinitionValueResolver.java:453) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at java.util.LinkedHashMap.forEach(LinkedHashMap.java:684) ~[?:?]
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveManagedMap(BeanDefinitionValueResolver.java:451) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:181) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1697) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1442) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:324) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.resolveBeanByName(AbstractAutowireCapableBeanFactory.java:453) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:527) ~[spring-context-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:497) ~[spring-context-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:650) ~[spring-context-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:239) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:130) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessProperties(CommonAnnotationBeanPostProcessor.java:318) ~[spring-context-5.2.9.RELEASE.jar:5.2.9.RELEASE]
        ... 27 more


Question is:
From the error above I don't really understand why spring tries to convert property value of type '...order.impl.DefaultCheckoutFacade' to required type '...facades.order.CompanyCheckoutFacade' for property 'checkoutFacade'. I'm not using checkoutFacade property anywhere in my getter. DefaultCheckoutFacade is the default implementation of CheckoutFacade interface and I'm sure that checkoutFacade ref in xml configuration refers to the correct implementation, here:

<alias name="defaultCheckoutFacade" alias="checkoutFacade"/>
<bean id="defaultCheckoutFacade" class="...order.impl.DefaultCheckoutFacade">
    // properties are omitted
</bean>

I my class I'm saying that getter should return different implementation and that is it. To get rid of this error I just need to rename getter and do not override the one from parent class but I don't understand why approach which overrides getter does not work?

Thank you for spending your time / answering question.

np_6
  • 514
  • 1
  • 6
  • 19
Maksim
  • 351
  • 1
  • 2
  • 12
  • Because of the return-type of the getter, which you changed from `CheckoutFacade` to `CompanyCartFacade`. So now when you inject something it has to be of that type. – M. Deinum Apr 07 '21 at 09:27
  • @Override protected CompanyCartFacade getCartFacade() { return (CompanyCartFacade) super.getCartFacade(); } Why then this getter is working fine? It has also different type from parent getter. – Maksim Apr 07 '21 at 09:33
  • Because that isn't being wired by spring. – M. Deinum Apr 07 '21 at 09:43
  • You mean, that spring performance a validation if setter and getter type is the same before bean is instantiated ? I mean, in order to set the dependency we need only correctly defined setter even without getter, or I am mistaken? – Maksim Apr 07 '21 at 09:45
  • There can only be 1 type for a bean property, if there is a getter/setter that doesn't match it might lead to issues (as you see here). – M. Deinum Apr 07 '21 at 09:46

0 Answers0