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:
- A no-arg constructor if you have an arg constructor
- 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:
- The Client (Arquillian) Test is same as above
- The Jersey Post method is same as above
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);