随分前に発表された DocumentDB だが、意外にサンプルが少ないので触ってみたところを軽く記載する。DocumentDB は JSON 形式でデータをやり取りするため、Java オブジェクトを JSON 形式に変換する必要がある。
Build a Java web application using DocumentDB に記載されたサンプルを見ると Project Lombok を利用しているが、今回は jackson を使ってみた。
まず、あらかじめ管理ポータルから DocumentDB アカウントを作成し、"TestDB" というデータベースの作成、"TestCollection" というコレクションの作成、以下の様にドキュメントの作成を実施する。
次に、管理ポータルからエンドポイントとキーを取得し、以下のコードを実行する。
- SampleTest.java
package com.mydomain.documentdb; import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.Properties; import org.codehaus.jackson.JsonParseException; import org.codehaus.jackson.map.JsonMappingException; import org.codehaus.jackson.map.ObjectMapper; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import com.microsoft.azure.documentdb.ConnectionPolicy; import com.microsoft.azure.documentdb.ConsistencyLevel; import com.microsoft.azure.documentdb.Database; import com.microsoft.azure.documentdb.Document; import com.microsoft.azure.documentdb.DocumentClient; import com.microsoft.azure.documentdb.DocumentClientException; import com.microsoft.azure.documentdb.DocumentCollection; import com.microsoft.azure.documentdb.RequestOptions; import com.mydomain.model.Person; public class SampleTest { // Define an id for your database and collection private static final String DATABASE_ID = "TestDB"; private static final String COLLECTION_ID = "TestCollection"; // documentdb.properties から情報を取得 private static String END_POINT; private static String MASTER_KEY; private static DocumentClient documentClient; private static Database databaseCache; private static DocumentCollection collectionCache; @Before public void testInitialize() throws IOException { // TODO: 外部設定ファイルを作成すること String path = "documentdb.properties"; InputStream in = SampleTest.class.getClassLoader().getResourceAsStream( path); if (in == null) { throw new IllegalArgumentException(path + " not found."); } Properties props = new Properties(); props.load(in); END_POINT = props.getProperty("END_POINT"); MASTER_KEY = props.getProperty("MASTER_KEY"); documentClient = new DocumentClient(END_POINT, MASTER_KEY, ConnectionPolicy.GetDefault(), ConsistencyLevel.Session); } @Test public void readTest01() throws DocumentClientException, JsonParseException, JsonMappingException, IOException { Person expected = new Person(); Person actual; expected.setAge(45); expected.setName("割と普通"); List<Document> documentList = documentClient .queryDocuments(getTestCollection().getSelfLink(), "SELECT * FROM root r WHERE r.id='" + 1 + "'", null) .getQueryIterable().toList(); ObjectMapper mapper = new ObjectMapper(); actual = mapper.readValue(documentList.get(0).toString(), Person.class); Assert.assertEquals(expected, actual); } private Database getTestDBDatabase() { if (databaseCache == null) { // Get the database if it exists List<Database> databaseList = documentClient .queryDatabases( "SELECT * FROM root r WHERE r.id='" + DATABASE_ID + "'", null).getQueryIterable().toList(); if (databaseList.size() > 0) { // Cache the database object so we won't have to query for it // later to retrieve the selfLink. databaseCache = databaseList.get(0); } else { // Create the database if it doesn't exist. try { Database databaseDefinition = new Database(); databaseDefinition.setId(DATABASE_ID); databaseCache = documentClient.createDatabase( databaseDefinition, null).getResource(); } catch (DocumentClientException e) { // TODO: e.printStackTrace(); } } } return databaseCache; } private DocumentCollection getTestCollection() { if (collectionCache == null) { // Get the collection if it exists. List<DocumentCollection> collectionList = documentClient .queryCollections( getTestDBDatabase().getSelfLink(), "SELECT * FROM root r WHERE r.id='" + COLLECTION_ID + "'", null).getQueryIterable().toList(); if (collectionList.size() > 0) { // Cache the collection object so we won't have to query for it // later to retrieve the selfLink. collectionCache = collectionList.get(0); } else { // Create the collection if it doesn't exist. try { DocumentCollection collectionDefinition = new DocumentCollection(); collectionDefinition.setId(COLLECTION_ID); // Configure the new collection performance tier to S1. RequestOptions requestOptions = new RequestOptions(); requestOptions.setOfferType("S1"); collectionCache = documentClient.createCollection( getTestDBDatabase().getSelfLink(), collectionDefinition, requestOptions).getResource(); } catch (DocumentClientException e) { // TODO: e.printStackTrace(); } } } return collectionCache; } }
- Person.java
package com.mydomain.model; public class Person { int age; String name; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public boolean equals(Object obj) { if (obj instanceof Person == false) return false; Person p = (Person) obj; boolean isAgeSame = age == p.getAge(); boolean isNameSame = name == null ? p.getName() == null : // name.equals(p.getName()); return isAgeSame && isNameSame; } }
上記を実行すると、以下のエラーが発生する。
org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Unrecognized field "_attachments" (Class com.mydomain.model.Person), not marked as ignorable at [Source: java.io.StringReader@1bb5a082; line: 1, column: 18] (through reference chain: com.mydomain.model.Person["_attachments"]) at org.codehaus.jackson.map.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:53) at org.codehaus.jackson.map.deser.StdDeserializationContext.unknownFieldException(StdDeserializationContext.java:246) at org.codehaus.jackson.map.deser.StdDeserializer.reportUnknownProperty(StdDeserializer.java:604) at org.codehaus.jackson.map.deser.StdDeserializer.handleUnknownProperty(StdDeserializer.java:590) at org.codehaus.jackson.map.deser.BeanDeserializer.handleUnknownProperty(BeanDeserializer.java:689) at org.codehaus.jackson.map.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:514) at org.codehaus.jackson.map.deser.BeanDeserializer.deserialize(BeanDeserializer.java:350) at org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:2395) at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1595) at com.mydomain.documentdb.SampleTest.readTest01(SampleTest.java:61) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) (中略)
不明なフィールドである _attachments が存在する様だ。念のためやり取りされる JSON データを見ると以下の様に複数のフィールドが追加されている。
{_attachments=attachments/, _rid=i-ZOANFBawACAAAAAAAAAA==, name=割と普通, id=1, _self=dbs/i-ZOAA==/colls/i-ZOANFBawA=/docs/i-ZOANFBawACAAAAAAAAAA==/, age=45, _etag="00001000-0000-0000-0000-5560769f0000", _ts=1432385183}
こちらの問題に対応するには以下の様に jackson 特有のアノテーションを追加して不明なプロパティの無視を指定する。
package com.mydomain.model; import org.codehaus.jackson.annotate.JsonIgnoreProperties; @JsonIgnoreProperties(ignoreUnknown = true) public class Person { int age; String name; //(中略)
読み込みの場合は上記で良いのだが、書き込みの場合(特に更新)では今回無視したフィールドが必要なことが懸念される。こちらに対する調査はまた後日で。