我有一个Java动态Web项目(部署在本地应用程序服务器Tomcat 7上),它使用Jersey创建REST API。
我不使用任何构建自动化工具(因此我的库被添加到构建路径中,并且servlet被插入到web.xml文件中)。
我使用的库是:
asm-3.1.jar
gson-2.2.1.jar
jersey-client-1.0.3.jar
jersey-core-1.0.3.jar
jersey-json-1.18.jar
jersey-server-1.0.3.jar
jettison-1.1.jar
jsr311-api-1.0.jar
mysql-connector-java-5.0.8-bin.jar
我的web.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>UserAccount</display-name>
<servlet>
<servlet-name>ServletAdaptor</servlet-name>
<servlet-class>com.sun.jersey.server.impl.container.servlet.ServletAdaptor</servlet-class>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ServletAdaptor</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
应用程序正在与MySQL数据库进行交互。 方案如下:数据库包含名为users的用户帐户表。列是id,名称,用户名和密码。
我有一个POST方法来验证帐户(用户名+密码)是否有效。 (作为标题参数传递的用户名和密码) http://localhost:8080/UserAccount/rest/login/doLogin 和标题: 用户名:x 密码:1234
@POST
@Path("/doLogin")
@Produces(MediaType.APPLICATION_JSON)
public String doLogin(@HeaderParam("username") String uname, @HeaderParam("password") String pwd){
String response = "";
if(checkCredentials(uname, pwd)){
response = Utility.constructJSON("login",true);
}else{
response = Utility.constructJSON("login", false, "Incorrect Email or Password");
}
return response;
}
如您所见,如果用户帐户有效,响应将生成一个带有true或false的JSON。 到目前为止它工作正常。它也可以正常执行GET并将params作为查询参数传递(但这不是重点)。
现在我正在尝试POST,但这次在JSON正文中传递用户名和密码:
{
"username":"x",
"password":"1234"
}
为此,我创建了一个名为User.java的类:
@XmlRootElement()
@XmlAccessorType(XmlAccessType.FIELD)
public class User implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
@XmlElement(name="username")
private String username;
@XmlElement(name="password")
private String password;
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "username: " + username;
}
}
我创建了一个方法:
//pass the arguments as JSON body
@POST
// Path: http://localhost:8080/UserAccount/rest/login/asklogin
@Path("/askLogin")
// Produces JSON as response
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response askLogin(User user) {
System.out.println("Inside POST askLogin");
if(checkCredentials(user.getUsername(), user.getPassword())) {
return Response.ok().build();
} else {
return Response.serverError().build();
}
}
我正在使用Google Chrome中的Advanced Rest Client和Firefox中的REST Easy来测试API。
我还创建了一个实现MessageBodyReader的类,如下所示:
@Provider
public class UserBeanMessageBodyReader implements MessageBodyReader<User> {
//used for MessageBodyReader
@Override
public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations,
MediaType mediaType) {
return type == User.class;
}
@Override
public User readFrom(Class<User> type, Type genericType, Annotation[] annotations,
MediaType mediaType, MultivaluedMap<String, String> httpHeaders,
InputStream entityStream) throws IOException, WebApplicationException {
try {
JAXBContext jaxbContext = JAXBContext.newInstance(User.class);
User user = (User) jaxbContext.createUnmarshaller().unmarshal(entityStream);
return user;
} catch (JAXBException jaxbException) {
jaxbException.printStackTrace();
System.out.println("Error deserializing a User" + jaxbException);
}
return null;
}
}
调试后,问题出现在这里:
User user = (User) jaxbContext.createUnmarshaller().unmarshal(entityStream);
它继续发表了捕获声明。
stacktrace如下:
INFO: Server startup in 1239 ms
javax.xml.bind.UnmarshalException
- with linked exception:
[org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is
not allowed in prolog.]
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.createUnmarshalException(AbstractUnmarshallerImpl.java:335)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.createUnmarshalException(UnmarshallerImpl.java:563)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:249)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:214)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:157)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:204)
at ro.useraccount.jersey.UserBeanMessageBodyReader.readFrom(UserBeanMessageBodyReader.java:36)
at ro.useraccount.jersey.UserBeanMessageBodyReader.readFrom(UserBeanMessageBodyReader.java:1)
at com.sun.jersey.spi.container.ContainerRequest.getEntity(ContainerRequest.java:393)
at com.sun.jersey.server.impl.model.method.dispatch.EntityParamDispatchProvider$EntityInjectable.getValue(EntityParamDispatchProvider.java:139)
at com.sun.jersey.server.impl.inject.InjectableValuesProvider.getInjectableValues(InjectableValuesProvider.java:43)
at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$EntityParamInInvoker.getParams(AbstractResourceMethodDispatchProvider.java:126)
at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:173)
at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:67)
at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:163)
at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:111)
at com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:71)
at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:111)
at com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:63)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:654)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:612)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:603)
at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:309)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:425)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:590)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:723)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:861)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:612)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:503)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not allowed in prolog.
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:203)
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(ErrorHandlerWrapper.java:177)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:400)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:327)
at com.sun.org.apache.xerces.internal.impl.XMLScanner.reportFatalError(XMLScanner.java:1437)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:999)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:606)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:118)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:510)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:848)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:643)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:243)
... 35 more
Error deserializing a Userjavax.xml.bind.UnmarshalException
- with linked exception:
[org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not allowed in prolog.]
Inside POST askLogin
Oct 06, 2016 8:57:27 AM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet ServletAdaptor threw exception
java.lang.NullPointerException
at ro.useraccount.jersey.Login.askLogin(Login.java:67)
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:497)
at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:175)
at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:67)
at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:163)
at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:111)
at com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:71)
at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:111)
at com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:63)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:654)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:612)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:603)
at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:309)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:425)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:590)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:723)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:861)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:612)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:503)
at java.lang.Thread.run(Thread.java:745)
您怎么看?
答案 0 :(得分:4)
你应该告诉Jersey使用Gson进行JSON处理。您可以执行此操作来实现Jersey提供的MessageBodyReader
和MessageBodyWriter
接口。
在此stackoverflow question中,您可以找到一个示例(请参阅接受的答案)。
如果你想为它添加一些上下文,请看一下
the JSON section of the Jersey 1.x manual
编辑:
我可能不理解你的代码,但是在你的代码中对Gson的调用在哪里
UserBeanMessageBodyReader
?
尝试使用
reaedFrom
方法
String result = new BufferedReader(new InputStreamReader(entityStream))
.lines().collect(Collectors.joining("\n"));
Gson gson = new GSon();
User myUser = gson.fromJson(result, User.class);
而不是使用JAXBContext
(它只能理解XML输入)。