JAX-WSの最終回である今週はRESTful WebサービスをJAX-WSとJAXBで扱ってみましょう。今週使用するRESTのサービスは,前回と同じFlickrのWeb APIです。サンプルも前回と同じですが,Flickrのサービスを呼び出す部分だけ変更します。

JAXBを使用するためにはXML Schemaなどのスキーマが定義されていないといけません。しかし,公開されているRESTのサービスは,かなりの割合でスキーマは公開されていません。残念ながら,FlickrのWeb APIもスキーマは公開されていません。

しかたないので,スキーマを自作することにしましょう。

Flickrのイメージ検索では,次に示すようなXMLドキュメントが結果として帰ってくることは前回紹介したとおりです。

<?xml version="1.0" encoding="UTF-8"?>
<rsp stat="ok">
  <photos page="1" pages="56" perpage="100" total="5508">
    <photo id="2768402844" 
           owner="57085156@N00" 
           secret="3ce02239b4" 
           server="3056" 
           farm="4"
           title="Macarons, Pierre Herm・, Shinjuku Isetan" 
           ispublic="1"
           isfriend="0"
           isfamily="0" />
    <photo id="2768391122" 
           owner="57085156@N00" 
           secret="6c8c2447f5"
           server="3139"
           farm="4"
           title="Macarons, Pierre Herm・, Shinjuku Isetan" 
           ispublic="1" 
           isfriend="0" 
           isfamily="0" />
    
        ~ 以下省略 ~

これをベースにXML Schemaを記述したものを以下に示します。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" 
           xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
           jxb:version="2.1">
 
  <xs:annotation>
    <xs:appinfo>
      <jxb:schemaBindings>
        <jxb:package name="net.javainthebox.rest.bind"/>
      </jxb:schemaBindings>
    </xs:appinfo>
  </xs:annotation>
 
  <xs:element name="rsp" type="rsp"/>
 
  <xs:complexType name="photo">
    <xs:sequence/>
    <xs:attribute name="id" type="xs:long" use="required"/>
    <xs:attribute name="owner" type="xs:string" use="required"/>
    <xs:attribute name="secret" type="xs:string" use="required"/>
    <xs:attribute name="server" type="xs:long" use="required"/>
    <xs:attribute name="farm" type="xs:int" use="required"/>
    <xs:attribute name="title" type="xs:string" use="required"/>
    <xs:attribute name="ispublic" type="xs:int" use="required"/>
    <xs:attribute name="isfriend" type="xs:int" use="required"/>
    <xs:attribute name="isfamily" type="xs:int" use="required"/>
  </xs:complexType>
 
  <xs:complexType name="photos">
    <xs:sequence>
      <xs:element name="photo" type="photo" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
    <xs:attribute name="page" type="xs:int" use="required"/>
    <xs:attribute name="pages" type="xs:int" use="required"/>
    <xs:attribute name="perpage" type="xs:int" use="required"/>
    <xs:attribute name="total" type="xs:int" use="required"/>
  </xs:complexType>
 
  <xs:complexType name="rsp">
    <xs:sequence>
      <xs:element name="photos" type="photos" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="stat" type="xs:string"/>
  </xs:complexType>
</xs:schema>

FlickrのWeb APIは名前空間を指定していないので,そのままスキーマからJavaのクラスを生成するとデフォルトパッケージになってしまいます。それを避けるために,JAXBのカスタマイズを用いて,パッケージを指定しました(青字部分)。

詳しくはJava SE 6完全攻略の第78回第79回を参照していただくとして,<schemaBindings>タグを使用してスキーマレベルでのカスタマイズを行うことができます。ここでは<package>タグでパッケージをnet.javainthebox.rest.bindと指定しています。

後は通常のXML Schemaです。

このスキーマは推測で作成しため,不正確な部分が多々あります。しかし,描画に必要な情報さえ取得できればいいので,不正確な部分もそのままにしてあります。

たとえば,<photo>要素のispublicアトリビュートやisfriendアトリビュートは正確に記述すれば0か1のbooleanなのですが,ここでは単に整数として定義しています。また,エラーの場合の扱いをここではまったく考慮していません。もし,興味があるようであれば,ご自分でエラーページも考慮したスキーマを作成してみるのもいいと思います。