Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
215 views
in Technique[技术] by (71.8m points)

java - retrieve JsonObject in POST with jersey

I have some problems in my application, I send a POST request, but I cannot retrieve the JsonObject in my server, this is the code to send:

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)));

Trying to retrieve with:

@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 network seems to be empty, in fact it doesn't execute the method ("Hello is not printed"), the error I get is "Invalid request body" (because the JsonObject is empty I think).. What's wrong with my code?

Ok, I understood that the problem is related to Json handling such as I'm using Gson. This is my improved code (simplified version) following users suggestion, but I still have problems..

Client Side:

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);

    }
}

Server Side:

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

    }
}

I created a GsonMessageBodyHandler.java in my package with the code suggested below by the user peeskillet. Added jersey-container-grizzly2-http.jar to my web-inf/lib (I don't know how to proper use Maven), but still doesn't work.. what am I missing?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

In order to convert JSON to a Java type, there is need to for a MessageBodyReader and a MessageBodyWriter implementation to do the conversion to and from. Since you are using JsonObject which is a GSON type, you can see this implementation. There is a problem with the implementation though, as the readFrom method doesn't compile with Jersey 2. Here is the a fixed version

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

Then we just need to register it with both the client and the application. I'm using a standalone test, where you can see the configuration here

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

Here is the resource class I used for the test

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

Here's the complete test, which requires 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();
    }
}

All the test does is send the JsonObject. Though there isn't any visible conversion to JSON, in any of my code, it is happening behind the scenes by the GsonMessageBodyHandler. If you look at the GsonResource class, you can see the methods don't do anything but send out the JsonObject. In the client test, I read the response as a String, and you can see the result the same as what sent out in the initial request.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...