我正在尝试使用Jersey + Jetty和Spring设置一个简单的REST应用程序,以设置用于自动装配的bean。我也在通过Gradle进行管理。
我有2个主要端点/users
和/greeting
。
GET
上的/greeting
仅返回文本响应并且可以正常工作。那里没有自动装配的依赖关系。
但是,如果我在/users
端点上执行get操作,则会使用应在spring之前注入的API类返回响应。该部分失败,因此,每当我呼叫该端点时,我都会得到一个NullPointerException
。
要注意的另一点是,我要使用运动衫1.12和春季4.2.0。原因是,这将是我必须在其他地方插入的原型。
在/ users上执行GET时发生异常:
java.lang.NullPointerException
at com.hateos.spring.test01.resources.user.controller.UserController.getAllUsers(UserController.java:35)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$TypeOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:185)
at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:288)
at com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108)
at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
at com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1483)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1414)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1363)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1353)
at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:414)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:708)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:841)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:535)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:188)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1253)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:168)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:166)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1155)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
at org.eclipse.jetty.server.Server.handle(Server.java:564)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:317)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:251)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:110)
at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124)
at org.eclipse.jetty.util.thread.Invocable.invokePreferred(Invocable.java:128)
at org.eclipse.jetty.util.thread.Invocable$InvocableExecutor.invoke(Invocable.java:222)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:294)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.produce(EatWhatYouKill.java:126)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:673)
at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:591)
at java.lang.Thread.run(Thread.java:748)
19-03-20 15:10:59:694 WARN qtp1567581361-16 server.HttpChannel:517 - /users
java.lang.NullPointerException
at com.hateos.spring.test01.resources.user.controller.UserController.getAllUsers(UserController.java:35)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$TypeOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:185)
at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:288)
at com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108)
at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
at com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1483)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1414)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1363)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1353)
at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:414)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:708)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:841)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:535)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:188)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1253)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:168)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:166)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1155)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
at org.eclipse.jetty.server.Server.handle(Server.java:564)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:317)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:251)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:110)
at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124)
at org.eclipse.jetty.util.thread.Invocable.invokePreferred(Invocable.java:128)
at org.eclipse.jetty.util.thread.Invocable$InvocableExecutor.invoke(Invocable.java:222)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:294)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.produce(EatWhatYouKill.java:126)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:673)
at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:591)
at java.lang.Thread.run(Thread.java:748)
项目结构如下(跳过不相关的文件):
hateos-spring-test01
|- src
| |- main
| | |- java
| | | |- com.hateos.spring.test01 (nested folders)
| | | |- resources
| | | | |- greeting
| | | | |- user
| | | | |- api
| | | | | |- impl
| | | | | | |- UserAPIImpl.java
| | | | | |- UserAPI.java
| | | | |- controller
| | | | |- UserController.java
| | | | |- exception
| | | | |- model
| | | | |- User.java
| | | | |- UserList.java
| | | |- MyApplication.java
| | |- resources
| | |- hateos-spring-test01.xml
| | |- log4j.properties
| |- test
|- build.gradle
|- gradlew
|- gradlew.bat
|- settings.gradle
build.gradle:
apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'com.github.johnrengelman.shadow'
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
mainClassName = 'com.hateos.spring.test01.MyApplication'
ext {
jettyVersion = '9.4.6.v20170531'
}
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.1'
}
}
repositories {
jcenter()
mavenCentral()
}
dependencies {
compile 'org.slf4j:slf4j-api:1.6.6'
compile 'org.slf4j:slf4j-log4j12:1.6.6'
compile "org.codehaus.jackson:jackson-core-asl:1.9.2"
compile "org.codehaus.jackson:jackson-jaxrs:1.9.2"
compile "org.codehaus.jackson:jackson-mapper-asl:1.9.2"
compile "org.codehaus.jackson:jackson-xc:1.9.2"
compile "com.sun.jersey:jersey-client:1.12"
compile "com.sun.jersey:jersey-core:1.12"
compile "com.sun.jersey:jersey-json:1.12"
compile "com.sun.jersey:jersey-server:1.12"
compile "com.sun.jersey:jersey-servlet:1.12"
compile "org.codehaus.jettison:jettison:1.1"
compile "org.eclipse.jetty:jetty-server:${jettyVersion}"
compile "org.eclipse.jetty:jetty-servlet:${jettyVersion}"
compile 'org.springframework:spring-core:4.2.0.RELEASE'
compile 'org.springframework:spring-web:4.2.0.RELEASE'
compile 'org.springframework.hateoas:spring-hateoas:0.25.1.RELEASE'
compile 'org.springframework:spring-beans:4.2.0.RELEASE'
compile 'org.springframework:spring-context:4.2.0.RELEASE'
compile 'org.springframework:spring-context-support:4.2.0.RELEASE'
testCompile group: 'junit', name: 'junit', version: '4.12'
}
spring xml文件(hateos-spring-text.xml):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.hateos.spring.test01"/>
<bean id="usersAPI" class="com.hateos.spring.test01.resources.user.api.impl.UserAPIImpl"/>
<bean id="usersController" class="com.hateos.spring.test01.resources.user.controller.UserController" />
</beans>
MyApplication.java
package com.hateos.spring.test01;
import com.sun.jersey.spi.container.servlet.ServletContainer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyApplication {
private static final Logger logger = LoggerFactory.getLogger(MyApplication.class);
public static void main(String[] args) {
logger.info("Hi guys!");
Server server = new Server(9090);
ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
servletContextHandler.setContextPath("/");
server.setHandler(servletContextHandler);
ServletHolder servletHolder = servletContextHandler.addServlet(ServletContainer.class, "/*");
servletHolder.setInitOrder(0);
servletHolder.setInitParameter(
"com.sun.jersey.config.property.packages",
"com.hateos.spring.test01.resources"
);
try {
server.start();
server.join();
} catch (Exception ex) {
logger.error("Error occurred while starting Jetty", ex);
System.exit(1);
} finally {
server.destroy();
}
}
}
/resources/user/api/UserAPI.java
package com.hateos.spring.test01.resources.user.api;
import com.hateos.spring.test01.resources.user.model.User;
import com.hateos.spring.test01.resources.user.model.UserList;
public interface UserAPI {
UserList getAll();
User getById(String userId);
}
/resources/user/api/impl/UserAPIImpl.java
package com.hateos.spring.test01.resources.user.api.impl;
import com.hateos.spring.test01.resources.user.api.UserAPI;
import com.hateos.spring.test01.resources.user.model.User;
import com.hateos.spring.test01.resources.user.model.UserList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
@Service
public class UserAPIImpl implements UserAPI {
private static final Logger logger = LoggerFactory.getLogger(UserAPIImpl.class);
@Override
public UserList getAll() {
UserList userList = new UserList();
for (int index = 0; index < userIds.length; index++) {
userList.getUserList().add(toUser(index));
}
return userList;
}
@Override
public User getById(String userId) {
return findUserById(userId);
}
private User toUser(int index) {
User newUser = null;
if (index < userIds.length) {
newUser = new User();
newUser.setFirstName(firstNames[index]);
newUser.setLastName(lastNames[index]);
newUser.setUserId(userIds[index]);
}
return newUser;
}
private User findUserById(String userId) {
for (int index = 0; index < userIds.length; index++) {
if (userIds[index].equals(userId)) {
return toUser(index);
}
}
return null;
}
private static String[] firstNames = {"Bob", "Jerry", "Milton", "Carrie"};
private static String[] lastNames = {"Builder", "Seinfeld", "Bombay", "Fisher"};
private static String[] userIds = {"001", "153", "5566", "234"};
}
/resources/user/controller/UserController.java
package com.hateos.spring.test01.resources.user.controller;
import com.hateos.spring.test01.resources.user.api.UserAPI;
import com.hateos.spring.test01.resources.user.exception.UserNotFoundException;
import com.hateos.spring.test01.resources.user.model.User;
import com.hateos.spring.test01.resources.user.model.UserList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/users")
@Component
public class UserController {
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
private UserAPI userAPI;
@Autowired
public void setUserAPI(UserAPI usersAPI) {
logger.info("userAPI is being injected");
this.userAPI = usersAPI;
}
@GET
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public UserList getAllUsers() {
logger.info("getAllUsers is being called");
return this.userAPI.getAll();
}
@GET
@Path("/{uid}")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public User getUser(@PathParam("uid") String userId) {
User foundUser = userAPI.getById(userId);
if (foundUser != null) {
return foundUser;
} else {
throw new UserNotFoundException(userId);
}
}
}
编辑1 :控制台启动时登录
5:06:41 PM: Executing task 'run'...
> Task :compileJava UP-TO-DATE
> Task :processResources UP-TO-DATE
> Task :classes UP-TO-DATE
> Task :run
19-03-20 17:06:42:452 INFO main test01.MyApplication:15 - Hi guys!
19-03-20 17:06:42:496 INFO main util.log:192 - Logging initialized @446ms to org.eclipse.jetty.util.log.Slf4jLog
19-03-20 17:06:42:618 INFO main server.Server:372 - jetty-9.4.6.v20170531
Mar 20, 2019 5:06:42 PM com.sun.jersey.api.core.PackagesResourceConfig init
INFO: Scanning for root resource and provider classes in the packages:
com.hateos.spring.test01.resources
Mar 20, 2019 5:06:42 PM com.sun.jersey.api.core.ScanningResourceConfig logClasses
INFO: Root resource classes found:
class com.hateos.spring.test01.resources.greeting.controller.GreetingController
class com.hateos.spring.test01.resources.user.controller.UserController
class com.hateos.spring.test01.resources.shared.RootController
Mar 20, 2019 5:06:42 PM com.sun.jersey.api.core.ScanningResourceConfig logClasses
INFO: Provider classes found:
class com.hateos.spring.test01.resources.shared.controller.BaseExceptionMapper
Mar 20, 2019 5:06:42 PM com.sun.jersey.server.impl.application.WebApplicationImpl _initiate
INFO: Initiating Jersey application, version 'Jersey: 1.12 02/15/2012 04:51 PM'
19-03-20 17:06:43:540 INFO main handler.ContextHandler:788 - Started o.e.j.s.ServletContextHandler@4b29d1d2{/,null,AVAILABLE}
19-03-20 17:06:44:316 INFO main server.AbstractConnector:280 - Started ServerConnector@4a003cbe{HTTP/1.1,[http/1.1]}{0.0.0.0:9090}
19-03-20 17:06:44:316 INFO main server.Server:444 - Started @2270ms
编辑2:此问题与链接的重复项不同。我用球衣,但他们不。我的解决方案(由LppEdd提供)是通过最初的主要功能让球衣+春季比赛互相配合。我的问题是关于使用Jersey进行基于XML的Spring bean自动装配。
答案 0 :(得分:1)
很可能您需要指定与property
关联的UserAPI
<bean id="usersController" class="com.hateos.spring.test01.resources.user.controller.UserController" />
<property name="userAPI" ref="usersAPI" />
</bean>
但是,老实说,我会去构造函数注入。这很干净。
@Path("/users")
@Component
class UserController {
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
private final UserAPI userApi;
UserController(final UserAPI userApi) {
this.userApi = userApi;
}
...
}
使用
<bean id="usersController" class="com.hateos.spring.test01.resources.user.controller.UserController" />
<constructor-arg ref="usersAPI" />
</bean>
尽管您已经使用
<context:annotation-config/>
<context:component-scan base-package="com.hateos.spring.test01"/>
因此完全不需要XML文件中的<bean>
条目。
查看评论。
// You forgot about this!
servletContextHandler.addEventListener(new ContextLoaderListener());
servletContextHandler.setInitParameter("contextConfigLocation", "classpath*:**/hateos-spring-text.xml");
// You basically already have this part. Added for clarity
final ServletHolder jerseyServlet = new ServletHolder(SpringServlet.class);
jerseyServlet.setInitOrder(0);
jerseyServlet.setInitParameter(
"com.sun.jersey.config.property.packages",
"com.hateos.spring.test01"
);
servletContextHandler.addServlet(jerseyServlet, "/*");
应该足够。