JAX-RS不适用于Spring Boot 1.4.1

时间:2016-10-07 06:07:36

标签: java maven spring-boot jax-rs

我正在尝试使用Spring Boot 1.4.1.RELEASE开发一个简单的基于JAX-RS的Web服务。但是得到这个例外 -

java.lang.IllegalStateException: No generator was provided and there is no default generator registered
at org.glassfish.hk2.internal.ServiceLocatorFactoryImpl.internalCreate(ServiceLocatorFactoryImpl.java:308) ~[hk2-api-2.5.0-b05.jar:na]
at org.glassfish.hk2.internal.ServiceLocatorFactoryImpl.create(ServiceLocatorFactoryImpl.java:268) ~[hk2-api-2.5.0-b05.jar:na]
at org.glassfish.jersey.internal.inject.Injections._createLocator(Injections.java:138) ~[jersey-common-2.23.2.jar:na]
at org.glassfish.jersey.internal.inject.Injections.createLocator(Injections.java:123) ~[jersey-common-2.23.2.jar:na]
at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:330) ~[jersey-server-2.23.2.jar:na]
at org.glassfish.jersey.servlet.WebComponent.<init>(WebComponent.java:392) ~[jersey-container-servlet-core-2.23.2.jar:na]
at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:177) ~[jersey-container-servlet-core-2.23.2.jar:na]
at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:369) ~[jersey-container-servlet-core-2.23.2.jar:na]

以下是我的计划详情 -

POM.xml中包含的依赖项 -

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

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

这是JerseyConfig文件 -

package com.test.main;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.stereotype.Component;
import com.test.resources.TutorialResource;

@Component
public class JerseyConfig extends ResourceConfig{
    public JerseyConfig() {
        register(TutorialResource.class);
        packages("com.test.resources");
    }
}

3 个答案:

答案 0 :(得分:14)

  

重要说明:在最新版本的Spring Boot中看起来不存在此问题。但是,当您想要使用Spring Boot和Jersey创建应用程序时,此答案的内容仍可用作指南。

JAR的布局在Spring Boot 1.4.1

中发生了变化

Spring Boot 1.4.1中的layout of executable jars has changed:应用程序的依赖项现在打包在BOOT-INF/lib而不是lib中,而应用程序自己的类现在打包在BOOT-INF/classes而不是BOOT-INF/lib中。罐子的根。它会影响泽西岛:

  

Jersey classpath scanning limitations

     

对可执行jar的布局的更改意味着limitation in Jersey’s classpath scanning现在影响可执行jar文件以及可执行war文件。要解决此问题,您希望由Jersey扫描的类应打包在jar中,并作为依赖项包含在pom.xml中。然后,Spring Boot启动程序应为configured to unpack those jars on start up,以便Jersey可以扫描其内容。

我发现注册类而不是包工作。请参阅下面使用Spring Boot和Jersey创建应用程序的步骤。

使用Spring Boot和Jersey

创建Web应用程序

确保您的spring-boot-starter-parent文件将<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.1.RELEASE</version> </parent> 声明为父项目:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</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-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

您还需要以下依赖项:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

Spring Boot Maven插件:

GET

出于示例目的,创建使用@Path注释的Jersey资源类,并定义处理@Path("/greetings") public class GreetingResource { @GET @Produces(MediaType.TEXT_PLAIN) public Response getGreeting() { return Response.ok("Hello, World!").build(); } } 请求的资源方法,生成text/plain

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

    @PostConstruct
    private void init() {
        registerClasses(GreetingResource.class);
    }
}

然后创建一个扩展ResourceConfigApplication的类来注册Jersey资源并使用@ApplicationPath对其进行注释。注册类而不是注册包与Spring Boot 1.4.1一起使用:

@SpringBootApplication
public class Application {

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

最后创建一个Spring Boot类来执行应用程序:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class GreetingResourceTest {

    @LocalServerPort
    private int port;

    private URI uri;

    @Before
    public void setUp() throws Exception {
        this.uri = new URI("http://localhost:" + port);
    }

    @Test
    public void testGreeting() {

        Client client = ClientBuilder.newClient();
        Response response = client.target(uri).path("api").path("greetings")
                                  .request(MediaType.TEXT_PLAIN).get();

        String entity = response.readEntity(String.class);
        assertEquals("Hello, World!", entity);
    }
}

如果您想测试此网络服务,可以使用JAX-RS Client API

pom.xml

要编译并运行该应用程序,请按以下步骤操作:

  • 打开命令行窗口或终端。
  • 导航到mvn clean compile所在的项目的根目录。
  • 编译项​​目:mvn package
  • 打包应用程序:spring-jersey-1.0-SNAPSHOT.jar
  • 查看目标目录。您应该看到一个包含以下名称或类似名称的文件:java -jar spring-jersey-1.0-SNAPSHOT.jar
  • 转到目标目录。
  • 执行JAR:http://localhost:8080/api/greetings
  • 应用程序应在{{1}}。
  • 上提供

注1:查看Spring Boot文档。有section dedicated to Jersey

注2:生成JSON时,请确保您拥有JSON provider registeredResourceConfig应该注意这一点(只需确保依赖关系在类路径上)。

答案 1 :(得分:6)

虽然Jersey无法在新版本的胖启动jar中扫描你的类,但使用Spring类路径扫描工具可以达到同样的效果。这样,您可以类似于ResourceConfig.packages()扫描包:

ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter(new AnnotationTypeFilter(Provider.class));
scanner.addIncludeFilter(new AnnotationTypeFilter(Path.class));
config.registerClasses(scanner.findCandidateComponents("your.package.to.scan").stream()
            .map(beanDefinition -> ClassUtils.resolveClassName(beanDefinition.getBeanClassName(), config.getClassLoader()))
            .collect(Collectors.toSet()));

注意:请查看org.glassfish.jersey.server.internal.scanning.AnnotationAcceptingListener的来源。这是库存解决方案,您可以看到它执行相同的操作:它会扫描使用@Path@Provider注释的类(但由于扫描机制损坏,无法找到任何内容)。 / p>

<强>更新

我有一个自定义配置,它没有扩展ResourceConfig,但是将它的实例作为bean返回。 如果您查看官方Spring example,可以将上面的代码插入JerseyConfig()构造函数(而不是两个register(...)调用)。唯一的区别是,您只需在构造函数中调用config.registerClasses(...),而不是调用registerClasses(...)

答案 2 :(得分:0)

我认为您应该使用@Configuration而不是@Componentdocument.getElementById("parent").addEventListener("keyup", function (event){ if(event.target.className == 'inp') { //your code } else{ //for other inner elements event.preventDefault(); //prevents the default action event.stopPropagation(); //stop bubbling up } } 进行注释。