4

Im unable to run the generated jar file with my spring-boot with jersey project.

exception that i encounter is:

Error starting Tomcat context. Exception: org.springframework.beans.factory.UnsatisfiedDependencyException. Message: Error creating bean with name 'org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration': Unsatisfied dependency expressed through constructor parameter 1

Project runs properly when it's done via IDE (running the Main class) or when using spring-boot:run

Here are the details of the current setup:

Packaging:

jar

dependency:

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

my jersey configuration (ResourceConfig) is set to scan packages

@Component
public class JerseyConfiguration extends ResourceConfig {

    public JerseyConfiguration() {
        packages(true, "com.my.base.jaxrs.packages");
    }

}

spring-boot-maven-plugin configured as: org.springframework.boot

<artifactId>spring-boot-maven-plugin</artifactId>
  <executions>
    <execution>
      <goals>
        <goal>repackage</goal>
      </goals>
    </execution>
  </executions>
</plugin>

I also did not use the spring-boot-starter-parent but added the spring-boot-dependencies as indicated in the docs.

geneqew
  • 2,401
  • 5
  • 33
  • 48

3 Answers3

2

This is more of a workaround than an actual valid solution to use packages(true, "my.package");

in reference to Anton's answer, i settled with this solution with the limitation that it requires resources with class level @Path or @Provider annotation:

ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
        provider.addIncludeFilter(new AnnotationTypeFilter(Path.class));
        provider.addIncludeFilter(new AnnotationTypeFilter(Provider.class));
        provider.findCandidateComponents("my.package.here").forEach(beanDefinition -> {
            try {
                LOGGER.info("registering {} to jersey config", beanDefinition.getBeanClassName());
                register(Class.forName(beanDefinition.getBeanClassName()));
            } catch (ClassNotFoundException e) {
                LOGGER.warn("Failed to register: {}", beanDefinition.getBeanClassName());
            }
        });
geneqew
  • 2,401
  • 5
  • 33
  • 48
  • 1
    I came to the same solution (previously answered here: http://stackoverflow.com/a/42281515/1732450). The class level `@Path` and `@Provider` annotations aren't real limitations. See the source of `org.glassfish.jersey.server.internal.scanning.AnnotationAcceptingListener`. It's the stock solution and it also scans for the same classes as the workaround. – mihu86 Mar 17 '17 at 07:57
1

I had this problem, I did not want to complicate things too much so I just registered all my jersey controllers individually.

@Configuration
public class JerseyConfig extends ResourceConfig {

    JerseyConfig() {

        //  my old version that does not play well with spring boot fat jar        
        /*
            packages(
                    "com.mycompany.api.resources"           
            );
        */

        register(com.mycompany.api.resources.FooController.class);
        register(com.mycompany.api.resources.BarController.class);

}

NOTE: I would not recommend this for large projects with many files, it will very quickly become long and unreadable and tedious to maintain. That said, it is a working solution and you will be able to run your jar with the usual java -jar my-project.jar command.

Norbert Bicsi
  • 1,562
  • 2
  • 19
  • 33
0

Alternatively you could do,

@Configuration
public class JerseyConfig extends ResourceConfig {

    JerseyConfig() {
        BeanConfig beanConfig = new BeanConfig();
        beanConfig.setResourcePackage("com.mycompany.api.resources");
    }
}