2012-01-20 14 views
4

Web APIから返されるモデルオブジェクトに対してJAXB注釈を使用しており、ユーザーの好みに基づいてデータをローカライズし、他の値にフォーマットしたいメトリック対法令)。 Marshallerにカスタムアダプターを追加することでこれを行います。最も簡単な方法私はHTTPリクエストヘッダからロケールを取得し、MessageBodyWriterクラスのいずれかにマーシャラーにそれを提供しますをしようとJAX-RS(Jersey)JAXB注釈付き応答の方法

Marshaller marshaller = jc.createMarshaller(); 
marshaller.setAdapter(NumberPersonalizedXmlAdapter.class, 
      new NumberPersonalizedXmlAdapter(locale); 
marshaller.marshal(expected, writer); 

私はXMLRootElementProviderのような既定の登録プロバイダを拡張することを検討しましたが、ほとんど最終的に書かれているので、私はそのアプローチを断念しました。とにかく私は理想的ではなかったので、少なくとも10のクラスが必要でした。

MessageBodyWriterで顧客アダプタごとにリクエストごとにmarshallerを取得するにはどうすればいいですか?私はそれがContextResolverと何か関係があると確信しています。

答えて

4

マーシャリングのためのContextResolverを書くと、MessageBodyWriterを書くよりはるかにクリーンで適切な解決策になります。すべてのJAXBクラスは、Providers.getContextResolverメソッドを使用してマーシャラを取得します。私は私のカスタムContextResolverを提供し、私はi18n応答を持っています。

@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はローカライズされていませんでしたし、いくつかの調査の後、私はジャクソンJSONライブラリではなくJAXBJSONElementProviderの使用ジャージーライブラリと一緒に配布されていたが実現しました。私は012.xmlのweb.xmlにありますが、私はJSONをローカライズしていますが、Jackson JSONほど面白くありません。

JAX-RSとJerseyの実装が非常にうまくいっていると思う非常にきれいな解決策です。

0

MessageBodyWriterは、この使用例の正しいアプローチです。私はあなたのMessageBodyWriterに次のフィールドを追加することをお勧めします:

@javax.ws.rs.core.Context 
protected Providers providers; 

そして

  • Validate JAXBElement in JPA/JAX-RS Web Service
  • Marshaller

    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(); 
    } 
    

    関連の例を作成するたJAXBContextにアクセスするためにそれを使用して

1

私は後でレスポンスを書くときに使うコンストラクタに注入されたHttpHeadersを受け取る私自身のMessageBodyWriterを書く問題を解決しました。それはそれほど大きくないので、私はクラス全体を含めます。 FR-FRのロケールがヘッダに送信され

<display lang="en_US"> 
    <value>3,286.1</value> 
</display> 

と、このXMLの抜粋:

<display lang="fr_FR"> 
    <value>3 286,1</value> 
</display> 
EN-USのデフォルトロケールで、このXMLの抜粋を生成

@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); 
     } 
    } 
} 

このアプローチはまだ理想的ではありません。JSON用に同様のMessageBodyWriterを作成するか、このMessageBodyWriterにJSONサポートを追加する必要があります。また、デフォルトのJAXBプロバイダが私が利用していない調整を​​行っていると仮定します。

関連する問題