NBW
NBW

Reputation: 1487

Issue marshalling generic with Moxy and JerseyClient2

The following code uses the Jersey2 client (v 2.22.2) with the built-in Moxy JSON support. I am trying to marshal a generified wrapper class into JSON. As you can see below the json property isn't unmarshalling as intended.

When I change the type for the json property to Service and 'ungenerify' the class everything works as intended but I would prefer to be able to do this with generics so I don't have to create a bunch of these wrapper classes for each type that needs to be wrapped in this fashion.

JSONWrapper.java

public class JSONWrapper<T> implements Serializable {
  private T json;

  public T getJson() { return this.json; }
  public void setJson (T payload) { this.json = payload; }

  public JSONWrapper() {}
}

Service.java

public class Service implements Serializable {
    private String name;
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

MyClient.java

public class MyClient {
  private Client jerseyClient;

  public void createService(Service item) {
    Invocation.Builder invocationBuilder = buildRequest(SERVICE_PATH);
    JSONWrapper<Service> wrapper = new JSONWrapper<>();
    wrapper.setJson(item);
    final Response response = invocationBuilder.post(Entity.entity(wrapper, MediaType.APPLICATION_JSON_TYPE));
  }

  public MyClient() {
     this.jerseryClient = ClientBuilder.newBuilder().build();
  }

  public static void main(String[] args) {
     MyClient myClient = new MyClient();
     Service myService = new Service();
     myService.setName("foo");
     myClient.createService(myService);
  }
}

With the logging filter turned on I am seeing that Moxy's marshalling of things looks like so:

{"json":"com.baz.Service@5674e1f2"}

When I want it to look like so

{"json":"{"name": "foo"}"}

Upvotes: 1

Views: 394

Answers (1)

Paul Samsotha
Paul Samsotha

Reputation: 209052

Because of type erasure, the generic type is wiped out at runtime, so MOXy doesn't know the generic type and just spits out its toString. This is one of the limitations of using MOXy (it relies on some JAXB functionality). To get around this, JAX-RS has the GenericEntity that let's us wrap the generic type, so it's known to serializers.

JsonWrapper<Service> service = new JsonWrapper<>();
user.setJson(new Service("blah"));
GenericEntity<JsonWrapper<Service>> entity 
        = new GenericEntity<JsonWrapper<Service>>(service){};
Response response = target("test").request().post(Entity.json(entity));

From what I just tested with MOXy, for some reason it spits out an extra "type":"service" property in the JSON. I am not completely sure why. I haven't used MOXy in a while. I've had too many problems with it. Personally, I'd recommend switching over to Jackson. With Jackson you will not have this type problem. You could get away with not using GenericEntity, and it will work out the box. If you're using Maven, just add the following dependency and remove MOXy

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
    <version>${jersey2.version}</version>
</dependency>

If you're not using Maven, have a look at this post.

Upvotes: 1

Related Questions