Search code examples
javaspringspring-config

Return anything other than null


My code used to work until I added the sslEnabled configuration. Since I put "false" as the default value for sslEnabled, it will return null.

And that null causes me the following:

Caused by: org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'servletContainer' is expected to be of type 'org.springframework.boot.web.servlet.server.ServletWebServerFactory' but was actually of type 'org.springframework.beans.factory.support.NullBean'

I tried to return new ServletWebServerFactory(); but says Cannot instantiate the type ServletWebServerFactory

@Configuration
public class ConnectorConfig {

@Value("${security.ssl.enabled}")
private boolean sslEnabled;

/**
 * Servlet container.
 *
 * @return the servlet web server factory
 */
@Bean
public ServletWebServerFactory servletContainer() {
    if(sslEnabled) {
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
            @Override
            protected void postProcessContext(Context context) {
                SecurityConstraint securityConstraint = new SecurityConstraint();
                securityConstraint.setUserConstraint("CONFIDENTIAL");
                SecurityCollection collection = new SecurityCollection();
                collection.addPattern("/*");
                securityConstraint.addCollection(collection);
                context.addConstraint(securityConstraint);
            }
        };
        tomcat.addAdditionalTomcatConnectors(redirectConnector());
        return tomcat;
    }
    return null;
}
....

Basically if the flag sslEnabled is false I don't want to enable the SSL and I want to skip that configuration


Solution

  • Maybe the simplest thing to do is declaring a wrapper class and injecting that class. Like creating the following bean:

    public class ServletWebServerFactoryWrapper {
    
        private ServletWebServerFactory servletWebServerFactory;
    
        public ServletWebServerFactoryWrapper(ServletWebServerFactory servletWebServerFactory){
            this.servletWebServerFactory = servletWebServerFactory;
        }
    
        public static ServletWebServerFactoryWrapper getWrapper(ServletWebServerFactory servletWebServerFactory){
            return new ServletWebServerFactoryWrapper(servletWebServerFactory);
        }
    
        public ServletWebServerFactory getFactory(){
            return servletWebServerFactory;
        }
    }
    

    and returning it in your code:

    @Bean
    public ServletWebServerFactoryWrapper servletContainer() {
        if(sslEnabled) {
            TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
                @Override
                protected void postProcessContext(Context context) {
                    SecurityConstraint securityConstraint = new SecurityConstraint();
                    securityConstraint.setUserConstraint("CONFIDENTIAL");
                    SecurityCollection collection = new SecurityCollection();
                    collection.addPattern("/*");
                    securityConstraint.addCollection(collection);
                    context.addConstraint(securityConstraint);
                }
            };
            tomcat.addAdditionalTomcatConnectors(redirectConnector());
            return ServletWebServerFactoryWrapper.getWrapper(tomcat);
        }
        return ServletWebServerFactoryWrapper.getWrapper(null);
    }
    

    I don't know if you ca use an Optional<ServletWebServerFactory> (Java 8), but you can try, it should be pretty equivalent to this. Your method should become the following:

    @Bean
    public Optional<ServletWebServerFactory> servletContainer() {
        if(sslEnabled) {
            TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
                @Override
                protected void postProcessContext(Context context) {
                    SecurityConstraint securityConstraint = new SecurityConstraint();
                    securityConstraint.setUserConstraint("CONFIDENTIAL");
                    SecurityCollection collection = new SecurityCollection();
                    collection.addPattern("/*");
                    securityConstraint.addCollection(collection);
                    context.addConstraint(securityConstraint);
                }
            };
            tomcat.addAdditionalTomcatConnectors(redirectConnector());
            return Optional.of(tomcat);
        }
        return Optional.empty();
    }
    

    Remember that this last alternative works only on Java 8 or superior.