From 9179d9c7259217c4f571442023f38eee1372d07e Mon Sep 17 00:00:00 2001 From: Tetsuro Sano Date: Wed, 18 Jan 2023 19:18:48 +0900 Subject: [PATCH 1/4] Fix null handling --- .../embulk/input/kintone/KintoneAccessor.java | 55 ++++--- .../input/kintone/TestKintoneAccessor.java | 136 +++++++++++++++++- 2 files changed, 171 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/embulk/input/kintone/KintoneAccessor.java b/src/main/java/org/embulk/input/kintone/KintoneAccessor.java index 57de845..2c99089 100644 --- a/src/main/java/org/embulk/input/kintone/KintoneAccessor.java +++ b/src/main/java/org/embulk/input/kintone/KintoneAccessor.java @@ -33,7 +33,11 @@ import com.kintone.client.model.record.TimeFieldValue; import com.kintone.client.model.record.UserSelectFieldValue; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalTime; import java.util.List; +import java.util.Objects; import java.util.function.BiFunction; import java.util.function.Function; @@ -55,21 +59,25 @@ public String get(final String name) private String getAsString(final String fieldCode) { - switch (getFieldType(fieldCode)) { + final FieldType fieldType = getFieldType(fieldCode); + if (fieldType == null) { + return null; + } + switch (fieldType) { case RECORD_NUMBER: return record.getRecordNumberFieldValue(); case __ID__: - return String.valueOf(record.getId()); + return toString(record.getId(), Objects::toString); case __REVISION__: - return String.valueOf(record.getRevision()); + return toString(record.getRevision(), Objects::toString); case CREATOR: - return record.getCreatorFieldValue().getCode(); + return toString(record.getCreatorFieldValue(), User::getCode); case CREATED_TIME: - return String.valueOf(record.getCreatedTimeFieldValue().toInstant()); + return toString(record.getCreatedTimeFieldValue(), (value) -> value.toInstant().toString()); case MODIFIER: - return record.getModifierFieldValue().getCode(); + return toString(record.getModifierFieldValue(), User::getCode); case UPDATED_TIME: - return String.valueOf(record.getUpdatedTimeFieldValue().toInstant()); + return toString(record.getUpdatedTimeFieldValue(), (value) -> value.toInstant().toString()); case SINGLE_LINE_TEXT: return record.getSingleLineTextFieldValue(fieldCode); case MULTI_LINE_TEXT: @@ -77,9 +85,9 @@ private String getAsString(final String fieldCode) case RICH_TEXT: return record.getRichTextFieldValue(fieldCode); case NUMBER: - return String.valueOf(record.getNumberFieldValue(fieldCode)); + return toString(record.getNumberFieldValue(fieldCode), BigDecimal::toString); case CALC: - return String.valueOf(record.getCalcFieldValue(fieldCode)); + return toString(record.getCalcFieldValue(fieldCode), BigDecimal::toString); case CHECK_BOX: return toString(record.getCheckBoxFieldValue(fieldCode)); case RADIO_BUTTON: @@ -95,11 +103,11 @@ private String getAsString(final String fieldCode) case GROUP_SELECT: return toString(record.getGroupSelectFieldValue(fieldCode), Group::getCode); case DATE: - return String.valueOf(record.getDateFieldValue(fieldCode)); + return toString(record.getDateFieldValue(fieldCode), LocalDate::toString); case TIME: - return String.valueOf(record.getTimeFieldValue(fieldCode)); + return toString(record.getTimeFieldValue(fieldCode), LocalTime::toString); case DATETIME: - return String.valueOf(record.getDateTimeFieldValue(fieldCode).toInstant()); + return toString(record.getDateTimeFieldValue(fieldCode), (value) -> value.toInstant().toString()); case LINK: return record.getLinkFieldValue(fieldCode); case FILE: @@ -119,7 +127,7 @@ private String getAsString(final String fieldCode) case HR: case GROUP: default: - return ""; + return null; } } @@ -135,18 +143,27 @@ private FieldType getFieldType(final String fieldCode) return fieldType; } + private String toString(final T value, final Function mapper) + { + return value == null ? null : mapper.apply(value); + } + private String toString(final List list) { return list.stream() + .filter(Objects::nonNull) .reduce((accum, value) -> accum + delimiter + value) - .orElse(""); + .orElse(null); } private String toString(final List list, final Function mapper) { - return list.stream().map(mapper) + return list.stream() + .filter(Objects::nonNull) + .map(mapper) + .filter(Objects::nonNull) .reduce((accum, value) -> accum + delimiter + value) - .orElse(""); + .orElse(null); } private Gson createGson() @@ -261,7 +278,7 @@ private JsonElement serialize(final TimeFieldValue src, final JsonSerializationC private JsonElement serialize(final DateTimeFieldValue src, final JsonSerializationContext context) { - return serialize(src, src.getValue().toInstant()); + return serialize(src, toString(src.getValue(), (value) -> value.toInstant().toString())); } private JsonElement serialize(final LinkFieldValue src, final JsonSerializationContext context) @@ -280,7 +297,7 @@ private JsonElement serialize(final FileBody src, final JsonSerializationContext object.addProperty("contentType", src.getContentType()); object.addProperty("fileKey", src.getFileKey()); object.addProperty("name", src.getName()); - object.addProperty("size", String.valueOf(src.getSize())); + object.addProperty("size", toString(src.getSize(), Objects::toString)); return object; } @@ -288,7 +305,7 @@ private JsonElement serialize(final FieldValue src, final T value) { final JsonObject object = new JsonObject(); object.addProperty("type", src.getType().name()); - object.addProperty("value", String.valueOf(value)); + object.addProperty("value", toString(value, T::toString)); return object; } diff --git a/src/test/java/org/embulk/input/kintone/TestKintoneAccessor.java b/src/test/java/org/embulk/input/kintone/TestKintoneAccessor.java index 954de97..1b0c27b 100644 --- a/src/test/java/org/embulk/input/kintone/TestKintoneAccessor.java +++ b/src/test/java/org/embulk/input/kintone/TestKintoneAccessor.java @@ -41,6 +41,7 @@ import java.util.ArrayList; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; public class TestKintoneAccessor { @@ -247,6 +248,139 @@ private TableRow tableRow(final Long id) return tableRow; } + @Test + public void testNullFields() + { + final KintoneAccessor accessor = new KintoneAccessor(nullRecord()); + assertNull(accessor.get("レコード番号")); + assertNull(accessor.get("$id")); + assertNull(accessor.get("$revision")); + assertNull(accessor.get("作成者")); + assertNull(accessor.get("作成者(null項目)")); + assertNull(accessor.get("作成日時")); + assertNull(accessor.get("更新者")); + assertNull(accessor.get("更新者(null項目)")); + assertNull(accessor.get("更新日時")); + assertNull(accessor.get("文字列(1行)")); + assertNull(accessor.get("文字列(複数行)")); + assertNull(accessor.get("リッチエディター")); + assertNull(accessor.get("数値")); + assertNull(accessor.get("計算")); + assertNull(accessor.get("チェックボックス(空)")); + assertNull(accessor.get("チェックボックス(null要素)")); + assertNull(accessor.get("ラジオボタン")); + assertNull(accessor.get("複数選択(空)")); + assertNull(accessor.get("複数選択(null要素)")); + assertNull(accessor.get("ドロップダウン")); + assertNull(accessor.get("ユーザー選択(空)")); + assertNull(accessor.get("ユーザー選択(null要素)")); + assertNull(accessor.get("ユーザー選択(null項目)")); + assertNull(accessor.get("組織選択(空)")); + assertNull(accessor.get("組織選択(null要素)")); + assertNull(accessor.get("組織選択(null項目)")); + assertNull(accessor.get("グループ選択(空)")); + assertNull(accessor.get("グループ選択(null要素)")); + assertNull(accessor.get("グループ選択(null項目)")); + assertNull(accessor.get("日付")); + assertNull(accessor.get("時刻")); + assertNull(accessor.get("日時")); + assertNull(accessor.get("リンク")); + assertNull(accessor.get("添付ファイル(空)")); + assertNull(accessor.get("添付ファイル(null要素)")); + assertNull(accessor.get("添付ファイル(null項目)")); + assertEquals("[]", accessor.get("テーブル(空)")); + assertEquals("[null,null]", accessor.get("テーブル(null要素)")); + assertEquals("[{\"value\":{\"添付ファイル(null要素)\":{\"type\":\"FILE\",\"value\":[null,null]},\"添付ファイル(null項目)\":{\"type\":\"FILE\",\"value\":[{},{}]},\"複数選択(空)\":{\"type\":\"MULTI_SELECT\",\"value\":[]},\"リッチエディター\":{\"type\":\"RICH_TEXT\"},\"文字列(1行)\":{\"type\":\"SINGLE_LINE_TEXT\"},\"ユーザー選択(null項目)\":{\"type\":\"USER_SELECT\",\"value\":[{},{}]},\"文字列(複数行)\":{\"type\":\"MULTI_LINE_TEXT\"},\"ユーザー選択(空)\":{\"type\":\"USER_SELECT\",\"value\":[]},\"チェックボックス(null要素)\":{\"type\":\"CHECK_BOX\",\"value\":[null,null]},\"組織選択(null項目)\":{\"type\":\"ORGANIZATION_SELECT\",\"value\":[{},{}]},\"計算\":{\"type\":\"CALC\"},\"日付\":{\"type\":\"DATE\"},\"組織選択(空)\":{\"type\":\"ORGANIZATION_SELECT\",\"value\":[]},\"添付ファイル(空)\":{\"type\":\"FILE\",\"value\":[]},\"ラジオボタン\":{\"type\":\"RADIO_BUTTON\"},\"グループ選択(null項目)\":{\"type\":\"GROUP_SELECT\",\"value\":[{},{}]},\"複数選択(null要素)\":{\"type\":\"MULTI_SELECT\",\"value\":[null,null]},\"ドロップダウン\":{\"type\":\"DROP_DOWN\"},\"日時\":{\"type\":\"DATETIME\"},\"組織選択(null要素)\":{\"type\":\"ORGANIZATION_SELECT\",\"value\":[null,null]},\"時刻\":{\"type\":\"TIME\"},\"グループ選択(空)\":{\"type\":\"GROUP_SELECT\",\"value\":[]},\"数値\":{\"type\":\"NUMBER\"},\"ユーザー選択(null要素)\":{\"type\":\"USER_SELECT\",\"value\":[null,null]},\"グループ選択(null要素)\":{\"type\":\"GROUP_SELECT\",\"value\":[null,null]},\"リンク\":{\"type\":\"LINK\"},\"チェックボックス(空)\":{\"type\":\"CHECK_BOX\",\"value\":[]}}},{\"value\":{\"添付ファイル(null要素)\":{\"type\":\"FILE\",\"value\":[null,null]},\"添付ファイル(null項目)\":{\"type\":\"FILE\",\"value\":[{},{}]},\"複数選択(空)\":{\"type\":\"MULTI_SELECT\",\"value\":[]},\"リッチエディター\":{\"type\":\"RICH_TEXT\"},\"文字列(1行)\":{\"type\":\"SINGLE_LINE_TEXT\"},\"ユーザー選択(null項目)\":{\"type\":\"USER_SELECT\",\"value\":[{},{}]},\"文字列(複数行)\":{\"type\":\"MULTI_LINE_TEXT\"},\"ユーザー選択(空)\":{\"type\":\"USER_SELECT\",\"value\":[]},\"チェックボックス(null要素)\":{\"type\":\"CHECK_BOX\",\"value\":[null,null]},\"組織選択(null項目)\":{\"type\":\"ORGANIZATION_SELECT\",\"value\":[{},{}]},\"計算\":{\"type\":\"CALC\"},\"日付\":{\"type\":\"DATE\"},\"組織選択(空)\":{\"type\":\"ORGANIZATION_SELECT\",\"value\":[]},\"添付ファイル(空)\":{\"type\":\"FILE\",\"value\":[]},\"ラジオボタン\":{\"type\":\"RADIO_BUTTON\"},\"グループ選択(null項目)\":{\"type\":\"GROUP_SELECT\",\"value\":[{},{}]},\"複数選択(null要素)\":{\"type\":\"MULTI_SELECT\",\"value\":[null,null]},\"ドロップダウン\":{\"type\":\"DROP_DOWN\"},\"日時\":{\"type\":\"DATETIME\"},\"組織選択(null要素)\":{\"type\":\"ORGANIZATION_SELECT\",\"value\":[null,null]},\"時刻\":{\"type\":\"TIME\"},\"グループ選択(空)\":{\"type\":\"GROUP_SELECT\",\"value\":[]},\"数値\":{\"type\":\"NUMBER\"},\"ユーザー選択(null要素)\":{\"type\":\"USER_SELECT\",\"value\":[null,null]},\"グループ選択(null要素)\":{\"type\":\"GROUP_SELECT\",\"value\":[null,null]},\"リンク\":{\"type\":\"LINK\"},\"チェックボックス(空)\":{\"type\":\"CHECK_BOX\",\"value\":[]}}}]", accessor.get("テーブル(null項目)")); + assertNull(accessor.get("カテゴリー(空)")); + assertNull(accessor.get("カテゴリー(null要素)")); + assertNull(accessor.get("ステータス")); + assertNull(accessor.get("作業者(空)")); + assertNull(accessor.get("作業者(null要素)")); + assertNull(accessor.get("作業者(null項目)")); + } + + private Record nullRecord() + { + final Record record = new Record(); + record.putField("レコード番号", new RecordNumberFieldValue(null)); + record.putField("作成者", new CreatorFieldValue(null)); + record.putField("作成者(null項目)", new CreatorFieldValue(user(null, null))); + record.putField("作成日時", new CreatedTimeFieldValue(null)); + record.putField("更新者", new ModifierFieldValue(null)); + record.putField("更新者(null項目)", new ModifierFieldValue(user(null, null))); + record.putField("更新日時", new UpdatedTimeFieldValue(null)); + record.putField("文字列(1行)", new SingleLineTextFieldValue(null)); + record.putField("文字列(複数行)", new MultiLineTextFieldValue(null)); + record.putField("リッチエディター", new RichTextFieldValue(null)); + record.putField("数値", new NumberFieldValue(null)); + record.putField("計算", new CalcFieldValue((BigDecimal) null)); + record.putField("チェックボックス(空)", new CheckBoxFieldValue()); + record.putField("チェックボックス(null要素)", new CheckBoxFieldValue(null, null)); + record.putField("ラジオボタン", new RadioButtonFieldValue(null)); + record.putField("複数選択(空)", new MultiSelectFieldValue()); + record.putField("複数選択(null要素)", new MultiSelectFieldValue(null, null)); + record.putField("ドロップダウン", new DropDownFieldValue(null)); + record.putField("ユーザー選択(空)", new UserSelectFieldValue()); + record.putField("ユーザー選択(null要素)", new UserSelectFieldValue(null, null)); + record.putField("ユーザー選択(null項目)", new UserSelectFieldValue(user(null, null), user(null, null))); + record.putField("組織選択(空)", new OrganizationSelectFieldValue()); + record.putField("組織選択(null要素)", new OrganizationSelectFieldValue(null, null)); + record.putField("組織選択(null項目)", new OrganizationSelectFieldValue(organization(null, null), organization(null, null))); + record.putField("グループ選択(空)", new GroupSelectFieldValue()); + record.putField("グループ選択(null要素)", new GroupSelectFieldValue(null, null)); + record.putField("グループ選択(null項目)", new GroupSelectFieldValue(group(null, null), group(null, null))); + record.putField("日付", new DateFieldValue(null)); + record.putField("時刻", new TimeFieldValue(null)); + record.putField("日時", new DateTimeFieldValue(null)); + record.putField("リンク", new LinkFieldValue(null)); + record.putField("添付ファイル(空)", new FileFieldValue()); + record.putField("添付ファイル(null要素)", new FileFieldValue(null, null)); + record.putField("添付ファイル(null項目)", new FileFieldValue(file(null, null, null, null), file(null, null, null, null))); + record.putField("テーブル(空)", new SubtableFieldValue()); + record.putField("テーブル(null要素)", new SubtableFieldValue(null, null)); + record.putField("テーブル(null項目)", new SubtableFieldValue(nullTableRow(), nullTableRow())); + record.putField("カテゴリー(空)", new CategoryFieldValue()); + record.putField("カテゴリー(null要素)", new CategoryFieldValue(null, null)); + record.putField("ステータス", new StatusFieldValue(null)); + record.putField("作業者(空)", new StatusAssigneeFieldValue()); + record.putField("作業者(null要素)", new StatusAssigneeFieldValue(null, null)); + record.putField("作業者(null項目)", new StatusAssigneeFieldValue(user(null, null), user(null, null))); + return record; + } + + private TableRow nullTableRow() + { + final TableRow tableRow = new TableRow(); + tableRow.putField("文字列(1行)", new SingleLineTextFieldValue(null)); + tableRow.putField("文字列(複数行)", new MultiLineTextFieldValue(null)); + tableRow.putField("リッチエディター", new RichTextFieldValue(null)); + tableRow.putField("数値", new NumberFieldValue(null)); + tableRow.putField("計算", new CalcFieldValue((BigDecimal) null)); + tableRow.putField("チェックボックス(空)", new CheckBoxFieldValue()); + tableRow.putField("チェックボックス(null要素)", new CheckBoxFieldValue(null, null)); + tableRow.putField("ラジオボタン", new RadioButtonFieldValue(null)); + tableRow.putField("複数選択(空)", new MultiSelectFieldValue()); + tableRow.putField("複数選択(null要素)", new MultiSelectFieldValue(null, null)); + tableRow.putField("ドロップダウン", new DropDownFieldValue(null)); + tableRow.putField("ユーザー選択(空)", new UserSelectFieldValue()); + tableRow.putField("ユーザー選択(null要素)", new UserSelectFieldValue(null, null)); + tableRow.putField("ユーザー選択(null項目)", new UserSelectFieldValue(user(null, null), user(null, null))); + tableRow.putField("組織選択(空)", new OrganizationSelectFieldValue()); + tableRow.putField("組織選択(null要素)", new OrganizationSelectFieldValue(null, null)); + tableRow.putField("組織選択(null項目)", new OrganizationSelectFieldValue(organization(null, null), organization(null, null))); + tableRow.putField("グループ選択(空)", new GroupSelectFieldValue()); + tableRow.putField("グループ選択(null要素)", new GroupSelectFieldValue(null, null)); + tableRow.putField("グループ選択(null項目)", new GroupSelectFieldValue(group(null, null), group(null, null))); + tableRow.putField("日付", new DateFieldValue(null)); + tableRow.putField("時刻", new TimeFieldValue(null)); + tableRow.putField("日時", new DateTimeFieldValue(null)); + tableRow.putField("リンク", new LinkFieldValue(null)); + tableRow.putField("添付ファイル(空)", new FileFieldValue()); + tableRow.putField("添付ファイル(null要素)", new FileFieldValue(null, null)); + tableRow.putField("添付ファイル(null項目)", new FileFieldValue(file(null, null, null, null), file(null, null, null, null))); + return tableRow; + } + private User user(final String code, final String name) { return new User(name, code); @@ -268,7 +402,7 @@ private FileBody file(final String contentType, final String fileKey, final Stri file.setContentType(contentType); file.setFileKey(fileKey); file.setName(name); - file.setSize(Integer.valueOf(size)); + file.setSize(size == null ? null : Integer.valueOf(size)); return file; } } From 3619ef8b74a0c54024ea8b77d5186eddf9544460 Mon Sep 17 00:00:00 2001 From: Tetsuro Sano Date: Fri, 3 Feb 2023 20:06:12 +0900 Subject: [PATCH 2/4] Avoid NullPointerException --- .../kintone/KintoneInputColumnVisitor.java | 52 +++++++++++++------ 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/embulk/input/kintone/KintoneInputColumnVisitor.java b/src/main/java/org/embulk/input/kintone/KintoneInputColumnVisitor.java index 25fb5e0..6c4614a 100644 --- a/src/main/java/org/embulk/input/kintone/KintoneInputColumnVisitor.java +++ b/src/main/java/org/embulk/input/kintone/KintoneInputColumnVisitor.java @@ -1,6 +1,5 @@ package org.embulk.input.kintone; -import com.google.gson.JsonElement; import org.embulk.spi.Column; import org.embulk.spi.ColumnVisitor; import org.embulk.spi.PageBuilder; @@ -12,7 +11,6 @@ import org.slf4j.LoggerFactory; import java.time.Instant; -import java.util.List; import java.util.Objects; public class KintoneInputColumnVisitor implements ColumnVisitor @@ -35,13 +33,12 @@ public KintoneInputColumnVisitor(final KintoneAccessor accessor, final PageBuild public void stringColumn(Column column) { try { - String data = accessor.get(column.getName()); + final String data = accessor.get(column.getName()); if (Objects.isNull(data)) { pageBuilder.setNull(column); + return; } - else { - pageBuilder.setString(column, data); - } + pageBuilder.setString(column, data); } catch (Exception e) { logger.warn(String.format("Invalid string column: %s", column.getName()), e); @@ -53,7 +50,11 @@ public void stringColumn(Column column) public void booleanColumn(Column column) { try { - String data = accessor.get(column.getName()); + final String data = accessor.get(column.getName()); + if (Objects.isNull(data)) { + pageBuilder.setNull(column); + return; + } pageBuilder.setBoolean(column, Boolean.parseBoolean(data)); } catch (Exception e) { @@ -66,7 +67,11 @@ public void booleanColumn(Column column) public void longColumn(Column column) { try { - String data = accessor.get(column.getName()); + final String data = accessor.get(column.getName()); + if (Objects.isNull(data)) { + pageBuilder.setNull(column); + return; + } pageBuilder.setLong(column, Long.parseLong(data)); } catch (Exception e) { @@ -79,7 +84,11 @@ public void longColumn(Column column) public void doubleColumn(Column column) { try { - String data = accessor.get(column.getName()); + final String data = accessor.get(column.getName()); + if (Objects.isNull(data)) { + pageBuilder.setNull(column); + return; + } pageBuilder.setDouble(column, Double.parseDouble(data)); } catch (Exception e) { @@ -92,9 +101,13 @@ public void doubleColumn(Column column) public void timestampColumn(Column column) { try { - List columnConfigs = pluginTask.getFields().getColumns(); + final String data = accessor.get(column.getName()); + if (Objects.isNull(data)) { + pageBuilder.setNull(column); + return; + } String pattern = DEFAULT_TIMESTAMP_PATTERN; - for (ColumnConfig config : columnConfigs) { + for (ColumnConfig config : pluginTask.getFields().getColumns()) { if (config.getName().equals(column.getName()) && config.getOption() != null && config.getFormat() != null) { @@ -103,7 +116,7 @@ public void timestampColumn(Column column) } } final TimestampFormatter formatter = TimestampFormatter.builder("ruby:" + pattern).build(); - Instant instant = formatter.parse(accessor.get(column.getName())); + final Instant instant = formatter.parse(data); pageBuilder.setTimestamp(column, Timestamp.ofInstant(instant)); } catch (Exception e) { @@ -116,13 +129,20 @@ public void timestampColumn(Column column) public void jsonColumn(Column column) { try { - JsonElement data = com.google.gson.JsonParser.parseString(accessor.get(column.getName())); - if (data.isJsonNull() || data.isJsonPrimitive()) { + final String data = accessor.get(column.getName()); + if (Objects.isNull(data)) { + pageBuilder.setNull(column); + return; + } + final com.google.gson.JsonElement gson = com.google.gson.JsonParser.parseString(data); + if (gson.isJsonNull()) { pageBuilder.setNull(column); + return; } - else { - pageBuilder.setJson(column, new JsonParser().parse(data.toString())); + if (gson.isJsonPrimitive()) { + throw new Exception(String.format("'%s' is json primitive", gson)); } + pageBuilder.setJson(column, new JsonParser().parse(gson.toString())); } catch (Exception e) { logger.warn(String.format("Invalid json column: %s", column.getName()), e); From df5d79b41459787c86d44bc65b9484c5cb4ef30f Mon Sep 17 00:00:00 2001 From: Tetsuro Sano Date: Mon, 13 Feb 2023 13:31:00 +0900 Subject: [PATCH 3/4] List field as null or empty to empty string instead of null --- .../embulk/input/kintone/KintoneAccessor.java | 4 +- .../input/kintone/TestKintoneAccessor.java | 50 +++++++++++-------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/src/main/java/org/embulk/input/kintone/KintoneAccessor.java b/src/main/java/org/embulk/input/kintone/KintoneAccessor.java index 2c99089..8aa7147 100644 --- a/src/main/java/org/embulk/input/kintone/KintoneAccessor.java +++ b/src/main/java/org/embulk/input/kintone/KintoneAccessor.java @@ -153,7 +153,7 @@ private String toString(final List list) return list.stream() .filter(Objects::nonNull) .reduce((accum, value) -> accum + delimiter + value) - .orElse(null); + .orElse(""); } private String toString(final List list, final Function mapper) @@ -163,7 +163,7 @@ private String toString(final List list, final Function mapper .map(mapper) .filter(Objects::nonNull) .reduce((accum, value) -> accum + delimiter + value) - .orElse(null); + .orElse(""); } private Gson createGson() diff --git a/src/test/java/org/embulk/input/kintone/TestKintoneAccessor.java b/src/test/java/org/embulk/input/kintone/TestKintoneAccessor.java index 1b0c27b..f706a52 100644 --- a/src/test/java/org/embulk/input/kintone/TestKintoneAccessor.java +++ b/src/test/java/org/embulk/input/kintone/TestKintoneAccessor.java @@ -266,37 +266,41 @@ public void testNullFields() assertNull(accessor.get("リッチエディター")); assertNull(accessor.get("数値")); assertNull(accessor.get("計算")); - assertNull(accessor.get("チェックボックス(空)")); - assertNull(accessor.get("チェックボックス(null要素)")); + assertEquals("", accessor.get("チェックボックス(空)")); + assertEquals("", accessor.get("チェックボックス(null要素)")); assertNull(accessor.get("ラジオボタン")); - assertNull(accessor.get("複数選択(空)")); - assertNull(accessor.get("複数選択(null要素)")); + assertEquals("", accessor.get("複数選択(空)")); + assertEquals("", accessor.get("複数選択(null要素)")); assertNull(accessor.get("ドロップダウン")); - assertNull(accessor.get("ユーザー選択(空)")); - assertNull(accessor.get("ユーザー選択(null要素)")); - assertNull(accessor.get("ユーザー選択(null項目)")); - assertNull(accessor.get("組織選択(空)")); - assertNull(accessor.get("組織選択(null要素)")); - assertNull(accessor.get("組織選択(null項目)")); - assertNull(accessor.get("グループ選択(空)")); - assertNull(accessor.get("グループ選択(null要素)")); - assertNull(accessor.get("グループ選択(null項目)")); + assertEquals("", accessor.get("ユーザー選択(空)")); + assertEquals("", accessor.get("ユーザー選択(null要素)")); + assertEquals("", accessor.get("ユーザー選択(null項目)")); + assertEquals("", accessor.get("組織選択(空)")); + assertEquals("", accessor.get("組織選択(null要素)")); + assertEquals("", accessor.get("組織選択(null項目)")); + assertEquals("", accessor.get("グループ選択(空)")); + assertEquals("", accessor.get("グループ選択(null要素)")); + assertEquals("", accessor.get("グループ選択(null項目)")); assertNull(accessor.get("日付")); assertNull(accessor.get("時刻")); assertNull(accessor.get("日時")); assertNull(accessor.get("リンク")); - assertNull(accessor.get("添付ファイル(空)")); - assertNull(accessor.get("添付ファイル(null要素)")); - assertNull(accessor.get("添付ファイル(null項目)")); + assertEquals("", accessor.get("添付ファイル(空)")); + assertEquals("", accessor.get("添付ファイル(null要素)")); + assertEquals("", accessor.get("添付ファイル(null項目)")); assertEquals("[]", accessor.get("テーブル(空)")); assertEquals("[null,null]", accessor.get("テーブル(null要素)")); assertEquals("[{\"value\":{\"添付ファイル(null要素)\":{\"type\":\"FILE\",\"value\":[null,null]},\"添付ファイル(null項目)\":{\"type\":\"FILE\",\"value\":[{},{}]},\"複数選択(空)\":{\"type\":\"MULTI_SELECT\",\"value\":[]},\"リッチエディター\":{\"type\":\"RICH_TEXT\"},\"文字列(1行)\":{\"type\":\"SINGLE_LINE_TEXT\"},\"ユーザー選択(null項目)\":{\"type\":\"USER_SELECT\",\"value\":[{},{}]},\"文字列(複数行)\":{\"type\":\"MULTI_LINE_TEXT\"},\"ユーザー選択(空)\":{\"type\":\"USER_SELECT\",\"value\":[]},\"チェックボックス(null要素)\":{\"type\":\"CHECK_BOX\",\"value\":[null,null]},\"組織選択(null項目)\":{\"type\":\"ORGANIZATION_SELECT\",\"value\":[{},{}]},\"計算\":{\"type\":\"CALC\"},\"日付\":{\"type\":\"DATE\"},\"組織選択(空)\":{\"type\":\"ORGANIZATION_SELECT\",\"value\":[]},\"添付ファイル(空)\":{\"type\":\"FILE\",\"value\":[]},\"ラジオボタン\":{\"type\":\"RADIO_BUTTON\"},\"グループ選択(null項目)\":{\"type\":\"GROUP_SELECT\",\"value\":[{},{}]},\"複数選択(null要素)\":{\"type\":\"MULTI_SELECT\",\"value\":[null,null]},\"ドロップダウン\":{\"type\":\"DROP_DOWN\"},\"日時\":{\"type\":\"DATETIME\"},\"組織選択(null要素)\":{\"type\":\"ORGANIZATION_SELECT\",\"value\":[null,null]},\"時刻\":{\"type\":\"TIME\"},\"グループ選択(空)\":{\"type\":\"GROUP_SELECT\",\"value\":[]},\"数値\":{\"type\":\"NUMBER\"},\"ユーザー選択(null要素)\":{\"type\":\"USER_SELECT\",\"value\":[null,null]},\"グループ選択(null要素)\":{\"type\":\"GROUP_SELECT\",\"value\":[null,null]},\"リンク\":{\"type\":\"LINK\"},\"チェックボックス(空)\":{\"type\":\"CHECK_BOX\",\"value\":[]}}},{\"value\":{\"添付ファイル(null要素)\":{\"type\":\"FILE\",\"value\":[null,null]},\"添付ファイル(null項目)\":{\"type\":\"FILE\",\"value\":[{},{}]},\"複数選択(空)\":{\"type\":\"MULTI_SELECT\",\"value\":[]},\"リッチエディター\":{\"type\":\"RICH_TEXT\"},\"文字列(1行)\":{\"type\":\"SINGLE_LINE_TEXT\"},\"ユーザー選択(null項目)\":{\"type\":\"USER_SELECT\",\"value\":[{},{}]},\"文字列(複数行)\":{\"type\":\"MULTI_LINE_TEXT\"},\"ユーザー選択(空)\":{\"type\":\"USER_SELECT\",\"value\":[]},\"チェックボックス(null要素)\":{\"type\":\"CHECK_BOX\",\"value\":[null,null]},\"組織選択(null項目)\":{\"type\":\"ORGANIZATION_SELECT\",\"value\":[{},{}]},\"計算\":{\"type\":\"CALC\"},\"日付\":{\"type\":\"DATE\"},\"組織選択(空)\":{\"type\":\"ORGANIZATION_SELECT\",\"value\":[]},\"添付ファイル(空)\":{\"type\":\"FILE\",\"value\":[]},\"ラジオボタン\":{\"type\":\"RADIO_BUTTON\"},\"グループ選択(null項目)\":{\"type\":\"GROUP_SELECT\",\"value\":[{},{}]},\"複数選択(null要素)\":{\"type\":\"MULTI_SELECT\",\"value\":[null,null]},\"ドロップダウン\":{\"type\":\"DROP_DOWN\"},\"日時\":{\"type\":\"DATETIME\"},\"組織選択(null要素)\":{\"type\":\"ORGANIZATION_SELECT\",\"value\":[null,null]},\"時刻\":{\"type\":\"TIME\"},\"グループ選択(空)\":{\"type\":\"GROUP_SELECT\",\"value\":[]},\"数値\":{\"type\":\"NUMBER\"},\"ユーザー選択(null要素)\":{\"type\":\"USER_SELECT\",\"value\":[null,null]},\"グループ選択(null要素)\":{\"type\":\"GROUP_SELECT\",\"value\":[null,null]},\"リンク\":{\"type\":\"LINK\"},\"チェックボックス(空)\":{\"type\":\"CHECK_BOX\",\"value\":[]}}}]", accessor.get("テーブル(null項目)")); - assertNull(accessor.get("カテゴリー(空)")); - assertNull(accessor.get("カテゴリー(null要素)")); + assertEquals("", accessor.get("カテゴリー(空)")); + /* ビルトインフィールドは 1 つしか追加できない + assertEquals("", accessor.get("カテゴリー(null要素)")); + */ assertNull(accessor.get("ステータス")); - assertNull(accessor.get("作業者(空)")); - assertNull(accessor.get("作業者(null要素)")); - assertNull(accessor.get("作業者(null項目)")); + assertEquals("", accessor.get("作業者(空)")); + /* ビルトインフィールドは 1 つしか追加できない + assertEquals("", accessor.get("作業者(null要素)")); + assertEquals("", accessor.get("作業者(null項目)")); + */ } private Record nullRecord() @@ -340,11 +344,15 @@ private Record nullRecord() record.putField("テーブル(null要素)", new SubtableFieldValue(null, null)); record.putField("テーブル(null項目)", new SubtableFieldValue(nullTableRow(), nullTableRow())); record.putField("カテゴリー(空)", new CategoryFieldValue()); + /* ビルトインフィールドは 1 つしか追加できない record.putField("カテゴリー(null要素)", new CategoryFieldValue(null, null)); + */ record.putField("ステータス", new StatusFieldValue(null)); record.putField("作業者(空)", new StatusAssigneeFieldValue()); + /* ビルトインフィールドは 1 つしか追加できない record.putField("作業者(null要素)", new StatusAssigneeFieldValue(null, null)); record.putField("作業者(null項目)", new StatusAssigneeFieldValue(user(null, null), user(null, null))); + */ return record; } From 602f88ab7a68455550d69097274b386fcae377b9 Mon Sep 17 00:00:00 2001 From: Tetsuro Sano Date: Mon, 13 Feb 2023 13:32:23 +0900 Subject: [PATCH 4/4] Update version 0.1.8 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 36386d2..185f2d1 100644 --- a/build.gradle +++ b/build.gradle @@ -12,7 +12,7 @@ repositories { } group = "io.trocco" -version = "0.1.7" +version = "0.1.8" sourceCompatibility = 1.8 targetCompatibility = 1.8