调查
环境:泽西岛 2.13(所有提供程序版本也是 2.13)。
无论使用声明性链接还是编程式链接,序列化都不应有所不同。我选择了程序化,只是因为我可以:-)
测试类:
@XmlRootElement
public class TestClass {
private javax.ws.rs.core.Link link;
public void setLink(Link link) { this.link = link; }
@XmlElement(name = "link")
@XmlJavaTypeAdapter(Link.JaxbAdapter.class)
public Link getLink() { return link; }
}
@Path("/links")
public class LinkResource {
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getResponse() {
URI uri = URI.create("https://stackoverflow.com/questions/24968448");
Link link = Link.fromUri(uri).rel("stackoverflow").build();
TestClass test = new TestClass();
test.setLink(link);
return Response.ok(test).build();
}
}
@Test
public void testGetIt() {
WebTarget baseTarget = target.path("links");
String json = baseTarget.request().accept(
MediaType.APPLICATION_JSON).get(String.class);
System.out.println(json);
}
使用不同提供程序的结果(无需额外配置)
平纹针织-介质-莫克西
屬地
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
</dependency>
结果(奇怪)
{
"link": "javax.ws.rs.core.Link$JaxbLink@cce17d1b"
}
jersey-media-json-jackson
屬地
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
</dependency>
结果(关闭,但有什么?params
{
"link": {
"params": {
"rel": "stackoverflow"
},
"href": "https://stackoverflow.com/questions/24968448"
}
}
jackson-jaxrs-json-provider
屬地
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.4.0</version>
</dependency>
结果(两个不同的结果,具有两个不同的 JSON 提供程序)
resourceConfig.register(JacksonJsonProvider.class);
{
"link": {
"uri": "https://stackoverflow.com/questions/24968448",
"params": {
"rel": "stackoverflow"
},
"type": null,
"uriBuilder": {
"absolute": true
},
"rels": ["stackoverflow"],
"title": null,
"rel": "stackoverflow"
}
}
resourceConfig.register(JacksonJaxbJsonProvider.class);
{
"link": {
"params": {
"rel": "stackoverflow"
},
"href": "https://stackoverflow.com/questions/24968448"
}
}
我结论
我们用 对字段进行注释。让我们看一下此适配器的一个片段@XmlJavaTypeAdapter(Link.JaxbAdapter.class)
public static class JaxbAdapter extends XmlAdapter<JaxbLink, Link> {...}
所以从 ,我们被编组到Link
JaxbLink
public static class JaxbLink {
private URI uri;
private Map<QName, Object> params;
...
}
平纹针织-介质-莫克西
似乎是一个错误...请参阅下面的解决方案。
其他
另外两个依赖于 jackson-module-jaxb-annotations
来处理使用 JAXB 注释的编组。 将自动注册所需的 .对于 ,使用将不支持 JAXB 注释(没有 confgiruation),而 using 将给予 JAXB 注释支持。jersey-media-json-jackson
JaxbAnnotationModule
jackson-jaxrs-json-provider
JacksonJsonProvider
JacksonJsonJaxbProvider
因此,如果我们有 JAXB 注释支持,我们将被编组到 ,这将给出这个结果JaxbLink
{
"link": {
"params": {
"rel": "stackoverflow"
},
"href": "https://stackoverflow.com/questions/24968448"
}
}
我们可以获得所有不需要的属性的结果的方法是1),使用's或2),创建一个我们不注册.你似乎正在做其中之一。jackson-jaxrs-json-provider
JacksonJsonProvider
ContextResolver
ObjectMapper
JaxbAnnotationModule
解决 方案
上述内容仍然没有让我们到达我们想要到达的地方(即没有)。params
对于 jersey-media-json-jackson
和 jackson-jaxrs-json-provider
...
...使用Jackson,此时我唯一能想到的就是创建自定义序列化程序
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import javax.ws.rs.core.Link;
public class LinkSerializer extends JsonSerializer<Link>{
@Override
public void serialize(Link link, JsonGenerator jg, SerializerProvider sp)
throws IOException, JsonProcessingException {
jg.writeStartObject();
jg.writeStringField("rel", link.getRel());
jg.writeStringField("href", link.getUri().toString());
jg.writeEndObject();
}
}
然后为 创建一个,在其中注册序列化程序ContextResolver
ObjectMapper
@Provider
public class ObjectMapperContextResolver
implements ContextResolver<ObjectMapper> {
private final ObjectMapper mapper;
public ObjectMapperContextResolver() {
mapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Link.class, new LinkSerializer());
mapper.registerModule(simpleModule);
}
@Override
public ObjectMapper getContext(Class<?> type) {
return mapper;
}
}
这就是结果
{
"link": {
"rel": "stackoverflow",
"href": "https://stackoverflow.com/questions/24968448"
}
}
使用 jersey-media-moxy 时,类中似乎有一个 Bug 缺少二传手,因此编组将恢复为调用 ,如上所示。正如Garard Davidson在这里所建议的那样,解决方法只是创建另一个适配器。JaxbLink
toString
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.core.Link;
import javax.xml.bind.annotation.XmlAnyAttribute;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.namespace.QName;
public class LinkAdapter
extends XmlAdapter<LinkJaxb, Link> {
public LinkAdapter() {
}
public Link unmarshal(LinkJaxb p1) {
Link.Builder builder = Link.fromUri(p1.getUri());
for (Map.Entry<QName, Object> entry : p1.getParams().entrySet()) {
builder.param(entry.getKey().getLocalPart(), entry.getValue().toString());
}
return builder.build();
}
public LinkJaxb marshal(Link p1) {
Map<QName, Object> params = new HashMap<>();
for (Map.Entry<String,String> entry : p1.getParams().entrySet()) {
params.put(new QName("", entry.getKey()), entry.getValue());
}
return new LinkJaxb(p1.getUri(), params);
}
}
class LinkJaxb {
private URI uri;
private Map<QName, Object> params;
public LinkJaxb() {
this (null, null);
}
public LinkJaxb(URI uri) {
this(uri, null);
}
public LinkJaxb(URI uri, Map<QName, Object> map) {
this.uri = uri;
this.params = map!=null ? map : new HashMap<QName, Object>();
}
@XmlAttribute(name = "href")
public URI getUri() {
return uri;
}
@XmlAnyAttribute
public Map<QName, Object> getParams() {
return params;
}
public void setUri(URI uri) {
this.uri = uri;
}
public void setParams(Map<QName, Object> params) {
this.params = params;
}
}
改用此适配器
@XmlElement(name = "link")
@XmlJavaTypeAdapter(LinkAdapter.class)
private Link link;
将给我们所需的输出
{
"link": {
"href": "https://stackoverflow.com/questions/24968448",
"rel": "stackoverflow"
}
}
更新
现在我想起来了,这也将与杰克逊提供商合作。无需创建 Jackson 序列化程序/反序列化程序。Jackson 模块应该已经支持开箱即用的 JAXB 注释,前提是启用了 JAXB 注释。上面的示例显示了单独使用 JAXB/JSON 提供程序,但假设只启用了 JAXB 提供程序,则应使用该提供程序的 JAXB 版本。这实际上可能是更可取的解决方案。无需为:-D创建LinkAdapter
JacksonFeature
JacksonFeature
ContextResolvers
ObjectMapper
也可以在包级别声明注释,如此处所示