Jersey deserializing JSON when using local jersey

2019-08-04 01:18发布

I'm trying to create a webservice using a Jersey HttpServer instead of Tomcat. The server is working when using simple GET request or plaintext, but when I try to send JSON objects I only get a server answer telling me that the media type is not supported (HTTP Error 415).

I think the problem is, that the JSON objects can't be deserialized like it's described in this post. But as I'm using a locally created HttpServer the solution of this answer didn't work for me.

So the question is: How can I configure my Jersey HttpServer to work for JSON objects?

The server implementation I'm using is:

import java.io.IOException;
import java.net.URI;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.glassfish.jersey.jdkhttp.JdkHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;

import com.sun.net.httpserver.HttpServer;

public class JsonRpcServer {

    private static final Logger LOGGER = LogManager.getLogger(JsonRpcServer.class);

    private static final String BASE_URI = "http://localhost:4711/";
    private static final String BASE_PACKAGE = "com.picavi.json_rpc_server.service";

    public static void main(String[] args) {
        ResourceConfig config = new ResourceConfig().packages(BASE_PACKAGE);
        HttpServer server = JdkHttpServerFactory.createHttpServer(URI.create(BASE_URI), config);

        LOGGER.info("Starting server at {}", BASE_URI);
        //server.start() is called as side effect
        System.out.println("Press <Enter> to stop the server");
        try {
            System.in.read();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
        //stop the server after the user has made an input
        LOGGER.info("Stopping server\n\n\n");
        server.stop(0);

        System.exit(0);
    }
}

The service class:

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.picavi.json_rpc_server.backend.LoginException;
import com.picavi.json_rpc_server.backend.OrderPicking;
import com.picavi.json_rpc_server.backend.SystemAutentification;
import com.picavi.json_rpc_server.model.Configuration;
import com.picavi.json_rpc_server.model.Credentials;
import com.picavi.json_rpc_server.model.JsonRpcError;
import com.picavi.json_rpc_server.model.JsonRpcLoginAnswer;
import com.picavi.json_rpc_server.model.JsonRpcRequest;
import com.picavi.json_rpc_server.model.JsonRpcResponse;
import com.picavi.json_rpc_server.model.Picklist;
import com.picavi.json_rpc_server.model.PicklistRequestParameters;

@Path("/")
public class JsonRpcService {

    private static final Logger LOGGER = LogManager.getLogger(JsonRpcService.class);

    private static final String jsonRPC = "2.0";

    @POST
    @Path("/")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response processRequest(JsonRpcRequest request) {
        LOGGER.info("received (synchrone) request: {}", request);

        //execute the requested method
        switch (request.getMethod()) {
            case "system.login":
                return processLogin(request);
            case "system.logout":
                return processLogout(request);
        }

        //if the method is none of the above return an error
        LOGGER.warn("the request could not be processed, because the method name is unknown: {}", request.getMethod());
        return createMethodNotFoundErrorResponse(request.getId(), request.getMethod());
    }

    @POST
    @Path("/async")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response processRequestAsync(JsonRpcRequest request) {
        LOGGER.info("received (asynchrone) request: {}", request);

        //execute the requested method
        try {
            switch (request.getMethod()) {
                case "system.login":
                    return CompletableFuture.supplyAsync(() -> processLogin(request)).get();
                case "system.logout":
                    return CompletableFuture.supplyAsync(() -> processLogout(request)).get();
            }
        }
        catch (InterruptedException | ExecutionException e) {
            LOGGER.error("The asynchrone execution of the request failed", e);

            //return an unknown error because this exceptions should never occur
            return createErrorResponse(request.getId());
        }

        //if the method is none of the above return an error
        LOGGER.warn("the request could not be processed, because the method name is unknown: {}", request.getMethod());
        return createMethodNotFoundErrorResponse(request.getId(), request.getMethod());
    }

    private Response processLogin(JsonRpcRequest request) {
        LOGGER.info("processing login request");
        //get the login information
        Credentials credentials;
        try {
            credentials = (Credentials) request.getParams();
        }
        catch (ClassCastException cce) {
            return createIllegalParameterErrorResponse(request.getId(), request.getParams());
        }

        String user = credentials.getUser();
        String password = credentials.getPassword();

        //login the user
        SystemAutentification systemProcessor = SystemAutentification.getInstance();
        String sessionId;
        try {
            sessionId = systemProcessor.login(user, password);
        }
        catch (LoginException le) {
            return createLoginErrorResponse(request.getId());
        }

        //create the response
        JsonRpcResponse response = new JsonRpcResponse();
        response.setId(request.getId());
        response.setJsonRpc(jsonRPC);
        response.setError(JsonRpcError.OK);
        response.setResult(new JsonRpcLoginAnswer(sessionId, new Configuration("DE", "right")));

        //return the response
        return Response.status(Status.OK).entity(response).build();
    }

    private Response processLogout(JsonRpcRequest request) {
        LOGGER.info("Processing logout request");

        //get the information form the request
        String sessionId;
        try {
            sessionId = (String) request.getParams();
        }
        catch (ClassCastException cce) {
            return createIllegalParameterErrorResponse(request.getId(), request.getParams());
        }

        //logout the user
        SystemAutentification systemProcessor = SystemAutentification.getInstance();
        boolean logoutSucessful = systemProcessor.logout(sessionId);

        //create the response
        JsonRpcResponse response = new JsonRpcResponse();
        response.setId(request.getId());
        response.setJsonRpc(jsonRPC);
        response.setError(JsonRpcError.OK);
        response.setResult(Boolean.valueOf(logoutSucessful));

        //return the response
        return Response.status(Status.OK).entity(response).build();
    }

    //... some eror handling and response creation is left out here
}

My web.xml (although I don't think that it is even used because I use the local jersey http server):

<web-app id="WebApp_ID" version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>Picavi RPC</display-name>

    <servlet>
        <servlet-name>jersey-serlvet</servlet-name>
        <servlet-class>
                     com.sun.jersey.spi.container.servlet.ServletContainer
                </servlet-class>
        <init-param>
             <param-name>com.sun.jersey.config.property.packages</param-name>
             <param-value>com.picavi.json_rpc_server.service</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>jersey-serlvet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

</web-app>

And a client log file that told me there is an HTTP 415 error:

[INFO ] 2019-06-30 19:16:27.244 [JavaFX Application Thread] SimpleRpcClient - Sending POST request to url: http://localhost:4711/; request: {
  "jsonRpc" : "2.0",
  "method" : "system.login",
  "params" : {
    "user" : "name",
    "password" : "secret",
    "station" : "",
    "deviceIdent" : ""
  },
  "id" : "1"
}
[INFO ] 2019-06-30 19:16:27.429 [JavaFX Application Thread] SimpleRpcClient - Server sent response code: 415

Edit: My Maven dependencies are:

<repositories>
    <repository>
        <id>snapshot-repository.java.net</id>
        <name>Java.net Snapshot Repository for Maven</name>
        <url>https://maven.java.net/content/repositories/snapshots/</url>
        <layout>default</layout>
    </repository>
</repositories>

<dependencies>
    <!-- some testing and logging frameworks -->

    <!-- JAX-RS for REST -->
    <dependency>
        <groupId>javax.ws.rs</groupId>
        <artifactId>javax.ws.rs-api</artifactId>
        <version>2.0</version>
    </dependency>

    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-jdk-http</artifactId>
        <version>2.10.1</version>
    </dependency>

    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet</artifactId>
        <version>2.10</version>
    </dependency>
</dependencies>

标签: java json jersey
0条回答
登录 后发表回答