首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >How do I i18n JAX-RS (Jersey) JAXB注释响应

How do I i18n JAX-RS (Jersey) JAXB注释响应
EN

Stack Overflow用户
提问于 2012-01-20 23:47:40
回答 3查看 4.3K关注 0票数 4

我们在从Web API返回的模型对象上使用JAXB注释,我们希望数据本地化,并根据用户偏好设置其他值的格式(例如,指标与法规)。我们通过向Marshaller添加自定义适配器来实现这一点。

代码语言:javascript
复制
Marshaller marshaller = jc.createMarshaller();
marshaller.setAdapter(NumberPersonalizedXmlAdapter.class,
          new NumberPersonalizedXmlAdapter(locale);
marshaller.marshal(expected, writer);

尝试最简单的方法,我将只从HTTP请求头部获取区域设置,并将其提供给其中一个MessageBodyWriter类中的Marshaller。

我考虑过扩展像XMLRootElementProvider这样的默认注册提供者,但意识到它们大多是最终版本,所以我放弃了这种方法。无论如何,我至少需要扩展10个类,所以这并不理想。

有人知道如何最好地让MessageBodyWriter中的编组程序为每个请求设置customer Adapter吗?我很确定这和ContextResolver有关。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-01-21 09:58:14

与编写MessageBodyWriter相比,为编组编写ContextResolver会产生更干净、更合适的解决方案。所有JAXB类都使用Providers.getContextResolver方法来获取编组程序。我提供了我的自定义ContextResolver,并且我有i18n响应。

代码语言:javascript
复制
@Provider
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public class JaxbPersonalizerContextResolver implements ContextResolver<Marshaller> {

    private HttpHeaders requestHeaders;

    public JaxbPersonalizerContextResolver(@Context HttpHeaders requestHeaders) {
        this.requestHeaders = requestHeaders;
    }

    @Override
    public Marshaller getContext(Class<?> type) {
        Locale locale = If.first(this.requestHeaders.
                                    getAcceptableLanguages(), Locale.US);
        NumberFormat formatter = NumberFormat.getNumberInstance(locale);
        formatter.setMaximumFractionDigits(1);

        Marshaller marshaller;
        try {
            JAXBContext jc = JAXBContext.newInstance(type);
            marshaller = jc.createMarshaller();
        } catch (JAXBException e) {
            throw new RuntimeException(e);
        }
        marshaller.setAdapter(QuantityXmlAdapter.class, 
                           new QuantityXmlAdapter.Builder().locale(locale).build());
        marshaller.setAdapter(NumberPersonalizedXmlAdapter.class,
                new NumberPersonalizedXmlAdapter.Builder().
                                    formatter(formatter).build());
        return marshaller;
    }
}

JSON没有本地化,在一些调查之后,我意识到使用Jackson JSON库而不是与Jersey库一起分发的JAXBJSONElementProvider。I removed the POJOMappingFeature configuration in web.xml,我已经本地化了JSON,然而,它不如Jackson JSON好。

一个非常干净的解决方案,这让我认为JAX-RS和Jersey实现做得非常好。

票数 4
EN

Stack Overflow用户

发布于 2012-01-21 09:45:43

我通过编写自己的MessageBodyWriter解决了这个问题,它接收注入到构造函数中的HttpHeaders,我稍后编写响应时会用到该构造函数。我将包括整个类,因为它不是那么大。

代码语言:javascript
复制
@Produces(MediaType.APPLICATION_XML)
@Provider
public class JaxbPersonalizationProvider implements MessageBodyWriter<Object> {

    private HttpHeaders requestHeaders;
    private Providers providers;

    public JaxbPersonalizationProvider(@Context HttpHeaders requestHeaders, @Context Providers providers) {
        this.requestHeaders = requestHeaders;
        this.providers = providers;
    }

    @Override
    public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        return type.getAnnotation(XmlRootElement.class) != null && mediaType.equals(MediaType.APPLICATION_XML_TYPE);
    }

    @Override
    public long getSize(Object t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        return -1;
    }

    @Override
    public void writeTo(Object t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType,
            MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException,
            WebApplicationException {
        Locale locale = If.first(this.requestHeaders.getAcceptableLanguages(), Locale.US);
        NumberFormat formatter = NumberFormat.getNumberInstance(locale);
        formatter.setMaximumFractionDigits(1);

        Marshaller marshaller;
        try {
            JAXBContext jc = JAXBContext.newInstance(TrackInfo.class);
            marshaller = jc.createMarshaller();
            marshaller.setAdapter(QuantityXmlAdapter.class, new QuantityXmlAdapter.Builder().locale(locale).build());
            marshaller.setAdapter(NumberPersonalizedXmlAdapter.class, new NumberPersonalizedXmlAdapter.Builder()
                    .formatter(formatter).build());

            marshaller.marshal(t, entityStream);
        } catch (JAXBException e) {
            throw new RuntimeException(e);
        }
    }
}

它使用默认语言环境en-US生成以下xml摘录:

代码语言:javascript
复制
 <display lang="en_US">
    <value>3,286.1</value>
 </display>

以及在报头中发送fr-FR的区域设置时的xml摘录:

代码语言:javascript
复制
 <display lang="fr_FR">
   <value>3 286,1</value>
 </display>

这种方法仍然不理想,因为我现在需要为JSON编写一个类似的MessageBodyWriter,或者在这个MessageBodyWriter中添加对JSON的支持。此外,我假设默认的JAXB提供程序正在进行一些我没有利用的调整。

票数 1
EN

Stack Overflow用户

发布于 2012-01-21 02:15:33

对于这种用例,MessageBodyWriter是正确的方法。我建议在您的MessageBodyWriter中添加以下字段

代码语言:javascript
复制
@javax.ws.rs.core.Context
protected Providers providers;

然后使用它来访问JAXBContext以创建Marshaller

代码语言:javascript
复制
public void writeTo(DataObject dataObject, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> multivaluedMap, OutputStream outputStream) throws IOException, WebApplicationException {
    JAXBContext jaxbContext = null;
    ContextResolver<JAXBContext> resolver = providers.getContextResolver(JAXBContext.class, arg3);
    if(null != resolver) {
        jaxbContext = resolver.getContext(type);
    }
    if(null == jaxbContext) {
        jaxbContext = JAXBContext.newInstance(type);
    }
    Marshaller marshaller = jaxbContext.createMarshaller();
}

相关示例

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8944025

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档