Hi,

After upgrading from Spring Boot 1.4.1 to 1.4.2 i get an error which seems to be a strange combination of injecting a LocalValidatorFactoryBean with a @FilterRegistrationBean definition.

@SpringBootApplication
public class SpringDevtoolsIssueApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringDevtoolsIssueApplication.class, args);
    }

    @Autowired
    private org.springframework.validation.beanvalidation.LocalValidatorFactoryBean validator;

    @Bean
    public LocalValidatorFactoryBean validator() {
        return new LocalValidatorFactoryBean();
    }

    @Bean
    public FilterRegistrationBean create() {
        FilterRegistrationBean bean = new FilterRegistrationBean();
       . . . . . 

This error only occurs running standalone. Very odd. The error occurs on Linux / Windows and Mac.

I've managed to simplify and recreate the issue on bitbucket: https://bitbucket.org/davidmelia/spring-boot-validation-error (mvn clean install and run start.sh)

If you downgrade tomcat to 8.5.5 in the war pom.xml the problem goes away and I think it's related to the Tomcat 8.5.6 bugfix https://bz.apache.org/bugzilla/show_bug.cgi?id=60087

The error is

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'validator' defined in com.example.SpringDevtoolsIssueApplication: Invocation of init method failed; nested exception is java.util.ServiceConfigurationError: javax.validation.spi.ValidationProvider: Error reading configuration file
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1583) ~[spring-beans-4.3.4.RELEASE.jar!/:4.3.4.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) ~[spring-beans-4.3.4.RELEASE.jar!/:4.3.4.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) ~[spring-beans-4.3.4.RELEASE.jar!/:4.3.4.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.4.RELEASE.jar!/:4.3.4.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.4.RELEASE.jar!/:4.3.4.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.4.RELEASE.jar!/:4.3.4.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-4.3.4.RELEASE.jar!/:4.3.4.RELEASE]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:207) ~[spring-beans-4.3.4.RELEASE.jar!/:4.3.4.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1131) ~[spring-beans-4.3.4.RELEASE.jar!/:4.3.4.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1059) ~[spring-beans-4.3.4.RELEASE.jar!/:4.3.4.RELEASE]
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:589) ~[spring-beans-4.3.4.RELEASE.jar!/:4.3.4.RELEASE]
        ... 35 common frames omitted
Caused by: java.util.ServiceConfigurationError: javax.validation.spi.ValidationProvider: Error reading configuration file
        at java.util.ServiceLoader.fail(ServiceLoader.java:232) ~[na:1.8.0_51]
        at java.util.ServiceLoader.parse(ServiceLoader.java:309) ~[na:1.8.0_51]
        at java.util.ServiceLoader.access$200(ServiceLoader.java:185) ~[na:1.8.0_51]
        at java.util.ServiceLoader$LazyIterator.hasNextService(ServiceLoader.java:357) ~[na:1.8.0_51]
        at java.util.ServiceLoader$LazyIterator.hasNext(ServiceLoader.java:393) ~[na:1.8.0_51]
        at java.util.ServiceLoader$1.hasNext(ServiceLoader.java:474) ~[na:1.8.0_51]
        at javax.validation.Validation$GetValidationProviderListAction.loadProviders(Validation.java:354) ~[validation-api-1.1.0.Final.jar!/:na]
        at javax.validation.Validation$GetValidationProviderListAction.run(Validation.java:329) ~[validation-api-1.1.0.Final.jar!/:na]
        at javax.validation.Validation$GetValidationProviderListAction.getValidationProviderList(Validation.java:316) ~[validation-api-1.1.0.Final.jar!/:na]
        at javax.validation.Validation$DefaultValidationProviderResolver.getValidationProviders(Validation.java:299) ~[validation-api-1.1.0.Final.jar!/:na]
        at javax.validation.Validation$GenericBootstrapImpl.configure(Validation.java:257) ~[validation-api-1.1.0.Final.jar!/:na]
        at org.springframework.validation.beanvalidation.LocalValidatorFactoryBean.afterPropertiesSet(LocalValidatorFactoryBean.java:248) ~[spring-context-4.3.4.RELEASE.jar!/:4.3.4.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1642) ~[spring-beans-4.3.4.RELEASE.jar!/:4.3.4.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1579) ~[spring-beans-4.3.4.RELEASE.jar!/:4.3.4.RELEASE]
        ... 45 common frames omitted
Caused by: java.io.FileNotFoundException: JAR entry !/META-INF/services/javax.validation.spi.ValidationProvider not found in /var/folders/2b/kfywdyt92x5dhdb11335m4bc0000gn/T/jar_cache3414609321058860736.tmp
        at sun.net.www.protocol.jar.JarURLConnection.connect(JarURLConnection.java:142) ~[na:1.8.0_51]
        at sun.net.www.protocol.jar.JarURLConnection.getInputStream(JarURLConnection.java:150) ~[na:1.8.0_51]
        at java.net.URL.openStream(URL.java:1038) ~[na:1.8.0_51]
        at java.util.ServiceLoader.parse(ServiceLoader.java:304) ~[na:1.8.0_51]
        ... 57 common frames omitted

Thanks

Comment From: wilkinsona

Thanks for the sample project. Interestingly, the problem doesn't occur when using jar packaging and embedding Tomcat 8.5.6.

Comment From: wilkinsona

With both Tomcat 8.5.5 and Tomcat 8.5.6 the initial URL is:

jar:war:file:/Users/awilkinson/dev/temp/spring-boot-validation-error/spring-boot-validation-error-war/target/spring-boot-validation-error-war.war*/WEB-INF/lib/hibernate-validator-5.2.4.Final.jar!/!/META-INF/services/javax.validation.spi.ValidationProvider

Things then diverge.

With 8.5.6, org.apache.catalina.webresources.war.Handler.parseURL is called and the URL becomes:

war:file:/Users/awilkinson/dev/temp/spring-boot-validation-error/spring-boot-validation-error-war/target/spring-boot-validation-error-war.war*/WEB-INF/lib/hibernate-validator-5.2.4.Final.jar

Calling openStream() fails.

With 8.5.5, WarURLStreamHandler.parseURL is called and the URL becomes:

war:jar:file:/Users/awilkinson/dev/temp/spring-boot-validation-error/spring-boot-validation-error-war/target/spring-boot-validation-error-war.war!/WEB-INF/lib/hibernate-validator-5.2.4.Final.jar

Calling openStream() works.

@markt-asf Could you take a look at this please? It looks like a regression in Tomcat. 8.5.8 appears to have the same problem.

Comment From: markt-asf

I can take a look. As an aside, that initial URL looks odd. The "...!/!/.." sequence in the middle looks wrong although I don't think it is related to this issue.

Comment From: wilkinsona

@markt-asf Thanks. I agree it looks odd. In addition to …!/!/…, the * in it is also strange. It's the same in both the working and failing case so I haven't dug into it to find out where it's coming from. I might do that now to satisfy my own curiosity if nothing else.

Comment From: markt-asf

The * I'd expect. "*/" in a war: URL is the Tomcat equivalent of "!/" in a jar: URL. If we use !/ in WAR URLs it confuses the JRE's handling of JAR URLs.

Comment From: wilkinsona

Aah, I see. Thanks. The URL is coming from a WebResource returned for a call to

WebResourceRoot.getClassLoaderResources("/META-INF/services/javax.validation.spi.ValidationProvider")

Its baseUrl is:

jar:war:file:/Users/awilkinson/dev/temp/spring-boot-validation-error/spring-boot-validation-error-war/target/spring-boot-validation-error-war.war*/WEB-INF/lib/hibernate-validator-5.2.4.Final.jar!/

And AbstractArchiveResource.getURL() does this:

baseUrl + "!/" + resource.getName()

Comment From: markt-asf

You are ahead of me. I'm still getting my test environment set up. Thanks for that. I should be able to convert that into a unit test.

Comment From: markt-asf

What do you know. That extra !/ does appear to be the issue. I have a test case for jar:war:file: but I want to add some more test cases before committing this. Should have the fix committed later today. The fix will be in the next set of releases (current ETA, around 1 month from now).

Comment From: markt-asf

I can have snapshots available sooner (i.e. shortly after the fix is committed) if that is useful.

Comment From: wilkinsona

Thanks, @markt-asf. A snapshot would be useful.

Comment From: markt-asf

Done: https://repository.apache.org/content/repositories/snapshots/org/apache/tomcat/

Comment From: wilkinsona

Thanks for the snapshots. I can confirm that they've fixed the problem reported here. Unfortunately, they've introduced a new problem that appears to be a regression in how Connectors are handled during startup. I've opened https://bz.apache.org/bugzilla/show_bug.cgi?id=60368.

Comment From: philwebb

Looks like Tomcat issue 60368 is now fixed.

Comment From: philwebb

When we close this we should also check the server port issue reported in #7615

Comment From: wilkinsona

Unfortunately there's a nasty performance regression in Tomcat 8.5.9 which adds ~4 seconds to the shut down time on macOS when Air Drop is enabled. As I understand it, other OSes with could also be affected depending on the network configuration. The problem is particularly noticeable when using DevTools as it adds ~4 seconds to the time taken for every restart. The regression's been fixed in http://svn.apache.org/viewvc?view=revision&revision=1774098.

Due to the performance degradation, we're going to have to wait for 8.5.10 to fix this issue so it's not going to make it into 1.4.3. If you're affected by this issue but won't be affected by the performance regression or think that you can live with it, overriding tomcat.version to 8.5.9 is a good option.

Comment From: wilkinsona

When the time comes, the necessary changes are available in this branch.

Comment From: xenoterracide

out of curiosity, would 8.5.7 or 8.5.8 be a valid candidate? (until 8.5.10?) because we're hitting the bug where all of the jar's are being added to the static resource cache, that was fixed in 8.5.7.

Comment From: wilkinsona

No, otherwise we would have already upgraded. We need the fix for http://bz.apache.org/bugzilla/show_bug.cgi?id=60368 which is only in 8.5.9

Comment From: wilkinsona

Still blocked. 8.5.11 has been released but it's yet to make it to Maven Central.

Comment From: philwebb

Still missing 8.5.11.

@markt-asf anything you can do to get the bits transferred?

Comment From: markt-asf

https://issues.apache.org/jira/browse/INFRA-13361

Comment From: wilkinsona

The upgrade has broken four Tomcat customisation tests. Reopening.