「jackson-databind」とは、JSONとjavaのオブジェクト間の相互変換等のために利用されるjavaのライブラリです。
「ObjectMapper」(ObjectMapper.java)とは「jackson-databind」において上記の機能を提供するクラスです。
(以降、簡単に「jackson」や「ObjectMapper」と表記します)
jacksonやObjectMapperの基本的な使い方に関しては、他の方の記事やjackson-databindのGitHubのドキュメントを参照ください(*1)。
当記事では、
- バイナリデータが与えられる(例:Httpリクエストのリクエストボディ、外部ファイルの入力)
- バイナリデータを出力する(例:Httpレスポンスのレスポンスボディ、外部ファイル書き込み)
場合の、ObjectMapperに対するエンコーディングの指定方法を紹介します。
また、ObjectMapperの動作の背景にあるJSONのエンコーディングの考え方についても言及します。
「エンコーディングの指定方法」は、ざっくり述べると「UTF-8(+α)以外の場合、Reader/Writerを渡すメソッドを使用する」という単純明快なものです。
動作確認した環境やVersion
- jackson-databind 2.9.8 (2019/5/3時点最新版)
- jdk11
デモ用ソースコード
重要なポイントは以下の4点です。以降で(a)~(d)をそれぞれ詳しく見ていきます。
ソースコードはGitHubにもアップロードしています。
- (a). UTF-8, UTF-16, UTF-32を「read」する場合は、エンコーディングの指定は不要
(byte[]やInputStreamを引数に渡すタイプのメソッドを使用可能) - (b). UTF-8, UTF-16, UTF-32以外を「read」する場合は、エンコーディングを明示したReaderを生成し、Readerを引数に渡すタイプのメソッドを使用する
- (c). UTF-8で「write」する場合は、エンコーディングの指定は不要(byte[]やInputStreamを引数に渡すタイプのメソッドを使用可能)
- (d). UTF-8以外で「write」する場合は、エンコーディングを明示したWriterを生成し、Writerを引数に渡すタイプのメソッドを使用する
この記事で使用する文言の補足
- 「read」: 「JSONのバイナリデータ to javaオブジェクト」の変換
- 「write」: 「javaオブジェクト to JSONのバイナリデータ」の変換
調査対象としたObjectMapperのメソッド
- 「read」のメソッド
- 「readValue」の内、第一引数がStringでないもの
- 「readTree」の内、第一引数がStringでないもの
- 「write」のメソッド
- 「wrteValue」
- 「writeTree」
- 「writeValueAsBytes」
「DataOutput」「DataInput」を引数に取るメソッドは他と比べて若干特殊なため「Appendix」で紹介します。
上記のメソッドは様々な引数を取れるようにオーバーロードされています。
対象のメソッドが多いため、対象のすべてのメソッドについてサンプルソースを掲載しているわけではありません。
準備
以降のソースコードで以下の変数やクラスを共通で使用します。
なお、以降のソースコードではリソースのクローズ処理が必要な個所でも一律割愛しています。
ObjectMapper mapper = new ObjectMapper();
String json = "{\"message\":\"あいうえお\"}"; // 「read」するJSON
String readExpected = new Bean("あいうえお").toString();// 「read」の期待値
Bean bean = new Bean("かきくけこ");// 「write」するjavaのオブジェクト
String writeExpected = "{\"message\":\"かきくけこ\"}";// 「write」の期待値
static class Bean {
private String message;
//setter ,getter, コンストラクタ, は割愛
public String toString() {
return "Bean [message=" + message + "]";
}
}
詳細
(a). UTF-8, UTF-16, UTF-32を「read」する場合は、エンコーディングの指定は不要
UTF-8, UTF-16, UTF-32を「read」する場合は、エンコーディングが自動で判定されるため、
byte[]やInputStreamを引数に渡すタイプのメソッドを使用可能です。
/*
* (a) UTF-8, UTF-16, UTF-32を「read」する場合は、エンコーディングの指定は不要
*
* String#getBytesを使用し、任意のエンコーディングのバイトデータが与えられた状況をシミュレートしています
* 確認に使用しているメソッド :
* ObjectMapper#readValue(byte[], Class<T>)<T> : T
*/
@Test
public void readValueFromUTF8or16or32ByteArrayShouldDetectEncodingSuccessfully() throws Exception {
Bean beanFromUTF32BE = mapper.readValue(json.getBytes("UTF-32BE"), Bean.class);
Bean beanFromUTF16BE = mapper.readValue(json.getBytes("UTF-16BE"), Bean.class);
Bean beanFromUTF32LE = mapper.readValue(json.getBytes("UTF-32LE"), Bean.class);
Bean beanFromUTF16LE = mapper.readValue(json.getBytes("UTF-16LE"), Bean.class);
Bean beanFromUTF8 = mapper.readValue(json.getBytes("UTF-8"), Bean.class);
assertThat(beanFromUTF32BE.toString(), equalTo(readExpected));
assertThat(beanFromUTF16BE.toString(), equalTo(readExpected));
assertThat(beanFromUTF32LE.toString(), equalTo(readExpected));
assertThat(beanFromUTF16LE.toString(), equalTo(readExpected));
assertThat(beanFromUTF8.toString(), equalTo(readExpected));
// !! 以下を実行するとExceptionが発生します。
// mapper.readValue(json.getBytes("Shift_JIS"), Bean.class);
// -> 「com.fasterxml.jackson.databind.JsonMappingException: Invalid UTF-8 start byte 0x82」
}
/*
* (a) 上記の「 ObjectMapper#readValue(byte[], Class<T>)<T> : T 」以外の
* 「(a)」パターンとして利用できるメソッド
*/
@Test
public void readMethodsFromAnyUTF8BinaryDataShouldDetectEncodingSuccessfully() throws Exception {
File file = new File("sample_UTF-8.json");
// 第一引数 : URL
Bean beanFromURL = mapper.readValue(file.toURI().toURL(), Bean.class);
assertThat(beanFromURL.toString(), equalTo(readExpected));
// 第一引数 : File
Bean beanFromFile = mapper.readValue(file, Bean.class);
assertThat(beanFromFile.toString(), equalTo(readExpected));
// 第一引数 : InputStream
InputStream inputStream = new FileInputStream(file);
Bean beanFromInputStream = mapper.readValue(inputStream, Bean.class);
assertThat(beanFromInputStream.toString(), equalTo(readExpected));
// 第一引数: JsonParser
// 「createParser」に渡せる引数の種類は、「readValue」の第一引数と似ています
// 以下は、byte[]を渡す例です。
// 他にも、File, URL, InputStream, Readerを渡すメソッド等があります
JsonParser jsonParser = mapper.getFactory().createParser(json.getBytes("UTF-8"));
Bean beanFromJsonParser = mapper.readValue(jsonParser, Bean.class);
assertThat(beanFromJsonParser.toString(), equalTo(readExpected));
// 「readTree」の場合も、「readValue」と同じような引数を渡せます。
// 以下は、byte[]を渡す例です。
JsonNode jsonNode = mapper.readTree(json.getBytes("UTF-8"));
assertThat(jsonNode.get("message").asText(), equalTo("あいうえお"));
}
背景にある(と想定される)JSONの仕様について
最新のJSONの仕様(RFC 8259)では、クローズドなエコシステム以外では「UTF-8」の使用が必須とされています。
一方、現時点のjacksonはRFC 4627を念頭に実装されているようです(*2)。
RFC 4627の「3. Encoding」よると、JSONテキストの先頭2文字は常にASCII文字であるため、JSONテキストの先頭の4バイト(*3)における「00」のパターンにより、「UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE)」が判断できます。
デモ用ソースコードで使用しているJSONテキストにて確認してみます。
JSONテキスト:{"message": "あいうえお"}(先頭2文字は「{"」)
encoding | 先頭4バイト |
---|---|
UTF-32BE | 00 00 00 7B |
UTF-16BE | 00 7B 00 22 |
UTF-32LE | 7B 00 00 00 |
UTF-16LE | 7B 00 22 00 |
UTF-8 | 7B 22 6D 65 |
先頭2バイトの両方が「00」以外であるのはUTF-8のみ、先頭2バイト両方が「00」なのはUTF-32BEのみ・・・・・といった要領でencodingが判定できることがわかります。
動作確認の結果、および以上の理解に基づくならば、UTF-8, UTF-16, UTF-32でエンコードされたバイトデータを「read」する場合には、エンコーディングの指定は不要といえると思われます。
(b). UTF-8, UTF-16, UTF-32以外を「read」する場合は、エンコーディングを明示したReaderを生成し、Readerを引数に渡すタイプのメソッドを使用する
jacksonのjavadoc(*4)にも記載されている通り、UTF-8, UTF-16, UTF-32以外のエンコーディングを使用する場合には、エンコーディングを明示したReaderを生成し、Readerを引数に渡すタイプのメソッドを使用します。
「(a)」に記載したように、jacksonがRFC 4627を念頭に置いているならば、UTF-8, UTF-16, UTF-32以外のエンコーディングを自動判定できない(しない)のは自然な動作です(*5)。
/*
* (b) UTF-8, UTF-16, UTF-32以外を「read」する場合は、
* エンコーディングを明示したReaderを生成し、Readerを引数に渡すタイプのメソッドを使用する
*
* String#getBytesを使用し、任意のエンコーディングのバイトデータが与えられた状況をシミュレートしています
* 確認に使用しているメソッド :
* ObjectMapper#readValue(Reader, Class<T>)<T> : T
*/
@Test
public void readValueFromReaderShouldReadBytesOfSpecifiedEncoding() throws Exception {
// 現実のアプリケーションの例:
// 「InputStream」を HttpServletRequest#getInputStreamから取得する
InputStream inputStream = new ByteArrayInputStream(json.getBytes("Shift_JIS"));
Reader reader = new InputStreamReader(inputStream, "Shift_JIS");
Bean beanFromReader = mapper.readValue(reader, Bean.class);
assertThat(beanFromReader.toString(), equalTo(readExpected));
}
/*
* (b) 上記の「 ObjectMapper#readValue(Reader, Class<T>)<T> : T 」以外の
* 「(b)」パターンとして利用できるメソッド
*/
@Test
public void readMethodsFromReaderShouldReadBytesOfSpecifiedEncoding() throws Exception {
// 第一引数: JsonParser
// 「createParser」にReaderを渡す
Reader reader = new InputStreamReader(new ByteArrayInputStream(json.getBytes("Shift_JIS")), "Shift_JIS");
JsonParser jsonParser = mapper.getFactory().createParser(reader);
Bean beanFromJsonParser = mapper.readValue(jsonParser, Bean.class);
assertThat(beanFromJsonParser.toString(), equalTo(readExpected));
// 「readTree」でもReaderを渡す
Reader readerToTree = new InputStreamReader(new ByteArrayInputStream(json.getBytes("Shift_JIS")), "Shift_JIS");
JsonNode jsonNode = mapper.readTree(readerToTree);
assertThat(jsonNode.get("message").asText(), equalTo("あいうえお"));
}
(c). UTF-8で「write」する場合は、エンコーディングの指定は不要
エンコーディングの指定がないタイプの「write」するメソッドでは、エンコーディングはUTF-8となっています(*6)。
そのため、書き出すバイトデータのエンコーディングがUTF-8の場合、エンコーディングの明示は不要です。
/*
* (c) UTF-8で「write」する場合は、エンコーディングの指定は不要
*
* ByteArrayOutputStreamを使用し、OutputStreamにJSONを書き出す状況をシミュレートしています
* 確認に使用しているメソッド
* : ObjectMapper#writeValue(OutputStream, Object) : void
*/
@Test
public void writeValueNotSpecifyingEncodingShouldWriteUTF8Bytes() throws Exception {
// 現実のアプリケーションの例:
// 「OutputStream」を HttpServletResponse#getOutputStreamから取得する
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
mapper.writeValue(outputStream, bean);
assertThat(outputStream.toByteArray(), equalTo(writeExpected.getBytes("UTF-8")));
}
/*
* (c) 上記の「 ObjectMapper#writeValue(OutputStream, Object) : void 」以外の
* 「(c)」パターンとして利用できるメソッド
*/
@Test
public void writeMethodsNotSpecifyingEncodingShouldWriteUTF8Bytes() throws Exception {
// 第一引数 : File
File outFile = new File("out_sample.json");
mapper.writeValue(outFile, bean);
byte[] fileData = Files.readAllBytes(outFile.toPath());
assertThat(fileData, equalTo(writeExpected.getBytes("UTF-8")));
// 第一引数: JsonGenerator
// 「createGenerator」に渡せる引数の種類は、「writeValue」の第一引数と似ています。
// 以下はOutputStreamを渡す例です。
// 他にもFileを渡すメソッド等があります。
ByteArrayOutputStream jsonGeneratorOutputBytes = new ByteArrayOutputStream();
JsonGenerator jsonGenerator = mapper.getFactory().createGenerator(jsonGeneratorOutputBytes);
mapper.writeValue(jsonGenerator, bean);
assertThat(jsonGeneratorOutputBytes.toByteArray(), equalTo(writeExpected.getBytes("UTF-8")));
// 「writeValueAsBytes」
assertThat(mapper.writeValueAsBytes(bean), equalTo(writeExpected.getBytes("UTF-8")));
// 「writeTree」の第一引数は、「JsonGenerator」のため、
// ことエンコーディングに関しては「writeValue」において「JsonGenerator」を使用する時と同じ要領で使用します
ByteArrayOutputStream jsonGeneratorOutputBytesForTree = new ByteArrayOutputStream();
JsonGenerator jsonGeneratorForTree = mapper.getFactory().createGenerator(jsonGeneratorOutputBytesForTree);
JsonNode tree = mapper.readTree(writeExpected);
mapper.writeTree(jsonGeneratorForTree, tree);
assertThat(jsonGeneratorOutputBytesForTree.toByteArray(), equalTo(writeExpected.getBytes("UTF-8")));
}
/*
* (c)補足 JsonGeneratorを使用する場合に関する補足
* 「createGenerator」の引数に「JsonEncoding」を渡せる場合は、UTF-16, UTF-32も使用できます
*/
@Test
public void writeValueByJsonGeneratorCanAlsoSpecifyUTF16orUTF32Encoding() throws Exception {
ByteArrayOutputStream jsonGeneratorOutputBytes = new ByteArrayOutputStream();
JsonGenerator jsonGenerator = mapper.getFactory().createGenerator(jsonGeneratorOutputBytes,
JsonEncoding.UTF16_BE);
mapper.writeValue(jsonGenerator, bean);
assertThat(jsonGeneratorOutputBytes.toByteArray(), equalTo(writeExpected.getBytes("UTF-16BE")));
}
(d). UTF-8以外で「write」する場合は、エンコーディングを明示したWriterを生成し、Writerを引数に渡すタイプのメソッドを使用する
エンコーディングを明示したい場合は、jacksonのjavadoc(*5)にも記載されている通り、エンコーディングを明示したWriterを生成し、Writerを引数に渡すタイプのメソッドを使用します。
/*
* (d) UTF-8以外で「write」する場合は、 エンコーディングを明示したWriterを生成し、
* Writerを引数に渡すタイプのメソッドを使用する
*
* ByteArrayOutputStreamを使用し、OutputStreamにJSONを書き出す状況をシミュレートしています
* 確認に使用しているメソッド
* : ObjectMapper#writeValue(Writer, Object) : void
*/
@Test
public void writeValueFromWriterShouldWriteBytesOfSpecifiedEncoding() throws Exception {
// 現実のアプリケーションの例:
// 「OutputStream」を HttpServletResponse#getOutputStreamから取得する
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(outputStream, "Shift_JIS");
mapper.writeValue(writer, bean);
assertThat(outputStream.toByteArray(), equalTo(writeExpected.getBytes("Shift_JIS")));
}
/*
* (d) 上記の「 ObjectMapper#writeValue(Writer, Object) : void 」以外の
* 「(d)」パターンとして利用できるメソッド
*/
@Test
public void writeMethodsFromWriterShouldWriteBytesOfSpecifiedEncoding() throws Exception {
// 第一引数: JsonGenerator
// 「createGenerator」にWriterを渡す
ByteArrayOutputStream jsonGeneratorOutputBytes = new ByteArrayOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(jsonGeneratorOutputBytes, "Shift_JIS");
JsonGenerator jsonGenerator = mapper.getFactory().createGenerator(writer);
mapper.writeValue(jsonGenerator, bean);
assertThat(jsonGeneratorOutputBytes.toByteArray(), equalTo(writeExpected.getBytes("Shift_JIS")));
// 「writeTree」の第一引数は、「JsonGenerator」のため、
// ことエンコーディングに関しては「writeValue」において「JsonGenerator」を使用する時と同じ要領で使用します
ByteArrayOutputStream jsonGeneratorOutputBytesForTree = new ByteArrayOutputStream();
OutputStreamWriter writerForTree = new OutputStreamWriter(jsonGeneratorOutputBytesForTree, "Shift_JIS");
JsonGenerator jsonGeneratorForTree = mapper.getFactory().createGenerator(writerForTree);
JsonNode tree = mapper.readTree(writeExpected);
mapper.writeTree(jsonGeneratorForTree, tree);
assertThat(jsonGeneratorOutputBytesForTree.toByteArray(), equalTo(writeExpected.getBytes("Shift_JIS")));
}
Appendix
1.「DataOutput」「DataInput」を引数に取るメソッド
- 「DataOutput」とは
- プリミティブ型や文字列をバイトデータとして書き出す機能を提供
- 文字列は「modified UTF-8」という形式で出力される(*7)
- 「DataInput」とは
- DataOutput等で書き出されたバイトデータをプリミティブ型や文字列として読み出す機能を提供
まずは、一旦jacksonを離れて、「DataOutput」「DataInput」そのものの使用方法を確認します。
以下のように使用します(*8)。
/*
* DataInput / DataOutputの典型的な使用例
* ・DataOutput : プリミティブ型または文字列を直接バイトデータとして書き出すために使用する
* ・DataInput : DataOutput等で書き出されたバイトデータを読み出すために使用する
*/
@Test
public void personShouldBeSerializedByDataOutputAndDeserializedByDataInput() throws Exception {
Person person = new Person();
person.setAge(25);
person.setName("𠮷太郎");
person.setKanaCode('あ');
File file = new File("sample_dataouput.dat");
// DataOutputによるバイトデータの書き出し
DataOutput dout = new DataOutputStream(new FileOutputStream(file));
dout.writeInt(person.getAge());
dout.writeUTF(person.getName());// 「modified UTF-8」で出力
dout.writeChar(person.getKanaCode());
// DataInputによるバイトデータの読み出し
DataInput din = new DataInputStream(new FileInputStream(file));
Person deserializedPerson = new Person();
deserializedPerson.setAge(din.readInt());
deserializedPerson.setName(din.readUTF());// 「modified UTF-8」として読み出す
deserializedPerson.setKanaCode(din.readChar());
assertThat(deserializedPerson.toString(), equalTo(person.toString()));
}
jacksonにおける想定される使用方法については、公式のドキュメント等に記載は見つけられませんでした。
しかし、上記コードからの類推でいろいろと試した結果、下記のコードで想定した結果が得られました。
結論としては、以下のように使用すればよさそうです
- 「writeValue(DataOutput, ...)」でシリアライズしたなら、「readValue(DataInput, ...)」でデシリアライズ
- 「writeUTF」で書き出したなら、「readUTF」で読み出した後、「readValue(String, ...)」等でデシリアライズ
/*
* ObjectMapperで、DataInput / DataOutputを使用する例
*/
@Test
public void person2ShouldBeSerializedByDataOutputAndDeserializedByDataInput() throws Exception {
Person2 person = new Person2();
person.setAge(25);
PersonName personName = new PersonName();
personName.setFirstname("𠮷太郎");
personName.setLastname("山田");
person.setPersonName(personName);
person.setKanaCode('あ');
File file = new File("sample_dataouput2.dat");
// DataOutputによるバイトデータの書き出し
DataOutput dout = new DataOutputStream(new FileOutputStream(file));
dout.writeInt(person.getAge());
// PersonNameはJSONで書き出す
mapper.writeValue(dout, person.getPersonName());
dout.writeChar(person.getKanaCode());
// DataInputによるバイトデータの読み出し
DataInput din = new DataInputStream(new FileInputStream(file));
Person2 deserializedPerson = new Person2();
deserializedPerson.setAge(din.readInt());
PersonName deserializedPersonName = mapper.readValue(din, PersonName.class);
// 以下のように記述しても正しくDeserializeできませんでした
// PersonName deserializedPersonName = mapper.readValue(din.readUTF(),
// PersonName.class);
deserializedPerson.setPersonName(deserializedPersonName);
deserializedPerson.setKanaCode(din.readChar());
assertThat(deserializedPerson.toString(), equalTo(person.toString()));
}
/*
* ObjectMapperで、DataInput / DataOutputを使用する場合の例
* 「writeUTF」で書き出されたJSONは
* ObjectMapper#readValue(DataInput, Class<T>) <T>: T
* では正しくDeserializeできない !!! このテストは失敗します
*/
@Test
public void modifiedUTF8StringShouldBeDeserializedByDataInput() throws Exception {
File file = new File("sample_dataouput3.dat");
// DataOutputによるバイトデータの書き出し
DataOutput dout = new DataOutputStream(new FileOutputStream(file));
dout.writeInt(55);
dout.writeUTF("{\"firstname\":\"𠮷太郎\", \"lastname\":\"山田\"}");
dout.writeChar('あ');
// DataInputによるバイトデータの読み出し
DataInput din = new DataInputStream(new FileInputStream(file));
assertThat(55, equalTo(din.readInt()));
PersonName deserializedPersonName = mapper.readValue(din, PersonName.class);
// 以下のようにすると正しくDeserializeされました
// PersonName deserializedPersonName = mapper.readValue(din.readUTF(),
// PersonName.class);
assertThat(deserializedPersonName.getFirstname(), equalTo("𠮷太郎"));
assertThat(deserializedPersonName.getLastname(), equalTo("山田"));
assertThat(din.readChar(), equalTo('あ'));
}
// 「1.「DataOutput」「DataInput」を引数に取るメソッド」のサンプルソースで使用するクラス
// setter, getter, toStringは割愛。toStringの結果の比較でフィールド値が比較できるようになっています。
static class Person2 {
private int age;
private PersonName personName;
private char kanaCode;
}
static class PersonName {
private String firstname;
private String lastname;
}
static class Person {
private int age;
private String name;
private char kanaCode;
}
2. JsonParser, JsonGeneratorについての補足
「JsonParser」「JsonGenerator」は当記事で対象としている「jackson-databind」ではなく「jackson-core」に位置付けられているクラスです(*9)。
「jackson-core」には(その名の通り)コアな低レベルのparser/generatorが含まれており、「jackson-databind」は「jackson-core」に依存しています。
コアな低レベルのparser/generatorが、ここで紹介する「JsonParser」「JsonGenerator」に当たります。
記事本文ではObjectMapperのメソッドに対象を絞っていたため、「JsonParser」「JsonGenerator」自体の使い方は紹介していませんでした。
以下で、エンコーディングを指定して「JsonParser」「JsonGenerator」を使用する例を紹介します。
/*
* JsonParserに関する補足
* UTF-8以外のエンコーディングを使用し、
* 典型的なJsonParserの使い方でJSONをreadする例です
*/
@Test
public void jsonParserShouldReadJSONIncrementally() throws Exception {
Reader reader = new InputStreamReader(new ByteArrayInputStream(json.getBytes("Shift_JIS")), "Shift_JIS");
JsonParser jsonParser = mapper.getFactory().createParser(reader);
JsonToken t = null;
String fieldName = null;
String message = null;
while ((t = jsonParser.nextToken()) != null) {
if (t == JsonToken.FIELD_NAME) {
fieldName = jsonParser.getCurrentName();
}
if (t == JsonToken.VALUE_STRING) {
message = jsonParser.getText();
}
}
assertThat(fieldName, equalTo("message"));
assertThat(message, equalTo("あいうえお"));
}
/*
* JsonGeneratorに関する補足
* UTF-8以外のエンコーディングを使用し、
* 典型的なJsonGeneratorの使い方でJSONをwriteする例です。
*/
@Test
public void jsonGeneratorShouldWriteJSONIncrementally() throws Exception {
ByteArrayOutputStream outputBytes = new ByteArrayOutputStream();
Writer writer = new OutputStreamWriter(outputBytes, "Shift_JIS");
JsonGenerator jsonGenerator = mapper.getFactory().createGenerator(writer);
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("message", "あいうえお");
jsonGenerator.writeEndObject();
jsonGenerator.close();
assertThat(outputBytes.toByteArray(), equalTo("{\"message\":\"あいうえお\"}".getBytes("Shift_JIS")));
}
注釈および参考サイト
RFC 4627(2019/5/3閲覧)
RFC 8259(2019/5/3閲覧)
*1
jacksonの使い方については、少し昔の記事ですが、Jackson使い方メモ(2019/5/3閲覧)が参考になります。
jackson-databindのGitHubにおける「Use It!」(2019/5/3閲覧)も参考になります。
*2
実際に動作させて確認した結果および、「JsonEncoding.java」(2019/5/3閲覧)のjavadocの記述を根拠としています。
*3
RFC 4627の「3. Encoding」にはBOMに関する記述はありませんが、BOMは無視して判断する前提で記述されていると考えられます。
*4
「JsonEncoding.java」(2019/5/3閲覧)に以下の記述があります。
「 Note: if application want to explicitly disregard Encoding limitations (to read in JSON encoded using an encoding not listed as allowed), they can use {@link java.io.Reader} / {@link java.io.Writer} instances as input」
*5
デモ用ソースコードの「(a)」の部分にも記載されている通り、Shift_JIS等でエンコードされたデータを「read」するとエラーとなる場合があります。
*6
「ObjectMapper#writeValue(OutputStream, Object): void」のjavadocには明記されています
*7
「DataInput」(2019/5/4閲覧)のjavadoc参照。
*8
「KAB-studio > プログラミング > JavaA2Z > DataInputStream」(2019/5/4閲覧)を参考にしました。
*9
「jackson-core」(2019/5/4閲覧)のGitHubの記述を参照しました。