如何重用 Jersey 的 JSON/JAXB 进行序列化?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1071749/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to reuse Jersey's JSON/JAXB for serialization?
提问by ctwomey
I have a JAX-RS REST service implemented using Jersey. One of the cool features of JAX-RS/Jersey is how easily a POJO can be turned into a REST service, simply by sprinkling a few Java annotations... including a trivially easy mechanism for translating POJOs to JSON - using JAXB annotations.
我有一个使用 Jersey 实现的 JAX-RS REST 服务。JAX-RS/Jersey 的一个很酷的特性是可以很容易地将 POJO 转换为 REST 服务,只需添加一些 Java 注释......包括将 POJO 转换为 JSON 的一种非常简单的机制 - 使用 JAXB 注释。
Now, I'd like to be able to take advantage of this cool JSON-ifying functionality for non-REST purposes - I'd love to be able to just serialize some of these objects to disk, as JSON text. Here's an example JAXB object that I'd want to serialize:
现在,我希望能够将这个很酷的 JSON 化功能用于非 REST 目的——我希望能够将其中一些对象作为 JSON 文本序列化到磁盘。这是我想要序列化的示例 JAXB 对象:
@XmlRootElement(name = "user")
public class UserInfoImpl implements UserInfo {
public UserInfoImpl() {}
public UserInfoImpl(String user, String details) {
this.user = user;
this.details = details;
}
public String getUser() { return user; }
public void setUser(String user) { this.user = user; }
public String getDetails() { return details; }
public void setDetails(String details) { this.details = details; }
private String user;
private String details;
}
Jersey can turn one of these into json with no additional info. I'm wondering if Jersey has exposed this functionality in the API for needs like mine? I've had no luck finding it so far...
Jersey 可以将其中之一转换为 json,无需额外信息。我想知道 Jersey 是否已经在 API 中公开了这个功能来满足我的需求?到目前为止我没有运气找到它......
Thanks!
谢谢!
UPDATE 2009-07-09: I have learned that I can use the Providers object to almostdo exactly what I want:
更新 2009-07-09:我了解到我可以使用 Providers 对象几乎完全按照我想要的做:
@Context Providers ps;
MessageBodyWriter uw = ps.getMessageBodyWriter(UserInfoImpl.class, UserInfoImpl.class, new Annotation[0], MediaType.APPLICATION_JSON_TYPE);
uw.writeTo(....)
... This writes the object as json to any outputstream, which would be perfect for me, but I can only get at the Providers object using @Context from a @Component object. Does anyone know how to access it from a regular, un-annotated POJO? Thanks!
...这将对象作为 json 写入任何输出流,这对我来说是完美的,但我只能使用 @Component 对象中的 @Context 获取 Providers 对象。有谁知道如何从常规的、未注释的 POJO 访问它?谢谢!
采纳答案by Andy O
Jersey uses a couple different frameworks depending on whether you use mapped(), badgerfish(), or natural() notation. Natural is usually the one people want. And that's implemented using the very good (and very fast) standalone Hymanson JSON processor, I believe, which goes from Object->JAXB->JSON. However Hymanson also provides it's own JAX-RS provider to go direct Object->JSON.
Jersey 使用几个不同的框架,具体取决于您使用的是 Mapped()、badgerfish() 还是 natural() 表示法。自然通常是人们想要的。我相信这是使用非常好的(并且非常快的)独立 Hymanson JSON 处理器实现的,它来自 Object->JAXB->JSON。然而,Hymanson 也提供了它自己的 JAX-RS 提供程序来直接使用 Object->JSON。
In fact, they even added support for JAXB annotations. Have a look at
事实上,他们甚至增加了对 JAXB 注释的支持。看一下
http://wiki.fasterxml.com/HymansonJAXBAnnotations
http://wiki.fasterxml.com/HymansonJAXBAnnotations
I think that's ultimately what you are looking for. Hymanson does Object<->JSON processing...Jersey just makes the calls for you
我认为这最终是你要找的。Hymanson 进行 Object<->JSON 处理...Jersey 只是为您打电话
回答by Ondra ?i?ka
Here's a simple brief example of using JAXB to map objects to JSON (using Hymanson):
下面是一个使用 JAXB 将对象映射到 JSON(使用 Hymanson)的简单示例:
http://ondra.zizka.cz/stranky/programovani/java/jaxb-json-Hymanson-howto.texy
http://ondra.zizka.cz/stranky/programovani/java/jaxb-json-Hymanson-howto.texy
回答by RimasK
ObjectMapper mapper = new ObjectMapper();
String str = mapper.writeValueAsString(pojoObject);
回答by ramon_salla
JAXB annotations work fine when serializing to XML. The main problem is that JAXB does not support empty arrays. So when serializing something like this...
JAXB 注释在序列化为 XML 时工作正常。主要问题是 JAXB 不支持空数组。所以当序列化这样的东西时......
List myArray = new ArrayList();
...to json via jaxb anottations all your empty arrays become null instead of [].
...通过 jaxb 注释到 json,所有空数组都变为空而不是 []。
To solve this you can just serialize your pojos directly to json via Hymanson.
要解决这个问题,您可以通过 Hymanson 将您的 pojo 直接序列化为 json。
Take a look at this from Jersey's user guide: http://jersey.java.net/nonav/documentation/latest/user-guide.html#d0e1959
看看泽西岛的用户指南:http: //jersey.java.net/nonav/documentation/latest/user-guide.html#d0e1959
This is the best way to use Hymanson provider without JAXB. Moreover, you can always use the latest version of Hymanson by downlaoding Hymanson-all-x.y.z-jar from its web.
这是在没有 JAXB 的情况下使用 Hymanson 提供程序的最佳方式。此外,您始终可以通过从其网站下载 Hymanson-all-xyz-jar 来使用最新版本的 Hymanson。
This method will not interfere with your jaxb annotations so I would suggest to have a try!
此方法不会干扰您的 jaxb 注释,因此我建议您尝试一下!
回答by Hyman Cox
Since Jersey is a reference implementation of JAX-RS and JAX-RS is focused completely on providing a standard way of implementing the end-point for the REST service the issues of serializing the payload is left to other standards.
由于 Jersey 是 JAX-RS 的参考实现,而 JAX-RS 完全专注于提供实现 REST 服务端点的标准方法,因此序列化有效负载的问题留给其他标准。
I think that if they included object serialization in the JAX-RS standard it would quickly become a large multi-headed beast that would be difficult to implement and loose some of it's focus.
我认为,如果他们在 JAX-RS 标准中包含对象序列化,它将很快成为一个难以实现的大型多头野兽,并且会失去一些重点。
I appreciate how focused Jersey is on delivering clean and simple to use REST endpoints. In my case I've just subclassed a parent that has all the JAXB plumbing in it so marshalling objects between binary and XML is very clean.
我很欣赏 Jersey 专注于提供干净且易于使用的 REST 端点。在我的例子中,我刚刚子类化了一个包含所有 JAXB 管道的父级,因此在二进制和 XML 之间编组对象非常干净。
回答by Archimedes Trajano
With a little Jersey specific bootstrapping, you can use it to create the necessary JSON objects for you. You need to include the following dependencies (you can use bundle, but it will cause problems if you are using Weld for testing):
通过一些 Jersey 特定的引导,您可以使用它为您创建必要的 JSON 对象。您需要包含以下依赖项(您可以使用bundle,但如果您使用Weld 进行测试会导致问题):
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>1.12</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.12</version>
</dependency>
From there you can create a JAXB annotated class. The following is an example:
从那里您可以创建一个 JAXB 注释类。下面是一个例子:
@XmlRootElement
public class TextMessage {
private String text;
public String getText() { return text; }
public void setText(String s) { this.text = text; }
}
Then you can create the following unit test:
然后您可以创建以下单元测试:
TextMessage textMessage = new TextMessage();
textMessage.setText("hello");
textMessage.setUuid(UUID.randomUUID());
// Jersey specific start
final Providers ps = new Client().getProviders();
// Jersey specific end
final MultivaluedMap<String, Object> responseHeaders = new MultivaluedMap<String, Object>() {
@Override
public void add(final String key, final Object value) {
}
@Override
public void clear() {
}
@Override
public boolean containsKey(final Object key) {
return false;
}
@Override
public boolean containsValue(final Object value) {
return false;
}
@Override
public Set<java.util.Map.Entry<String, List<Object>>> entrySet() {
return null;
}
@Override
public List<Object> get(final Object key) {
return null;
}
@Override
public Object getFirst(final String key) {
return null;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public Set<String> keySet() {
return null;
}
@Override
public List<Object> put(final String key, final List<Object> value) {
return null;
}
@Override
public void putAll(
final Map<? extends String, ? extends List<Object>> m) {
}
@Override
public void putSingle(final String key, final Object value) {
}
@Override
public List<Object> remove(final Object key) {
return null;
}
@Override
public int size() {
return 0;
}
@Override
public Collection<List<Object>> values() {
return null;
}
};
final MessageBodyWriter<TextMessage> messageBodyWriter = ps
.getMessageBodyWriter(TextMessage.class, TextMessage.class,
new Annotation[0], MediaType.APPLICATION_JSON_TYPE);
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
Assert.assertNotNull(messageBodyWriter);
messageBodyWriter.writeTo(textMessage, TextMessage.class,
TextMessage.class, new Annotation[0],
MediaType.APPLICATION_JSON_TYPE, responseHeaders, baos);
final String jsonString = new String(baos.toByteArray());
Assert.assertTrue(jsonString.contains("\"text\":\"hello\""));
The advantage to this approach is it keeps everything within the JEE6 API, no external libraries are explicitly needed except for testing and getting the providers. However, you need to create an implementation of MultivaluedMap since there is nothing provided in the standard and we don't actually use it. It mayalso be slower than GSON, and a lot more complicated than necessary.
这种方法的优点是它将所有内容都保留在 JEE6 API 中,除了测试和获取提供程序外,不需要任何外部库。但是,您需要创建 MultivaluedMap 的实现,因为标准中没有提供任何内容,我们实际上也没有使用它。这可能也比GSON慢,很多超过必要的复杂。
回答by Archimedes Trajano
I understand XML views but it would have shown some foresight to require JSON support for POJOs as standard equipment. Having to doctor up JSON identifiers with special characters makes no sense if your implementation is JSON and your client is a JavaScript RIA.
我理解 XML 视图,但它会显示出一些远见,要求 POJO 支持 JSON 作为标准设备。如果您的实现是 JSON 并且您的客户端是 JavaScript RIA,那么必须用特殊字符修改 JSON 标识符是没有意义的。
Also, not that Java Beans are NOT POJOs. I would like to use something like this on the outer surface of my web tier:
此外,并不是说 Java Bean 不是 POJO。我想在我的网络层的外表面上使用这样的东西:
public class Model
{
@Property height;
@Property weight;
@Property age;
}
No default constructor, no getter/setter noise, just a POJO with my own annotations.
没有默认构造函数,没有 getter/setter 噪音,只是一个带有我自己注释的 POJO。

