2016-10-04 4 views
2

У меня есть динамический веб-проект на Java (развернутый на локальном сервере приложений Tomcat 7), который использует Джерси для создания API REST.POST JSON в запросе тела с Джерси

Я не использую инструменты автоматизации сборки (поэтому мои библиотеки добавляются в путь сборки, и сервлет вставляется в файл 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. Сценарий следующий: база данных содержит таблицу учетных записей пользователей, называемую пользователями. В столбцах указаны id, имя, имя пользователя и пароль.

У меня есть метод POST для проверки правильности учетной записи (имя пользователя + пароль). (Имя пользователя и пароль передаются в качестве заголовка Params) http://localhost:8080/UserAccount/rest/login/doLogin и заголовки: имя пользователя: х пароль: 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;   
} 

Как вы можете видеть, ответ будет производить JSON с истинным или ложным, на основе, если учетная запись пользователя действительна или нет. И до сих пор он отлично работает. Он отлично работает и выполняет GET и передает параметры как параметры запроса (но это не так).

Теперь я пытаюсь сделать 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(); 
    } 
} 

Я тестирование API с помощью клиента Advanced Rest от Google C hrome и REST Easy от Firefox.

Я также создал класс, который реализует 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

Боюсь, что Джерси не поддерживает gson или jettison из коробки. Вы можете изменить использование джексона или написать собственный читатель и писатель тела сообщения. – Veeram

ответ

3

Вы должны сказать Джерси использовать Gson для обработки JSON. Вы можете сделать это, используя интерфейсы MessageBodyReader и MessageBodyWriter, предоставленные Джерси. В этом stackoverflow question вы можете найти пример (см. Принятый ответ). Если вы хотите добавить контекст к нему, посмотрите на the JSON section of the Jersey 1.x manual

EDIT: не может быть понимание кода, но где вызов Gson в вашем UserBeanMessageBodyReader? Попробуйте chaging метод 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 (который AFAICT понимает только входы XML).

+0

Привет Франческо. Сегодня утром я попытался с MessageBodyReader (создал отдельный класс с аннотацией @Provider). Теперь он может войти в метод askLogin(), и он печатает строку в первой строке «Inside POST askLogin», но она по-прежнему не может отменить маркер. Я получаю эту ошибку: Ошибка десериализации javax.xml.bind.UnmarshalException - со связанным исключением: [org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Содержимое не допускается в прологе.] –

+0

Я думаю, что это связано с тем, что вы предоставляете. Вы должны отлаживать «MessageBodyReader», чтобы узнать, что вызывает исключение. В противном случае вы можете попытаться временно изменить службу 'askLogin' на' @Consumes ("text/plain") 'и принять' String user' вместо 'User user'. Таким образом, вы сможете увидеть, что Джерси получает в качестве входных данных, и, надеюсь, почему Gson это не нравится. –

+0

Чтобы убедиться, попробуйте также добавить методы setter к 'User'. Может быть, проблема в том, что Gson не может найти сеттеры для полей в «User». –

Смежные вопросы