2016-10-04 5 views
2

Ich habe ein dynamisches Web-Projekt in Java (bereitgestellt auf einem lokalen Anwendungsserver Tomcat 7), die Jersey zum Erstellen von REST-APIs verwendet.POST JSON in Body Anfrage mit Jersey

Ich verwende keine Build-Automation-Tools (meine Bibliotheken werden also zum Build-Pfad hinzugefügt und das Servlet wird in die Datei web.xml eingefügt).

Die Bibliotheken, die ich verwende, sind:

<?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> 

Die Anwendung mit einer MySQL-Datenbank interagiert:

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 

Mein web.xml die folgende ist. Das Szenario ist das folgende: Die Datenbank enthält eine Benutzerkontentabelle, die als Benutzer bezeichnet wird. Die Spalten sind ID, Name, Benutzername und Passwort.

Ich habe eine POST-Methode für die Überprüfung, ob ein Konto (Benutzername + Passwort) gültig sind. (Benutzername und Passwort als Header-params übergeben) http://localhost:8080/UserAccount/rest/login/doLogin und die Header: Benutzername: x Passwort: 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;   
} 

Wie Sie sehen können, ist die Antwort ein JSON mit wahr oder falsch erzeugen, basiert, wenn die Benutzerkonto ist gültig oder nicht. Und bis jetzt funktioniert es gut. Es funktioniert auch ein GET und übergibt die Parameter als Abfrageparameter (aber das ist nicht der Punkt).

Jetzt versuche ich, eine POST aber dieses Mal das Bestehen der Benutzername und das Passwort in einem JSON Körper zu tun:

{ 
    "username":"x", 
    "password":"1234" 
} 

Dafür ich eine Klasse erstellt haben User.java genannt:

@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; 
    } 
} 

Und ich habe eine Methode erstellt:

//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(); 
    } 
} 

ich die API am testen von Advanced REST-Client von Google-C unter Verwendung von hrome und REST Einfach von Firefox.

ich habe auch eine Klasse, die die MessageBodyReader implementiert wie folgt:

@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; 
    } 
} 

Nach Debuggen, ist das Problem kommt hier:

User user = (User) jaxbContext.createUnmarshaller().unmarshal(entityStream); 

und es geht auf der catch-Anweisung.

Der Stacktrace ist die folgende:

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) 

Was denken Sie?

+0

Ich fürchte, Jersey unterstützt nicht Gson oder Jettison out of Box. Sie können ändern, um jackson zu verwenden oder Ihren eigenen Nachrichtenkörperleser und -schreiber zu schreiben. – Veeram

Antwort

3

Sie sollten Jersey anweisen, Gson für die JSON-Behandlung zu verwenden. Sie können dies tun, indem Sie die von Jersey zur Verfügung gestellten Schnittstellen MessageBodyReader und MessageBodyWriter implementieren. In diesem stackoverflow question finden Sie ein Beispiel (siehe die angenommene Antwort). Wenn Sie etwas Kontext zu es hinzufügen möchten, werfen Sie einen Blick auf the JSON section of the Jersey 1.x manual

EDIT: kann ich nicht Ihr Code werden verstehen, aber wo ist der Aufruf von Gson in Ihrem UserBeanMessageBodyReader? Versuchen Sie, die reaedFrom Methode mit etwas entlang der Linien von

String result = new BufferedReader(new InputStreamReader(entityStream)) 
       .lines().collect(Collectors.joining("\n")); 
Gson gson = new GSon(); 
User myUser = gson.fromJson(result, User.class); 

chaging statt JAXBContext verwenden (was AFAIK nur XML-Eingaben versteht).

+0

Hallo Francesco. Heute Morgen habe ich es mit MessageBodyReader versucht (eine separate Klasse mit der Annotation @Provider erstellt). Nun ist es möglich, in die Methode askLogin() zu gelangen und es wird die Zeichenfolge in der ersten Zeile "Inside POST askLogin" gedruckt, aber es kann immer noch nicht entpackt werden. Ich erhalte diesen Fehler: Error deserializing eine javax.xml.bind.UnmarshalException - mit verknüpfter Ausnahme: [org.xml.sax.SAXParseException; Zeilennummer: 1; Spaltennummer: 1; Inhalt ist in Prolog nicht erlaubt.] –

+0

Ich denke, das hat mit der von Ihnen bereitgestellten Eingabe zu tun. Sie sollten den 'MessageBodyReader' debuggen, um festzustellen, was die Ausnahme verursacht. Andernfalls könnten Sie versuchen, den Dienst 'askLogin' vorübergehend in' @Consumes ("text/plain") '' zu ändern und 'String user' anstelle von' User user' zu akzeptieren. Auf diese Weise sollten Sie in der Lage sein zu sehen, was Jersey als Eingabe erhält, und hoffentlich, warum Gson es nicht mag. –

+0

Um sicher zu sein, versuchen Sie auch, Setter-Methoden zu "User" hinzuzufügen. Vielleicht besteht das Problem nur darin, dass Gson die Setter für die Felder in "User" nicht finden kann. –