문제

I'm trying to @POST a user-created object and get a Response with a different user-created payload as the entity. Although the object returned exists and is populated, on the client end it is empty.

Client sent / server received object:

@XmlRootElement
public class TweetQuery {
    String query;
    List<TweetQueryTweet> tweets = new ArrayList<>();
    // setters and getters
}

public class TweetQueryTweet {
    private String id;
    private String text;
    // setters and getters
}

Server received / client sent object:

@XmlRootElement
public class TweetClusters {
    List<TweetCluster> tweetClusters = new ArrayList<>();
    // setters and getters
}

public class TweetCluster {
    List<String> labels = new ArrayList<>();
    List<String> docs = new ArrayList<>();
    // setters and getters
}

Client (Arquillian) Test:

@Test
@RunAsClient
public void test01SeeSomething(@ArquillianResource URL deploymentUrl) throws ... {

    final URI targetURI = ...;
    System.out.println("    test target:" + targetURI.toASCIIString());

    Entity<TweetQuery> tweetQuery = Entity.entity(getTestTweetQuery(), MediaType.APPLICATION_JSON);

    Client client = ClientBuilder.newBuilder().build();
    WebTarget target = client.target(targetURI.toASCIIString());

    Response response = target.request(MediaType.APPLICATION_JSON).post(tweetQuery);

    TweetClusters x = response.readEntity(TweetClusters.class);
    System.out.println("Entity:" + x);
    System.out.println("Response: " + response.getStatus());
    assertEquals(Status.OK.getStatusCode(), response.getStatus());
    assertNotNull(x);
    assertThat(x.getTweetClusters().size()).isGreaterThan(0);
}

Jersey Post method:

@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response clusterPost(TweetQuery tweetQuery) {
    TweetClusters tweetClusters = clusterService.getTweetClusters(tweetQuery);
    System.out.println("clusterPost - in - tweetQuery: " + tweetQuery);
    System.out.println("    - out tweetClusters: " + tweetClusters);
    return Response.status(Status.OK).type(MediaType.APPLICATION_JSON).entity(tweetClusters).build();
}

Debug:

test target:http://localhost:18080/test//cluster

clusterPost - in - tweetQuery: [TweetQuery - query:TweetQuery query, tweets:[[TweetQueryTweet - id:1, text:text 1], [TweetQueryTweet - id:2, text:text 2], [TweetQueryTweet - id:3, text:text 3]]]
    - out tweetClusters: [TweetClusters:[[TweetCluster - labels: [Other Topics], docs:[3, 2, 1]]]]
Entity:[TweetClusters:[]]
Response: 200

Line 2 - clusterPost - in -- shows TweetQuery is being marshalled properly. Line 3 - clusterPost - out -- shows the tweetClusters to be sent as the Response entity exists Line 4 - tweetClusters is not coming out of the request


Edit

I changed the REST method to return the tweetQuery that it receives as input and it is returned correctly. So its something about TweetClusters. Maybe I need a MessageBodyReader & Writer. Or a Moxy @XmlJavaTypeAdapter. But for what as Lists obviously work out of the box as TweetQuery works.

https://stackoverflow.com/users/383861/blaise-doughan are you out there? :)

Am I missing something simple?

도움이 되었습니까?

해결책

oK I worked it out. I unintentionally told a porkie-pie. When I said I had setters and getters I was mising the setter for TweetClusters. Then once fixed i had a constructor with an argument but no no-arg constructor. Once the no-arg constructor added it was all good.

In summary you need to have in objects to be (un)marshalled:

  1. A no-arg constructor if you have an arg constructor
  2. Setters and getters for all the elements

And if you have more complex types including Date and Calendar you need to have a Adapter @XmlJavaTypeAdapter (Moxy) or @JsonSerialize.using in Jackson (or ??? in RESTeasy ...).

Interestingly I didn't need to have @XmlRootElement (Moxy) though kept it there for good measure.

The complete answer is:

  1. The Client (Arquillian) Test is same as above
  2. The Jersey Post method is same as above
  3. The object classes that (un)marshall are:

    @XmlRootElement public class TweetClusters { List tweetClusters = new ArrayList<>();

    public void addCluster(Cluster c) {
        TweetCluster tweetCluster = new TweetCluster(c);
        tweetClusters.add(tweetCluster);
    }
    
    public List<TweetCluster> getTweetClusters() {
        return tweetClusters;
    }
    
    public void setTweetClusters(List<TweetCluster> tweetClusters) {
        this.tweetClusters = tweetClusters;
    }
    
    @Override
    public String toString() {
        return String.format("[TweetClusters:%s]", tweetClusters);
    }
    

    }

    public class TweetCluster { List labels = new ArrayList<>(); List docs = new ArrayList<>();

    public TweetCluster() {
    }
    
    public TweetCluster(Cluster c) {
        labels.add(c.getLabel());
        for (Document doc : c.getDocuments()) {
            docs.add(doc.getTitle());
        }
    }
    
    public List<String> getLabels() {
        return labels;
    }
    
    public void setLabels(List<String> labels) {
        this.labels = labels;
    }
    
    public List<String> getDocs() {
        return docs;
    }
    
    public void setDocs(List<String> docs) {
        this.docs = docs;
    }
    
    @Override
    public String toString() {
        return String.format("[TweetCluster - labels: %s, docs:%s]", labels, docs);
    }
    

    }

    public class TweetQuery { String query;

    List<TweetQueryTweet> tweets = new ArrayList<>();
    
    public String getQuery() {
        return query;
    }
    
    public void setQuery(String query) {
        this.query = query;
    }
    
    public List<TweetQueryTweet> getTweets() {
        return tweets;
    }
    
    public void setTweets(List<TweetQueryTweet> tweets) {
        this.tweets = tweets;
    }
    
    public void addTweets(TweetQueryTweet... queryTweets) {
        for (TweetQueryTweet tweet : queryTweets) {
            this.tweets.add(tweet);
        }
    }
    
    @Override
    public String toString() {
        return String.format("[TweetQuery - query:%s, tweets:%s]",query, tweets);
    }
    

    }

(Arghhh, sorry about the formatting; I can't fix it in SO)

For debugging purposes it is often good to get back the string representation returned from the response (ie. XML or JSON) and you simply specify the entity type as String.class:

String x = response.readEntity(String.class);

다른 팁

Try to return response like this : Response.ok(tweetClusters).build();

I'm not sure why you have the models Annotated with @XmlRootElements. So I would think you could remove that and make sure you are using Jackson to Serialize and Deserialize your request and response body. Which I assume you are or gson.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top