I am using Jersey 2.17 with Moxy and I have functions like :
@Produces(APPLICATION_JSON)
@Restricted
public List<User> getFriends(
@PathParam("user") String user
) {
return userDAO.getFriends(user);
}
User.preferences is a HashMap
.
It works fine for almost all Objects except for a HashMap
which gets translated into:
"preferences":{"entry":[{"key":{"type":"string","value":"language"},"value":{"type":"string","value":"en"}},{"key":{"type":"string","value":"country"},"value":{"type":"string","value":"US"}}]}
but what I would really like to return is just a javascript object like:
preferences:{"language":"en","country":"US"}
How can I do that?
Yeah MOXy and Maps don't work well. It's sad, as JSON is nothing more than mapped key/value pairs. If you want to use MOXy, you will need to use an XmlAdapter
. In which case, the way you want the JSON, you will need to create a type (class) that has the name of all possible preferences. Arbitrary key value pairs should be in the form you require, but since MOXy can't do maps, you'll need to map it to your own type. For instance
public class PreferencesAdapter extends XmlAdapter<Preference, HashMap<String, String>> {
@XmlRootElement
public static class Preference {
public String language;
public String country;
}
@Override
public HashMap<String, String> unmarshal(Preference p) throws Exception {
HashMap<String, String> map = new HashMap<>();
map.put("language", p.language);
map.put("country", p.country);
return map;
}
@Override
public Preference marshal(HashMap<String, String> v) throws Exception {
Preference p = new Preference();
p.language = v.get("language");
p.country = v.get("country");
return p;
}
}
Your DTO
@XmlRootElement
public class User {
@XmlJavaTypeAdapter(PreferencesAdapter.class)
public HashMap<String, String> preferences;
}
But if we're doing to do all this, why don't we just use a Preferences
object in the first place instead of a Map
? That was a rhetorical question. I totally understand why you wouldn't. But this is one of the limitations of MOXy, as it makes heavy us of JAXB under the hood, and JAXB has never played nicely with Map, which is sad, as like I said, JSON is really nothing more than a Map of key values.
For this reason, and actually many others I have encountered in the past, I do no recommend using MOXy even though it is recommended by Jersey. Instead, use Jackson. Jackson has been the defacto Java goto for JSON processing for a while. For Jackson, just use this dependency
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey.version}</version>
</dependency>
If you take out the MOXy dependency, this Jackson module should work out the box. Otherwise if you leave the MOXy dependency, you will need to register the JacksonFeature
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With