5

假设我在 JAX-RS 1 环境(带有 Jackson 提供程序的 RestEasy 2)中有一个数据类,如下所示:

class Foo {
   int id;
   String name;
   Bar bar;

   ...
}

Bar

class Bar {
   int one;
   String two;
}

现在我想以Bar一种特殊的方式进行序列化(可能取决于所请求的媒体类型(或取决于月相),我会写一个MessageBodyWriter<Bar>

@Provider
@Produces("application/json")
public class BarWriter implements MessageBodyWriter<Bar> {
   ...
}

如果Bar像在

@GET @Path("bar")  
public Bar getBar() { return new Bar(...); }

但是当我请求Foo

@GET @Path("foo")  
public Foo getFoo() { return new Foo(...); }

消息正文作者被忽略。

现在我想要的是MessageBodyWriter当我返回FooList<Bar>

我认为后者可以通过MessageBodyWriterList案例编写自定义来实现,但对于前一种情况,我无法为包含Bar字段的所有应用程序类编写消息正文编写器。

关于如何解决这个问题的任何想法?我还尝试在Bar实例上使用杰克逊序列化程序,但看起来这甚至没有被 RestEasy 注册(然后,我认为这种方式无论如何都太脆弱了)。

4

3 回答 3

6

不幸的是,这不是消息正文作者的工作方式。JAX-RS 实现将根据从资源方法返回的类型定位要在序列化中使用的编写器。因此,在您的情况下,使用为 定义的自定义编写器Bar,使用此资源方法:

@GET @Path("bar")  
public Bar getBar() { return new Bar(...); }

JAX-RS 提供程序将Bar使用您的自定义编写器进行序列化。但是对于此资源方法:

@GET @Path("foo")  
public Foo getFoo() { return new Foo(...); }

您没有定义自定义编写器,序列化将由第一个匹配(默认)提供程序处理,该提供程序可以处理返回类和内容类型的组合。要记住的关键一点是,与典型的 JSON 和 XML 序列化库不同,JAX-RS 实体提供程序不是递归的。Aka,对于A在资源方法中返回的给定对象,提供者将尝试仅为定位自定义编写器A,而不是为包含在A变量中的任何类型。

既然您使用的是 Jackson,为什么不为您的Bar类定义一个自定义序列化程序呢?这将处理您描述的几乎所有场景:

public class BarSerializer extends JsonSerializer<Bar> {

    @Override
    public void serialize(final Bar value, final JsonGenerator jgen,
            final SerializerProvider provider) throws IOException,
            JsonProcessingException {

        jgen.writeStartObject();
        jgen.writeFieldName("myBar");
        jgen.writeString(value.getTwo());
        jgen.writeEndObject();
    }
}

你告诉杰克逊使用这个自定义序列化程序:

@JsonSerialize(using=BarSerializer.class)
class Bar {
   int one;
   String two;
}

最后,不要忘记,如果您希望以与序列化相同的形式返回 JSON,您还需要一个自定义的JsonDeserializer.

为了让它工作,你需要在你的类路径中的jackson-mapperjackson-jaxrs罐子(可能也是那个jackson-core)。

于 2013-03-05T18:36:55.667 回答
2

JAX-RS 运行时只会为资源方法返回的对象查找一个MessageBodyWriter(请参阅规范中的“4.2.2 消息体编写器”一节),然后该单个MessageBodyWriter对整个对象图的序列化具有完全控制权返回给客户。

为了实现你想要的行为,你需要一个自定义的MessageBodyWriter每个媒体类型,当它在图中遇到特定类型时,它愿意将对象图的一部分的序列化委托给另一个写入器,然后恢复它自己的逻辑。获取特定类型的委托编写器不会是一个大问题(注入 a javax.ws.rs.ext.Providers和 call getMessageBodyWriter()),但我不认为现有的 xml/json/etc 序列化程序是在考虑到这种扩展的情况下实现的,所以我猜你不能只转发他们。仅仅为此重新实现 xml 编组器也不是一个有吸引力的选择。

于 2013-03-05T18:36:43.220 回答
-1

请参阅下面的帖子,为您的 Java 对象的序列化编写自定义消息正文编写器。

http://h2labz.blogspot.in/2014/12/marshalling-java-to-json-in-jax-rs.html

于 2014-12-22T11:35:28.703 回答