使用jersey在POST中检索JsonObject

时间:2014-11-28 12:31:07

标签: java json rest jersey gson

我在我的应用程序中遇到一些问题,我发送了一个POST请求,但我无法检索服务器中的JsonObject,这是要发送的代码:

String quo = "{\"network\": {\"label\": \"new net 111\",\"cidr\": \"10.20.105.0/24\"}}";
GsonBuilder builder = new GsonBuilder();
Gson gson = builder.create();
JsonParser json = new JsonParser();
JsonObject jo = (JsonObject)json.parse(quo);
ClientConfig config = new ClientConfig();

Client client = ClientBuilder.newClient(config);

WebTarget target = client.target("http://localhost:7999/jersey/rest/network/"+tenant_id);

Response oj = target.request().accept(MediaType.APPLICATION_JSON)
        .header("X-Auth-Token", token)
        .post(Entity.json(gson.toJson(jo)));

尝试使用以下方式检索:

@POST
@Produces(MediaType.APPLICATION_JSON)
@Path("/{tenant_id}")
public String createNetwork(@HeaderParam(value = "X-Auth-Token") String authToken, 
                        @PathParam(value = "tenant_id") String tenant_id, 
                        JsonObject network){

    Response response = client.target(NOVA_ENDPOINT+tenant_id)
                .request(MediaType.APPLICATION_JSON)
                .header("X-Auth-Token", authToken)
                .post(Entity.json(gson.toJson(network)));
    System.out.println("Hello"); 
    String responseJson = response.readEntity(String.class);

JsonObject网络似乎是空的,实际上它不执行该方法(“Hello is not printed”),我得到的错误是“Invalid request body”(因为我觉得JsonObject是空的).. 我的代码出了什么问题?

好的,我明白这个问题与Json处理有关,比如我正在使用Gson。这是我改进的代码(简化版),遵循用户的建议,但我仍有问题..

客户端:

package openstack;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.net.URI;


public class Post {

    public static HttpServer startServer() {
    final ResourceConfig resourceConfig = new ResourceConfig()
            .packages("openstack")
            .register(GsonMessageBodyHandler.class);
    return GrizzlyHttpServerFactory.createHttpServer(URI.create("http://localhost:7999/jersey/rest"), resourceConfig);
}  
    public static void main(String[] args) {

    String quo = "{\"keypair\": {\"name\": \"MyKey\"}}";
    HttpServer server = startServer();


    Client client = ClientBuilder.newClient();

    client.register(GsonMessageBodyHandler.class);

    GsonBuilder builder = new GsonBuilder();
    Gson gson = builder.create();
    JsonParser json = new JsonParser();
    JsonObject jo = (JsonObject)json.parse(quo);

    WebTarget target = client.target("http://localhost:7999/jersey/rest/test/prova");

    System.out.println(jo);
    Response oj = target.request().post(Entity.json(jo));

    String responseString = oj.readEntity(String.class);
    System.out.println(responseString);

    }
}

服务器端:

package openstack;

import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

@Path("/test")
public class Test {

    GsonBuilder builder = new GsonBuilder();
    Gson gson = builder.create();
    Parliament parliament = new Parliament();
    JsonParser json = new JsonParser();
    private final Client client;

    public Test() {
        client = ClientBuilder.newClient().register(GsonMessageBodyHandler.class);
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/prova")
    public Response mymethod(JsonObject keypairsob){

        return Response.ok(keypairsob).build();

    }
}

我在我的包中创建了一个GsonMessageBodyHandler.java,其中包含用户peeskillet建议的代码。将jersey-container-grizzly2-http.jar添加到我的web-inf / lib(我不知道如何正确使用Maven),但仍然无法正常工作..我错过了什么?

3 个答案:

答案 0 :(得分:2)

为了将JSON转换为Java类型,需要MessageBodyReaderMessageBodyWriter实现来进行转换。由于您使用的是JsonObject GSON类型,因此您可以看到this implementation。但是实现存在问题,因为readFrom方法不能用Jersey 2编译。这是固定版本

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;


@Provider
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public final class GsonMessageBodyHandler implements MessageBodyWriter<Object>,
        MessageBodyReader<Object> {

    private static final String UTF_8 = "UTF-8";

    private Gson gson;

    private Gson getGson() {
        if (gson == null) {
            final GsonBuilder gsonBuilder = new GsonBuilder();
            gson = gsonBuilder.create();
        }
        return gson;
    }

    @Override
    public boolean isReadable(Class<?> type, Type genericType,
            java.lang.annotation.Annotation[] annotations, MediaType mediaType) {
        return true;
    }

    @Override
    public Object readFrom(Class<Object> type, Type type1, Annotation[] antns,
            MediaType mt, MultivaluedMap<String, String> mm, InputStream in) 
            throws IOException, WebApplicationException {
        InputStreamReader streamReader = new InputStreamReader(in, UTF_8);
        try {
            Type jsonType;
            if (type.equals(type1)) {
                jsonType = type;
            } else {
                jsonType = type1;
            }
            return getGson().fromJson(streamReader, jsonType);
        } finally {
            streamReader.close();
        }
    }

    @Override
    public boolean isWriteable(Class<?> type, Type genericType, 
            Annotation[] annotations, MediaType mediaType) {
        return true;
    }

    @Override
    public long getSize(Object object, Class<?> type, Type genericType, 
            Annotation[] annotations, MediaType mediaType) {
        return -1;
    }

    @Override
    public void writeTo(Object object, Class<?> type, Type genericType, 
            Annotation[] annotations, MediaType mediaType, 
            MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) 
            throws IOException, WebApplicationException {
        OutputStreamWriter writer = new OutputStreamWriter(entityStream, UTF_8);
        try {
            Type jsonType;
            if (type.equals(genericType)) {
                jsonType = type;
            } else {
                jsonType = genericType;
            }
            getGson().toJson(object, jsonType, writer);
        } finally {
            writer.close();
        }
    }
}

然后我们只需要在客户端和应用程序中注册它。我正在使用独立测试,您可以在此处查看配置

final ResourceConfig resourceConfig = new ResourceConfig()
        .packages("jersey.stackoverflow.standalone")
        .register(GsonMessageBodyHandler.class);
...
Client c = ClientBuilder.newClient();
c.register(GsonMessageBodyHandler.class);

这是我用于测试的资源类

import com.google.gson.JsonObject;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import jersey.stackoverflow.standalone.provider.GsonMessageBodyHandler;

@Path("/gson")
public class GsonResource {

    private final Client client;
    private static final String BASE_URI = "http://localhost:8080/api/gson";

    public GsonResource() {
        client = ClientBuilder.newClient().register(GsonMessageBodyHandler.class);
    }

    @POST
    @Path("/proxy")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response proxyPost(JsonObject json) {
        Response response = client.target(BASE_URI)
                .path("main-resource").request().post(Entity.json(json));
        JsonObject fromMainResource = response.readEntity(JsonObject.class);
        return Response.created(null /* should be a created URI */)
                .entity(fromMainResource).build();
    }

    @POST
    @Path("/main-resource")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response mainResource(JsonObject json) {
        return Response.ok(json).build();
    }  
}

这是完整的测试,需要this maven dependency

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.net.URI;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
import static jersey.stackoverflow.standalone.Main.BASE_URI;
import jersey.stackoverflow.standalone.provider.GsonMessageBodyHandler;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.Test;

public class GsonProviderTest {

    public static HttpServer startServer() {
        final ResourceConfig resourceConfig = new ResourceConfig()
                .packages("jersey.stackoverflow.standalone")
                .register(GsonMessageBodyHandler.class);
        return GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), resourceConfig);
    }

    public static Client getClient() {
        Client c = ClientBuilder.newClient();
        c.register(GsonMessageBodyHandler.class);
        return c;
    }

    @Test
    public void testGetIt() {
        HttpServer server = startServer();
        Client c = getClient();

        c.register(GsonMessageBodyHandler.class);

        String quo = "{\"network\": {\"label\": \"new net 111\",\"cidr\": \"10.20.105.0/24\"}}";

        GsonBuilder builder = new GsonBuilder();
        Gson gson = builder.create();
        JsonParser json = new JsonParser();
        JsonObject jo = (JsonObject) json.parse(quo);

        WebTarget target = c.target("http://localhost:8080/api/gson/proxy");
        Response response = target.request().post(Entity.json(jo));
        String responseString = response.readEntity(String.class);
        System.out.println(responseString);
        response.close();

        c.close();
        server.stop();
    }
}

所有测试都是发送JsonObject。虽然没有任何可见的转换为JSON,但在我的任何代码中,它都在GsonMessageBodyHandler的幕后发生。如果您查看GsonResource课程,您可以看到这些方法除了发送JsonObject之外什么也不做。在客户端测试中,我将响应作为字符串读取,您可以看到结果与初始请求中发送的结果相同。

答案 1 :(得分:1)

使用post请求以com.google.gson.JsonObject类型获取JsonObject的简单方法。

我假设已经添加了com.google.gson,jersey和jax-rs的所有依赖项。

在服务器端,您需要具有与以下类似的代码:

import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;

@Path("/api")
public class JersyAPI {


    private JsonParser parser= new JsonParser();

    @POST
    @Path("/pudding")
    @Consumes("application/json")
    public Response postTest(String requestBody){
        Response re = Response.status(200).build();
        try{
            JsonObject inputObjectJson = parser.parse(requestBody).getAsJsonObject();

上面的代码有一个用path / api / pudding定义的rest端点,它接受Request Body as String。在服务器端收到Json作为字符串后,可以使用com.google.gson.JsonParser将其直接转换为com.google.gson.JsonObject,这可以在您的程序中使用。

要在服务器端发出请求,您发布的请求应如下所示:

POST /rest/api/pudding HTTP/1.1
Host: localhost:8082
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: c2b087d9-4830-c8a8-2a19-78273a73898c

{
  "id": 1312312,
  "name": "Test",
  "data": { 
            "test" : "data"
        },
}

答案 2 :(得分:0)

您是否成功解析了任何JSON请求?可能需要在Jersey中启用JSON支持:

https://jersey.java.net/documentation/1.18/json.html

否则,它可能只是在您的请求上失败,在这里将消息体转换为JsonObject:

public String createNetwork(
    @HeaderParam(value = "X-Auth-Token") String authToken, 
    @PathParam(value = "tenant_id") String tenant_id, 
    JsonObject network)