Build a Java web application using DocumentDB に記載されたサンプルを見ると Project Lombok を利用しているが、今回は jackson を使ってみた。
まず、あらかじめ管理ポータルから DocumentDB アカウントを作成し、"TestDB" というデータベースの作成、"TestCollection" というコレクションの作成、以下の様にドキュメントの作成を実施する。
次に、管理ポータルからエンドポイントとキーを取得し、以下のコードを実行する。
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 {
private static final String DATABASE_ID = "TestDB";
private static final String COLLECTION_ID = "TestCollection";
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) {
List<Database> databaseList = documentClient
.queryDatabases(
"SELECT * FROM root r WHERE r.id='" + DATABASE_ID
+ "'", null).getQueryIterable().toList();
if (databaseList.size() > 0) {
databaseCache = databaseList.get(0);
} else {
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) {
List<DocumentCollection> collectionList = documentClient
.queryCollections(
getTestDBDatabase().getSelfLink(),
"SELECT * FROM root r WHERE r.id='" + COLLECTION_ID
+ "'", null).getQueryIterable().toList();
if (collectionList.size() > 0) {
collectionCache = collectionList.get(0);
} else {
try {
DocumentCollection collectionDefinition = new DocumentCollection();
collectionDefinition.setId(COLLECTION_ID);
RequestOptions requestOptions = new RequestOptions();
requestOptions.setOfferType("S1");
collectionCache = documentClient.createCollection(
getTestDBDatabase().getSelfLink(),
collectionDefinition, requestOptions).getResource();
} catch (DocumentClientException e) {
TODO
e.printStackTrace();
}
}
}
return collectionCache;
}
}
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;
読み込みの場合は上記で良いのだが、書き込みの場合(特に更新)では今回無視したフィールドが必要なことが懸念される。こちらに対する調査はまた後日で。