New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EL dependencies missing in spring-boot-starter #2293

Closed
romainmoreau opened this Issue Jan 6, 2015 · 19 comments

Comments

Projects
None yet
10 participants
@romainmoreau

romainmoreau commented Jan 6, 2015

In http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-external-config-validation, it's stated that "Spring Boot will attempt to validate external configuration, by default using JSR-303 (if it is on the classpath).".

It's not always the case as this code can reproduce :

  • pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.0.RELEASE</version>
    </parent>
    <groupId>fr.romainmoreau.test</groupId>
    <artifactId>test</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
        </dependency>
    </dependencies>
</project>
  • TestApplication.java
package fr.romainmoreau.test;

import javax.validation.constraints.Min;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableConfigurationProperties
public class TestApplication {
    public class TestProperties {
        @Min(3)
        private int value;

        public int getValue() {
            return value;
        }

        public void setValue(int value) {
            this.value = value;
        }
    }

    @Bean
    @ConfigurationProperties(prefix = "test")
    public TestProperties testProperties() {
        return new TestProperties();
    }

    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }
}
  • application.properties
test=4

When runned, this sample will produce the following stack trace :

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor': Invocation of init method failed; nested exception is javax.validation.ValidationException: Unable to instantiate Configuration.
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1566)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198)
    at org.springframework.context.support.PostProcessorRegistrationDelegate.registerBeanPostProcessors(PostProcessorRegistrationDelegate.java:199)
    at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:615)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:465)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:321)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:961)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:950)
    at fr.romainmoreau.test.TestApplication.main(TestApplication.java:34)
Caused by: javax.validation.ValidationException: Unable to instantiate Configuration.
    at javax.validation.Validation$GenericBootstrapImpl.configure(Validation.java:279)
    at org.springframework.validation.beanvalidation.LocalValidatorFactoryBean.afterPropertiesSet(LocalValidatorFactoryBean.java:223)
    at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor$Jsr303ValidatorFactory.run(ConfigurationPropertiesBindingPostProcessor.java:361)
    at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.afterPropertiesSet(ConfigurationPropertiesBindingPostProcessor.java:174)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1625)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1562)
    ... 14 common frames omitted
Caused by: javax.validation.ValidationException: HV000183: Unable to load 'javax.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath
    at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.<init>(ResourceBundleMessageInterpolator.java:172)
    at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.<init>(ResourceBundleMessageInterpolator.java:118)
    at org.hibernate.validator.internal.engine.ConfigurationImpl.<init>(ConfigurationImpl.java:110)
    at org.hibernate.validator.internal.engine.ConfigurationImpl.<init>(ConfigurationImpl.java:86)
    at org.hibernate.validator.HibernateValidator.createGenericConfiguration(HibernateValidator.java:41)
    at javax.validation.Validation$GenericBootstrapImpl.configure(Validation.java:276)
    ... 19 common frames omitted
@wilkinsona

This comment has been minimized.

Member

wilkinsona commented Jan 6, 2015

There's nothing in spring-boot-starter that requires or uses EL so it doesn't make sense for it to depend on an EL implementation.

From the Hibernate Validator getting started page:

When your application runs in a Java EE container such as WildFly, an EL implementation is already provided by the container. In a Java SE environment, however, you have to add an implementation as dependency to your POM file.

You need to add your own EL dependency. Alternatively, spring-boot-starter-web pulls in Tomcat's EL implementation.

@wilkinsona wilkinsona closed this Jan 6, 2015

@dsyer dsyer reopened this Feb 9, 2015

@dsyer

This comment has been minimized.

Member

dsyer commented Feb 9, 2015

I see this quite a lot:

...
Caused by: javax.validation.ValidationException: Unable to instantiate Configuration.
    at javax.validation.Validation$GenericBootstrapImpl.configure(Validation.java:279)
    at org.springframework.validation.beanvalidation.LocalValidatorFactoryBean.afterPropertiesSet(LocalValidatorFactoryBean.java:223)
    at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor$Jsr303ValidatorFactory.run(ConfigurationPropertiesBindingPostProcessor.java:381)
    at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.afterPropertiesSet(ConfigurationPropertiesBindingPostProcessor.java:174)
...

That's what happens if isJsr303Present() is true but there actually is no implementation present. Since the validation API can be added independently it's easy to get this exception and be confused. As far as I know it doesn't come from any combination of Spring Boot starters, but starters plus anything that uses JSR 303 without specifying the implementation is broken.

@philwebb philwebb added this to the 1.2.2 milestone Feb 9, 2015

@wilkinsona

This comment has been minimized.

Member

wilkinsona commented Feb 11, 2015

@dsyer Which validation API jar did you have on the classpath to produce that failure? With javax.validation:validation-api:1.1.0.Final the exception message is helpful:

Caused by: javax.validation.ValidationException: Unable to create a Configuration, because no Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath.
    at javax.validation.Validation$GenericBootstrapImpl.configure(Validation.java:271)
    at org.springframework.validation.beanvalidation.LocalValidatorFactoryBean.afterPropertiesSet(LocalValidatorFactoryBean.java:223)
    at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor$Jsr303ValidatorFactory.run(ConfigurationPropertiesBindingPostProcessor.java:381)
    at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.afterPropertiesSet(ConfigurationPropertiesBindingPostProcessor.java:175)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1625)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1562)
    ... 14 more
@dsyer

This comment has been minimized.

Member

dsyer commented Feb 11, 2015

It's a transitive thing I think. Hibernate validator can work without EL (I think), but certain classpath combinations cause it to barf if there is no EL implementation available. We include Tomcat EL in spring-boot-starter-web so we hardly ever see this in a web app, at least with the default container. Try doing anything standalone with the raw Netflix stack (for instance). I'll have a go at reproducing it when I get back to me desk if you want.

@wilkinsona

This comment has been minimized.

Member

wilkinsona commented Feb 11, 2015

This confused me:

That's what happens if isJsr303Present() is true but there actually is no implementation present

I think you actually get that exception if JSR 303 API and Hibernate Validator is present but there's no EL implementation on the classpath. As I noted above Hibernate Validator 5 requires EL but doesn't pull it in transitively. I still don't think we should add EL to spring-boot-starter.

I guess we could check for the presence of Hibernate Validator and, if it's there, also check for an EL implementation but I'm not sure that would be much better than the message that Hibernate Validator already produces:

HV000183: Unable to load 'javax.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath

What did you expect the behaviour to be when the classpath's incomplete in this way?

@dsyer

This comment has been minimized.

Member

dsyer commented Feb 11, 2015

OK you're right. It does tend to send people off down a rabbit hole, but there probably isn't any way for us to make it any better.

@dsyer dsyer closed this Feb 11, 2015

@yarix

This comment has been minimized.

yarix commented Mar 16, 2015

adding the EL to dependency management spring-boot-dependencies can help a bit.

javax.el javax.el-api 2.2.4 org.glassfish.web javax.el 2.2.4
@dsyer

This comment has been minimized.

Member

dsyer commented Mar 16, 2015

We already have the tomcat implementation in dependency management.

@megascus

This comment has been minimized.

megascus commented Mar 18, 2015

I`m in trouble on using the spring-boot-starter-batch.

spring-boot-starter-batch is not contains javax.validation and the tomcat implementation.
so, not to use 23.7.3 @ConfigurationProperties Validation.
http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-validation

@wilkinsona

This comment has been minimized.

Member

wilkinsona commented Mar 18, 2015

@megascus We choose not to assume that all Batch applications will want to use validation. You should add the EL dependencies to your pom yourself.

@philwebb philwebb removed this from the 1.2.2 milestone Mar 22, 2015

@GKTheOne

This comment has been minimized.

GKTheOne commented May 21, 2015

So what should I be adding to my pom when I get this error? (Got it now, and this is the top google search hit)

(Should mention that I'm doing a command-line app)

@dsyer

This comment has been minimized.

Member

dsyer commented May 21, 2015

Lie it says above: you need to add an EL implementation (assuming you are using EL - if you are not I would look into what else you aren't using that is on the classpath). We recommend the tomcat implementation "org.apache.tomcat.embed:tomcat-embed-el", but only because it's what you get if you use our starters.

@romainmoreau

This comment has been minimized.

romainmoreau commented May 21, 2015

Note that the Hibernate Validator reference suggests to use the Glassfish implementation :
http://docs.jboss.org/hibernate/validator/5.1/reference/en-US/html_single/#validator-gettingstarted-uel

@GKTheOne

This comment has been minimized.

GKTheOne commented May 21, 2015

Excellent. Thank you gentle peoples :)

@rajjaiswalsaumya

This comment has been minimized.

rajjaiswalsaumya commented Sep 6, 2015

Using Intellij and running Spring initializr to create Boot Project, the basic pom that intellij created for me is


4.0.0

<groupId>org.cdac</groupId>
<artifactId>spring-boot-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>

<name>spring-boot-demo</name>
<description>Demo project for Spring Boot</description>

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.2.5.RELEASE</version>
    <relativePath/>
    <!-- lookup parent from repository -->
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.7</java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-jasper</artifactId>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

But i get Caused by: javax.validation.ValidationException: HV000183: Unable to load 'javax.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath

Im confused, if im using default tomcat implementation how come, javax.el is required ?

@dsyer

This comment has been minimized.

Member

dsyer commented Sep 6, 2015

Are you running from your main method? That should work. If you run in a container you probably have to add the EL jar back in runtime scope.

@rajjaiswalsaumya

This comment has been minimized.

rajjaiswalsaumya commented Sep 6, 2015

im running with main. The same application with same pom ran on STS. Something not sure why this is happening?

@snicoll

This comment has been minimized.

Member

snicoll commented Sep 7, 2015

Provided dependencies are not added in the classpath when you run your main method from Intellij IDEA. This is a known bug and I hope they'll fix it in 15.

@dowlingw

This comment has been minimized.

dowlingw commented Sep 8, 2015

IntelliJ Bug referenced by @snicoll can be found here:
https://youtrack.jetbrains.com/issue/IDEA-107048

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment