如何使用 Moxy 和 Jersey 从 HashMap return JSON 对象
How to return a JSON object from a HashMap with Moxy and Jersey
我正在将 Jersey 2.17 与 Moxy 一起使用,我的功能如下:
@Produces(APPLICATION_JSON)
@Restricted
public List<User> getFriends(
@PathParam("user") String user
) {
return userDAO.getFriends(user);
}
User.preferences 是 HashMap
.
它适用于几乎所有对象,除了 HashMap
被翻译成:
"preferences":{"entry":[{"key":{"type":"string","value":"language"},"value":{"type":"string","value":"en"}},{"key":{"type":"string","value":"country"},"value":{"type":"string","value":"US"}}]}
但我真正想要 return 的只是一个 javascript 对象,例如:
preferences:{"language":"en","country":"US"}
我该怎么做?
是的,MOXy 和地图运行不佳。很遗憾,因为 JSON 只不过是映射的 key/value 对。如果要使用 MOXy,则需要使用 XmlAdapter
。在这种情况下,按照您想要 JSON 的方式,您将需要创建一个具有所有可能首选项名称的类型 (class)。任意键值对 应该 是您需要的形式,但由于 MOXy 不能做映射,您需要将其映射到您自己的类型。例如
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;
}
}
你的 DTO
@XmlRootElement
public class User {
@XmlJavaTypeAdapter(PreferencesAdapter.class)
public HashMap<String, String> preferences;
}
但是如果我们要做这一切,为什么我们不首先使用 Preferences
对象而不是 Map
?那是一个反问句。我完全理解你为什么不这样做。但这是 MOXy 的局限性之一,因为它让我们在后台使用 JAXB 变得沉重,而 JAXB 从来没有很好地与 Map 一起使用,这很可悲,就像我说的那样,JSON 实际上只不过是一个键值映射。
出于这个原因,以及实际上我过去遇到的许多其他原因,我不推荐使用 MOXy,即使它是 Jersey 推荐的。相反,使用杰克逊。一段时间以来,Jackson 一直是 JSON 处理的事实上的 Java goto。对于 Jackson,只需使用此依赖项
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey.version}</version>
</dependency>
如果去掉 MOXy 依赖项,这个 Jackson 模块应该可以正常工作。否则,如果您离开 MOXy 依赖项,则需要注册 JacksonFeature
我正在将 Jersey 2.17 与 Moxy 一起使用,我的功能如下:
@Produces(APPLICATION_JSON)
@Restricted
public List<User> getFriends(
@PathParam("user") String user
) {
return userDAO.getFriends(user);
}
User.preferences 是 HashMap
.
它适用于几乎所有对象,除了 HashMap
被翻译成:
"preferences":{"entry":[{"key":{"type":"string","value":"language"},"value":{"type":"string","value":"en"}},{"key":{"type":"string","value":"country"},"value":{"type":"string","value":"US"}}]}
但我真正想要 return 的只是一个 javascript 对象,例如:
preferences:{"language":"en","country":"US"}
我该怎么做?
是的,MOXy 和地图运行不佳。很遗憾,因为 JSON 只不过是映射的 key/value 对。如果要使用 MOXy,则需要使用 XmlAdapter
。在这种情况下,按照您想要 JSON 的方式,您将需要创建一个具有所有可能首选项名称的类型 (class)。任意键值对 应该 是您需要的形式,但由于 MOXy 不能做映射,您需要将其映射到您自己的类型。例如
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;
}
}
你的 DTO
@XmlRootElement
public class User {
@XmlJavaTypeAdapter(PreferencesAdapter.class)
public HashMap<String, String> preferences;
}
但是如果我们要做这一切,为什么我们不首先使用 Preferences
对象而不是 Map
?那是一个反问句。我完全理解你为什么不这样做。但这是 MOXy 的局限性之一,因为它让我们在后台使用 JAXB 变得沉重,而 JAXB 从来没有很好地与 Map 一起使用,这很可悲,就像我说的那样,JSON 实际上只不过是一个键值映射。
出于这个原因,以及实际上我过去遇到的许多其他原因,我不推荐使用 MOXy,即使它是 Jersey 推荐的。相反,使用杰克逊。一段时间以来,Jackson 一直是 JSON 处理的事实上的 Java goto。对于 Jackson,只需使用此依赖项
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey.version}</version>
</dependency>
如果去掉 MOXy 依赖项,这个 Jackson 模块应该可以正常工作。否则,如果您离开 MOXy 依赖项,则需要注册 JacksonFeature