Spring-boot: Spring Boot application runs fine with spring-boot:run but not with java -jar

Created on 25 May 2017  路  9Comments  路  Source: spring-projects/spring-boot

Spring Boot version: 1.5.3
Java: 1.8
Maven: 3.5.0
OS: Ubuntu 16.10 x64

I have a Spring Boot project here: https://github.com/aifa-gov-it/invoices-processor

I have multiple unit and integration test, marked with @SpringBootTest that run fine, as you can see from the Travis CI build logs (example: https://travis-ci.org/aifa-gov-it/invoices-processor/builds/236038253).

If I build the project with mvn clean install -s settings.xml and then run the jar with java -jar target/database-uploader-exec.jar (the -exec qualifier has been added with the qualifier configuration option of the spring-boot-maven-plugin, I get a:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'java.util.Set<it.gov.aifa.invoice_processor.service.InvoiceMappingToEntityConverter<it.gov.aifa.invoice_processor.mapping.InvoiceMapping<java.lang.String>, it.gov.aifa.invoice_processor.entity.invoice.Invoice>>' available:
expected at least 1 bean which qualifies as autowire candidate.
Dependency annotations: {@org.hibernate.validator.constraints.NotEmpty(message={org.hibernate.validator.constraints.NotEmpty.message}, payload=[], groups=[])}

The jar runs fine with the spring-boot:run goal and so do unit and integration tests, so I'm suspecting an issue with the executable JAR. I also tried to add the executable configuration option but it changed nothing.

Shouldn't the spring-boot-maven-plugin produce a bootable JAR out-of-the-box?

Relevant bits:

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>
    <groupId>it.gov.aifa</groupId>
    <artifactId>database-uploader</artifactId>
    <version>1.0.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.3.RELEASE</version>
    </parent>

    <developers>
        <developer>
            <id>ferrarimarco</id>
            <email>[email protected]</email>
            <name>Marco Ferrari</name>
            <organization>Italian Medicines Agency - AIFA</organization>
            <organizationUrl>http://www.aifa.gov.it/</organizationUrl>
        </developer>
    </developers>

    <inceptionYear>2017</inceptionYear>

    <organization>
        <name>Italian Medicines Agency - AIFA</name>
        <url>http://www.aifa.gov.it/</url>
    </organization>

    <properties>
        <!-- Environment properties -->
        <java.version>1.8</java.version>
        <maven-required.version>3.3.9</maven-required.version>
        <project.resources.sourceEncoding>UTF-8</project.resources.sourceEncoding>

        <!-- Dependencies (keep this alphabetically ordered) -->
        <commons-io.version>2.5</commons-io.version>
        <commons-lang3.version>3.5</commons-lang3.version>
        <java-ee-api.version>7.0</java-ee-api.version>
        <liquibase-hibernate5.version>3.6</liquibase-hibernate5.version>
        <mockito-all.version>2.0.2-beta</mockito-all.version>
        <ojdbc.version>12.2.0.1</ojdbc.version>
        <spring-boot.version>${project.parent.version}</spring-boot.version>
        <sysout-over-slf4j.version>1.0.2</sysout-over-slf4j.version>
        <testng.version>6.11</testng.version>

        <!-- Plugins (keep this alphabetically ordered) -->
        <coveralls-maven-plugin.version>4.3.0</coveralls-maven-plugin.version>
        <jacoco-maven-plugin.version>0.7.9</jacoco-maven-plugin.version>
        <maven-project-info-reports-plugin.version>2.9</maven-project-info-reports-plugin.version>
        <maven-release-plugin.version>2.5.3</maven-release-plugin.version>
        <maven-surefire-report-plugin.version>${maven-surefire-plugin.version}</maven-surefire-report-plugin.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.tomcat</groupId>
                    <artifactId>tomcat-jdbc</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-batch</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-oxm</artifactId>
        </dependency>
        <dependency>
            <groupId>org.liquibase</groupId>
            <artifactId>liquibase-core</artifactId>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
        </dependency>
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>${commons-lang3.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.assertj</groupId>
            <artifactId>assertj-core</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>${commons-io.version}</version>
        </dependency>
        <dependency>
            <groupId>com.oracle.jdbc</groupId>
            <artifactId>ojdbc8</artifactId>
            <version>${ojdbc.version}</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>log4j-over-slf4j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>uk.org.lidalia</groupId>
            <artifactId>sysout-over-slf4j</artifactId>
            <version>${sysout-over-slf4j.version}</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
        </dependency>
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>${testng.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-all</artifactId>
            <version>${mockito-all.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.jayway.jsonpath</groupId>
            <artifactId>json-path</artifactId>
        </dependency>
    </dependencies>

    <build>
        <finalName>${project.artifactId}</finalName>

        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-enforcer-plugin</artifactId>
                <executions>
                    <execution>
                        <id>enforce-versions</id>
                        <goals>
                            <goal>enforce</goal>
                        </goals>
                        <configuration>
                            <rules>
                                <requireMavenVersion>
                                    <version>${maven-required.version}</version>
                                </requireMavenVersion>
                                <requireJavaVersion>
                                    <version>${java.version}</version>
                                </requireJavaVersion>
                            </rules>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-failsafe-plugin</artifactId>
                <configuration>
                    <!-- Skips tests if the value of skip.unit.tests property is true -->
                    <skipTests>${skipTests}</skipTests>
                    <skipITs>${skipTests}</skipITs>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>integration-test</goal>
                            <goal>verify</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-javadoc-plugin</artifactId>
                <executions>
                    <execution>
                        <id>attach-javadocs</id>
                        <goals>
                            <goal>jar</goal>
                            <goal>test-jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <executions>
                    <execution>
                        <id>generate-test-jar</id>
                        <goals>
                            <goal>test-jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-release-plugin</artifactId>
                <version>${maven-release-plugin.version}</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
                <executions>
                    <execution>
                        <id>attach-sources</id>
                        <goals>
                            <goal>jar</goal>
                            <goal>test-jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <!-- Skips unit tests if the value of skip.unit.tests property is true -->
                    <skipTests>${skipTests}</skipTests>
                    <workingDirectory>${project.build.directory}</workingDirectory>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.eluder.coveralls</groupId>
                <artifactId>coveralls-maven-plugin</artifactId>
                <version>${coveralls-maven-plugin.version}</version>
            </plugin>
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>${jacoco-maven-plugin.version}</version>
                <executions>
                    <execution>
                        <id>default-prepare-agent</id>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>default-prepare-agent-integration</id>
                        <goals>
                            <goal>prepare-agent-integration</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>default-check</id>
                        <goals>
                            <goal>check</goal>
                        </goals>
                        <configuration>
                            <haltOnFailure>false</haltOnFailure>
                            <rules>
                                <!-- implementation is needed only for Maven 2 -->
                                <rule implementation="org.jacoco.maven.RuleConfiguration">
                                    <element>BUNDLE</element>
                                    <limits>
                                        <!-- implementation is needed only for Maven 2 -->
                                        <limit implementation="org.jacoco.report.check.Limit">
                                            <counter>COMPLEXITY</counter>
                                            <value>COVEREDRATIO</value>
                                            <minimum>0.80</minimum>
                                        </limit>
                                    </limits>
                                </rule>
                            </rules>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.liquibase</groupId>
                <artifactId>liquibase-maven-plugin</artifactId>
                <version>${liquibase.version}</version>
                <configuration>
                    <changeLogFile>src/main/resources/db/changelog/db.changelog-master.yaml</changeLogFile>
                    <diffChangeLogFile>src/main/resources/db/changelog/db.changelog-${project.version}.yaml</diffChangeLogFile>
                    <driver>org.h2.Driver</driver>
                    <outputFileEncoding>${project.resources.sourceEncoding}</outputFileEncoding>
                    <referenceUrl>hibernate:spring:it.gov.aifa.invoice_processor.entity?dialect=org.hibernate.dialect.Oracle12cDialect&amp;hibernate.physical_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy</referenceUrl>
                    <url>jdbc:h2:mem:testdb</url>
                    <username>sa</username>
                    <password>sa</password>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.liquibase.ext</groupId>
                        <artifactId>liquibase-hibernate5</artifactId>
                        <version>${liquibase-hibernate5.version}</version>
                    </dependency>
                    <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-data-jpa</artifactId>
                        <version>${spring-boot.version}</version>
                        <exclusions>
                            <exclusion>
                                <groupId>org.apache.tomcat</groupId>
                                <artifactId>tomcat-jdbc</artifactId>
                            </exclusion>
                        </exclusions>
                    </dependency>
                    <dependency>
                        <groupId>org.hibernate</groupId>
                        <artifactId>hibernate-validator</artifactId>
                        <version>${hibernate-validator.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <classifier>exec</classifier>
                    <executable>true</executable>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <reporting>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-report-plugin</artifactId>
                <version>${maven-surefire-report-plugin.version}</version>
                <reportSets>
                    <reportSet>
                        <id>unit-tests</id>
                        <reports>
                            <report>report-only</report>
                        </reports>
                    </reportSet>
                    <reportSet>
                        <id>integration-tests</id>
                        <reports>
                            <report>failsafe-report-only</report>
                        </reports>
                    </reportSet>
                </reportSets>
            </plugin>
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <reportSets>
                    <reportSet>
                        <id>jacoco-unit-tests</id>
                        <reports>
                            <report>report</report>
                        </reports>
                    </reportSet>
                    <reportSet>
                        <id>jacoco-integration-tests</id>
                        <reports>
                            <report>report-integration</report>
                        </reports>
                    </reportSet>
                </reportSets>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-javadoc-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-project-info-reports-plugin</artifactId>
                <version>${maven-project-info-reports-plugin.version}</version>
            </plugin>
        </plugins>
    </reporting>
</project>
invalid

Most helpful comment

This is quite a complicated one, but doesn't actually have anything to do with Spring Boot. The reason for the different behaviour isn't due to a difference in mvn spring-boot:run vs java -jar specifically, but due to a difference in the ordering of the class path. In both cases it's governed by Maven.

We can conclude from mvn spring-boot:run working and java -jar failing that Maven uses a different ordering for the classes when running and when packing them in a jar file. It's also interesting that the jar that I built (which works) has its contents in a different order to those in the jar that you built (which doesn't). From that, we can conclude that ordering of classes in a Maven-built jar may vary as well.

The ordering of the class path is important as it has an effect on when the beans in your application are created. When Spring Framework is looking at a bean instance it has more information available to it about the bean's type than it does when it's only looking at a bean definition. The injection that's failing is reliant upon the resolution of a fairly complex generic type signature and this only succeeds when the Invoice1_2MappingToEntityConverterImpl bean has been instantiated and the Framework can examine an instance of this bean rather than just its definition.

In the failing case, the injection of Set<InvoiceMappingToEntityConverter<InvoiceMapping<String>, Invoice>> into InvoiceMappingProcessor fails because it is happening before Invoice1_2MappingToEntityConverterImpl has been instantiated. In the successful case, the injection succeeds as Invoice1_2MappingToEntityConverterImpl has already been instantiated.

In the case of the two different jars, this difference in ordering is due to the different ordering of the entries in the jar:

    42617  05-25-2017 20:01   BOOT-INF/classes/it/gov/aifa/invoice_processor/service/impl/Invoice1_2MappingToEntityConverterImpl.class
     3882  05-25-2017 20:01   BOOT-INF/classes/it/gov/aifa/invoice_processor/service/impl/InvoiceMappingProcessor.class

vs

     3882  05-25-2017 22:08   BOOT-INF/classes/it/gov/aifa/invoice_processor/service/impl/InvoiceMappingProcessor.class
    42617  05-25-2017 22:08   BOOT-INF/classes/it/gov/aifa/invoice_processor/service/impl/Invoice1_2MappingToEntityConverterImpl.class

If I rename InvoiceMappingProcessor to AnInvoiceMappingProcessor I can reproduce the injection failure in Eclipse as it causes the processor bean to be created before the converter bean as the processor then appears first on the class path.

There may be an improvement that could be made in Spring Framework here, but I really can't tell for certain. If you'd like to pursue that, I would recommend stripping your application down as much as possible to a bare minimum that reproduces the problem and then opening a Spring Framework JIRA.

All 9 comments

<executable>true</executable> means create a truly executable jar (no java -jar needed). http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#deployment-install

Is that what you wanted?

Both the java -jar and the truly executable jar approaches are fine with me, but unfortunately neither worked :(

Thanks

I had to remove the dependency on Oracle's JDBC driver (401 response from Oracle's Maven repository), but other than that your app works fine for me:

$ java -jar target/database-uploader-exec.jar






               &&&:          8&&*          oooooooooooooooooo####
              #####          ###:         &&&&&&&&&&&&&&&&&&8####:
              ## ###         ###:         &&&               @#####
             ### ###         ###:        &&&               ###* ###
            @##*  ###        ###:       :&&&               ###  ####
            ###   o###       ###:       &&&               ###    ###
           ##@     ###*      ###:      8&&               ###@    @###
          8###      #@@      ###:     &&&8               @##      ###*
          ###       ####     ###:     &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
         ###         ###     ###:    &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&8
        &###         ####    ###:   &&8                ###          ###8
        ##################   ###:  *&&8               ####          8###
       ###############@###   ###:  &&8                ###            ####
       ###             ####  ###: &&&                ###:             ###o
      ####              #### ###: 8&8               ####              ####
     &###               #### ###:&&&                ###                ####





Database Uploader: upload data from source data files to the configured database.
OPTIONS
   --help Shows this help text.

   --import-mov-delimited-file Uploads data from a Delimiter Separated Value (DSV) file. Specify a path with the --path argument. Supports the parsing files with ';' as delimiter and the following header: CODICE_TIPO_MITTENTE;CODICE_MITTENTE;CODICE_TIPO_DESTINATARIO;CODICE_DESTINATARIO;CODICE_TIPO_COMMITTENTE;CODICE_COMMITTENTE;CODICE_TIPO_INTESTAT_FATTURA;CODICE_INTESTAT_FATTURA;CODICE_TIPO_DOCUMENTO;NUMERO_DOCUMENTO;DATA_TRASMISSIONE;ORA_TRASMISSIONE;CODICE_MOVIMENTO;AIC;LOTTO;DATA_SCADENZA;QUANTITA;VALORE

   --import-invoices Uploads data from XML files to the Database. Specify a path with the --path argument.

Perhaps you could share a pre-built jar somewhere that doesn't work?

Thanks @wilkinsona https://www.dropbox.com/s/zcwzkoghn3i76g0/database-uploader-exec.jar?dl=1

Here it is. I removed the OJDBC dependency before building it

UPDATE: here is a verbose log after running that JAR https://www.dropbox.com/s/cw0kitilhw48isj/ConEmu-2017-05-25-p10588.log?dl=1

This is quite a complicated one, but doesn't actually have anything to do with Spring Boot. The reason for the different behaviour isn't due to a difference in mvn spring-boot:run vs java -jar specifically, but due to a difference in the ordering of the class path. In both cases it's governed by Maven.

We can conclude from mvn spring-boot:run working and java -jar failing that Maven uses a different ordering for the classes when running and when packing them in a jar file. It's also interesting that the jar that I built (which works) has its contents in a different order to those in the jar that you built (which doesn't). From that, we can conclude that ordering of classes in a Maven-built jar may vary as well.

The ordering of the class path is important as it has an effect on when the beans in your application are created. When Spring Framework is looking at a bean instance it has more information available to it about the bean's type than it does when it's only looking at a bean definition. The injection that's failing is reliant upon the resolution of a fairly complex generic type signature and this only succeeds when the Invoice1_2MappingToEntityConverterImpl bean has been instantiated and the Framework can examine an instance of this bean rather than just its definition.

In the failing case, the injection of Set<InvoiceMappingToEntityConverter<InvoiceMapping<String>, Invoice>> into InvoiceMappingProcessor fails because it is happening before Invoice1_2MappingToEntityConverterImpl has been instantiated. In the successful case, the injection succeeds as Invoice1_2MappingToEntityConverterImpl has already been instantiated.

In the case of the two different jars, this difference in ordering is due to the different ordering of the entries in the jar:

    42617  05-25-2017 20:01   BOOT-INF/classes/it/gov/aifa/invoice_processor/service/impl/Invoice1_2MappingToEntityConverterImpl.class
     3882  05-25-2017 20:01   BOOT-INF/classes/it/gov/aifa/invoice_processor/service/impl/InvoiceMappingProcessor.class

vs

     3882  05-25-2017 22:08   BOOT-INF/classes/it/gov/aifa/invoice_processor/service/impl/InvoiceMappingProcessor.class
    42617  05-25-2017 22:08   BOOT-INF/classes/it/gov/aifa/invoice_processor/service/impl/Invoice1_2MappingToEntityConverterImpl.class

If I rename InvoiceMappingProcessor to AnInvoiceMappingProcessor I can reproduce the injection failure in Eclipse as it causes the processor bean to be created before the converter bean as the processor then appears first on the class path.

There may be an improvement that could be made in Spring Framework here, but I really can't tell for certain. If you'd like to pursue that, I would recommend stripping your application down as much as possible to a bare minimum that reproduces the problem and then opening a Spring Framework JIRA.

@oratengG4S this issue has been closed as invalid and Andy just gave a detailed explanation in the comment just above yours. As mentioned in the guidelines for contributing, we prefer to use GitHub issues only for bugs and enhancements. Please ask your question on StackOverflow.

i have same problem with java -jar. it not working properly like spring-boot:run

@romeo16971 "not working properly" is unlikely to provide enough information for anyone to be able to help you. If you would like some help, please ask on Stack Overflow and provide a minimal, complete, and verifiable example of your problem.

@wilkinsona I solved the problem. I use jsf ( i knew jsf is stateful but customer's requirement ) spring boot for my project. I add folder "META-INF/resources" under "src/main/resources" in order to act like "webapp" like normal maven web project. When i run it in "mvn spring-boot:run" or run project in IDE, it works perfectly but when i build it to jar file to distribute to EC2. It not read "faces-config.xml" under "META-INF/resources/WEB-INF". Thus resource-bundle inside faces-config.xml was not setup. So i move it in "META-INF" forlder and it worked. Any one got problem ?? please tell me why

NOT Work
src/main/resource
---------------------META-INF
-------------------------resources
-----------------------------WEB-INFO
---------------------------------faces-config.xml

Work
src/main/resource
---------------------META-INF
-------------------------faces-config.xml
-------------------------resources
-----------------------------WEB-INFO

Was this page helpful?
0 / 5 - 0 ratings