5

I'm trying to package my Spring Boot App which uses Jersey. When the app is launched during development it has no problems to run, the problem comes when I generate a jar file using

mvnw package && java -jar target/gs-spring-boot-docker-0.1.0.jar

Which produces the following error.

Error creating bean with name 'org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration': Unsatisfied depend ency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jerseyConfig' defined in URL [jar:file:..path/Backend/target/celulascontentas-2.0.jar!/BOOT-INF/classes!/tech/aabo/celulascontenta s/config/JerseyConfig.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [tech.aabo.ce lulascontentas.config.JerseyConfig]: Constructor threw exception; nested exception is org.glassfish.jersey.server.internal.scanning.ResourceFinderException: java.io.File NotFoundException: ..path\Backend\target\celulascontentas-2.0.jar!\BOOT-INF\classes (The system cannot find the path s pecified)

My Jersey Config looks like this:

package tech.aabo.celulascontentas.config;

import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.ServerProperties;
import org.springframework.stereotype.Component;

import javax.ws.rs.ApplicationPath;

@Component
@ApplicationPath("/api")
public class JerseyConfig extends ResourceConfig {

    public JerseyConfig() {
        register(JacksonJaxbJsonProvider.class);
        packages("tech.aabo.celulascontentas.endpoint");
        property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
    }
}

And my pom.xml looks like:

<?xml version="1.0" encoding="UTF-8"?>
<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>tech.aabo</groupId>
    <artifactId>celulascontentas</artifactId>
    <version>2.0</version>
    <packaging>jar</packaging>

    <name>celulascontentas</name>
    <description>API para celulas contentas</description>

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

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!-- Core -->

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jersey</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>

        <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <!-- DB -->

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!-- Extra -->

        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.9.3</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.7</version>
        </dependency>

        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-java-sdk</artifactId>
            <version>1.11.133</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-resources</id>
                        <phase>validate</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${basedir}/target/</outputDirectory>
                            <resources>
                                <resource>
                                    <directory>src/main/resources</directory>
                                    <filtering>true</filtering>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

I have tried various combinations but it always produces the same error. Those anybody now how to fix it?

Thanks

HFR1994
  • 536
  • 1
  • 5
  • 16

1 Answers1

3

Jersey classpath scanning limitations

The change to the layout of executable jars means that a limitation in Jersey’s classpath scanning now affects executable jar files as well as executable war files. To work around the problem, classes that you wish to be scanned by Jersey should be packaged in a jar and included as a dependency in BOOT-INF/lib. The Spring Boot launcher should then be configured to unpack those jars on start up so that Jersey can scan their contents.

This is a known problem and there is a open pull request that's not merged yet. I suggest you refer this issue which mentions some workarounds.

There are few workarounds

  1. Configure Boot's Maven plugin to unpack the jars containing that package

  2. Use the below workaround

jersey 1:

import java.util.Map;

import javax.annotation.PostConstruct;
import javax.ws.rs.Path;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import com.sun.jersey.api.core.DefaultResourceConfig;

@Component
public class RestApplication extends DefaultResourceConfig {

    private static final Logger log = LoggerFactory.getLogger(RestApplication.class);

    public RestApplication() {
        getFeatures().put("com.sun.jersey.api.json.POJOMappingFeature", true);
    }

    @Autowired
    ApplicationContext appCtx;

    @PostConstruct
    public void setup() {
        log.info("Rest classes found:");
        Map<String,Object> beans = appCtx.getBeansWithAnnotation(Path.class);
        for (Object o : beans.values()) {
            log.info(" -> " + o.getClass().getName());
            getSingletons().add(o);
        }
    }

}
and

    @Autowired
    RestApplication restApplication;

    @Bean
    public ServletRegistrationBean jersey() {
        ServletRegistrationBean bean = new ServletRegistrationBean();
        bean.setServlet(new ServletContainer(restApplication));
        bean.addInitParameter("com.sun.jersey.api.json.POJOMappingFeature", "true");
        bean.setUrlMappings(Arrays.asList("/rest/*"));
        return bean;
    }
jersery2:

import java.util.Map;

import javax.annotation.PostConstruct;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.Path;

import org.glassfish.jersey.server.ResourceConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import com.sun.jersey.api.core.ResourceConfig;

@Component
@ApplicationPath("/rest")
public class JerseyConfig extends ResourceConfig {

    private static final Logger log = LoggerFactory.getLogger(JerseyConfig.class);

    @Autowired
    ApplicationContext appCtx;

    @PostConstruct
    public void setup() {
        log.info("Rest classes found:");
        Map<String,Object> beans = appCtx.getBeansWithAnnotation(Path.class);
        for (Object o : beans.values()) {
            log.info(" -> " + o.getClass().getName());
            register(o);
        }
    }

}
Community
  • 1
  • 1
Vikram Palakurthi
  • 2,406
  • 1
  • 27
  • 30