Anurag
Anurag

Reputation: 397

How to set cacheControlMappings in WebContentInterceptor in Spring 5 Xml

I want to add cache-control directive (set both public and max-age seconds) for a couple of URLs in Spring MVC and I want to do those changes via applicationContext.xml only.

I am trying to set the map property cacheControlMappings of org.springframework.web.servlet.mvc.WebContentInterceptor, but the only problem is the design of the class which has no setter method for the property. As a workaround, I am invoking the addCacheMapping method using the org.springframework.beans.factory.config.MethodInvokingBean.

My configuration in spring-mvc-config.xml is as follows - I am creating a CacheControl bean as follows, and I verified by debugging that this bean gets created successfully with appropriate values populated in the application context.

<bean id="cacheControlFactory" class="org.springframework.http.CacheControl" factory-method="maxAge">
    <constructor-arg index="0" value="3600"/>
    <constructor-arg index="1">
        <value type="java.util.concurrent.TimeUnit">SECONDS</value>
    </constructor-arg>
</bean>

<bean id="myCacheControl" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject">
        <ref bean="cacheControlFactory"/>
    </property>
    <property name="targetMethod">
        <value>cachePublic</value>
    </property>
</bean>

Then I wish to invoke this method - public void addCacheMapping(CacheControl cacheControl, String... paths) of WebContentInterceptor which will add entries to the map cacheControlMappings.

I verified that calling this method programmatically works great, so it should work fine if I invoke it from the XML right? But I am trying to do the same, as shown below, but this does not work for me, and I get zero entries added to the final map.

<bean class="org.springframework.beans.factory.config.MethodInvokingBean">
    <property name="targetObject">
        <ref bean="webContentInterceptor"/>
    </property>
    <property name="targetMethod">
        <value>addCacheMapping</value>
    </property>
    <property name="arguments">
        <list>
            <ref bean="myCacheControl" />
            <value>/home</value>
            <value>/dp/**</value>
            <value>/**/b/*</value>
        </list>
    </property>
</bean>

Why does the above invocation with MethodInvokingBean not work? Am I setting the arguments wrong in any way? Do the varargs need a different handling? I don't see any errors thrown either during server startup.

Also, I am aware of this SO thread (How to set Cache-control: private with applicationContext.xml in Spring 4.2 or later ) where the accepted answer mentions there is no way to do this in the XML itself. I wanted to re-confirm if that is correct by trying to implement above solution but it is not working, but I don't see why.

Upvotes: 0

Views: 737

Answers (1)

Anurag
Anurag

Reputation: 397

As I had suspected, there was an issue in the way the arguments were getting populated. The varargs in a spring injection need to be given as an explicit list instead of an overload of arguments (like it's done in Java).

So the correct way to invoke such a method -

public void addCacheMapping(CacheControl cacheControl, String... paths)

in spring applicationContext.xml is as follows -

<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject">
        <ref bean="webContentInterceptor"/>
    </property>
    <property name="targetMethod">
        <value>addCacheMapping</value>
    </property>
    <property name="arguments">
        <list>
            <ref bean="myCacheControl" />
            <list>
                <value>/home</value>
                <value>/dp/**</value>
                <value>/**/b/*</value>
            </list>
        </list>
    </property>
</bean>

As you can see I have now used MethodInvokingFactoryBean. Somehow MethodInvokingBean did not work for me.

Upvotes: 1

Related Questions