Repository: influxdata/influxdb-client-java (java)

Issue:
The empty string is converted to null
Hi there,
When I query the empty string, I find that the value I get is null, So I debug the source code to find the empty string is converted to null. 
why it is designed this way?
Below is the source code section.
```
    @Nullable
    private Object toValue(@Nullable final String strValue, final @Nonnull FluxColumn column) {

        Arguments.checkNotNull(column, "column");

        // Default value
        if (strValue == null || strValue.isEmpty()) {
            String defaultValue = column.getDefaultValue();
            if (defaultValue == null || defaultValue.isEmpty()) {
                return null;
            }

            return toValue(defaultValue, column);
        }

        String dataType = column.getDataType();
        switch (dataType) {
            case "boolean":
                return Boolean.valueOf(strValue);
            case "unsignedLong":
                return Long.parseUnsignedLong(strValue);
            case "long":
                return Long.parseLong(strValue);
            case "double":
                switch (strValue) {
                    case "+Inf":
                        return Double.POSITIVE_INFINITY;
                    case "-Inf":
                        return Double.NEGATIVE_INFINITY;
                    default:
                        return Double.parseDouble(strValue);
                }
            case "base64Binary":
                return Base64.getDecoder().decode(strValue);
            case "dateTime:RFC3339":
            case "dateTime:RFC3339Nano":
                return Instant.parse(strValue);
            case "duration":
                return Duration.ofNanos(Long.parseUnsignedLong(strValue));
            default:
            case "string":
                return strValue;
        }
    }
```

Pull request:
fix: Issue/644
Closes #644

## Proposed Changes

When FluxCSVParser parses a value, and the stringValue is empty and the default value for the column is empty, now checks whether the data type for the column is "string" and if this is the case returns the empty default value instead of null.

Note that headerless csv tables will still return null and that null will be returned if the default value is null. 

Two tests are added to FluxCsvParserTest.

## Checklist

<!-- Checkboxes below this note can be erased if not applicable to your Pull Request. -->

- [x] CHANGELOG.md updated
- [x] Rebased/mergeable
- [x] A test has been added if appropriate
- [x] `mvn test` completes successfully
- [x] Commit messages are [conventional](https://www.conventionalcommits.org/en/v1.0.0/)
- [x] Sign [CLA](https://www.influxdata.com/legal/cla/) (if not already signed)


Patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 3ed02d579d..809c7c5ee7 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -200,7 +200,7 @@ jobs:
             - maven-cache_v3-<< parameters.maven-image >>-
       - run:
           name: "Check generate site"
-          command: mvn clean site site:stage -DskipTests
+          command: mvn clean install site site:stage -DskipTests
 
   deploy-snapshot:
     docker:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index aec05e6a72..362f1b1718 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,8 @@
 ## 6.11.0 [unreleased]
 
+### Bug Fixes
+1. [#648](https://github.com/influxdata/influxdb-client-java/pull/648): With csv parsing, return empty string when `stringValue` and `defaultValue` are both an empty string.
+
 ### Dependencies
 
 Update dependencies:
diff --git a/client-core/src/main/java/com/influxdb/query/internal/FluxCsvParser.java b/client-core/src/main/java/com/influxdb/query/internal/FluxCsvParser.java
index db4633c4d6..10b7d8b1b5 100644
--- a/client-core/src/main/java/com/influxdb/query/internal/FluxCsvParser.java
+++ b/client-core/src/main/java/com/influxdb/query/internal/FluxCsvParser.java
@@ -303,18 +303,20 @@ public class FluxCsvParser {
     private Object toValue(@Nullable final String strValue, final @Nonnull FluxColumn column) {
 
         Arguments.checkNotNull(column, "column");
+        String dataType = column.getDataType();
 
         // Default value
         if (strValue == null || strValue.isEmpty()) {
             String defaultValue = column.getDefaultValue();
             if (defaultValue == null || defaultValue.isEmpty()) {
+                if ("string".equals(dataType)) {
+                    return defaultValue;
+                }
                 return null;
             }
-
             return toValue(defaultValue, column);
         }
 
-        String dataType = column.getDataType();
         switch (dataType) {
             case "boolean":
                 return Boolean.valueOf(strValue);


Test patch:
diff --git a/client-core/src/test/java/com/influxdb/query/internal/FluxCsvParserTest.java b/client-core/src/test/java/com/influxdb/query/internal/FluxCsvParserTest.java
index 978dbddb34..df3b492e62 100644
--- a/client-core/src/test/java/com/influxdb/query/internal/FluxCsvParserTest.java
+++ b/client-core/src/test/java/com/influxdb/query/internal/FluxCsvParserTest.java
@@ -674,6 +674,60 @@ class FluxCsvParserTest {
         Assertions.assertThat(tables.get(0).getRecords().get(0).getRow().get(7)).isEqualTo(25.3);
     }
 
+
+    @Test
+    public void parseEmptyString() throws IOException {
+        String data = "#group,false,false,true,true,true,true,true,false,false\n"
+          + "#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,string,string,string,double,string\n"
+          + "#default,_result,,,,,,nana,,\n"
+          + ",result,table,_start,_stop,_field,_measurement,owner,le,_value\n"
+          + ",,0,2021-06-23T06:50:11.897825012Z,2021-06-25T06:50:11.897825012Z,wumpus,snipe,influxdata,0,\"foo\"\n"
+          + ",,0,2021-06-23T06:50:11.897825012Z,2021-06-25T06:50:11.897825012Z,wumpus,snipe,,10,\"foo\"\n"
+          + ",,0,2021-06-23T06:50:11.897825012Z,2021-06-25T06:50:11.897825012Z,wumpus,snipe,\"\",20,\"foo\"\n"
+          + ",,0,2021-06-23T06:50:11.897825012Z,2021-06-25T06:50:11.897825012Z,wumpus,snipe,influxdata,30,\"foo\"\n"
+          + ",,0,2021-06-23T06:50:11.897825012Z,2021-06-25T06:50:11.897825012Z,wumpus,snipe,influxdata,40,\"foo\"\n"
+          + ",,0,2021-06-23T06:50:11.897825012Z,2021-06-25T06:50:11.897825012Z,wumpus,snipe,influxdata,50,\"foo\"\n"
+          + ",,0,2021-06-23T06:50:11.897825012Z,2021-06-25T06:50:11.897825012Z,wumpus,snipe,influxdata,60,\"foo\"\n"
+          + ",,0,2021-06-23T06:50:11.897825012Z,2021-06-25T06:50:11.897825012Z,wumpus,snipe,influxdata,70,\"foo\"\n"
+          + ",,0,2021-06-23T06:50:11.897825012Z,2021-06-25T06:50:11.897825012Z,wumpus,snipe,influxdata,80,\"\"\n"
+          + ",,0,2021-06-23T06:50:11.897825012Z,2021-06-25T06:50:11.897825012Z,wumpus,snipe,influxdata,90,\n"
+          + ",,0,2021-06-23T06:50:11.897825012Z,2021-06-25T06:50:11.897825012Z,wumpus,snipe,influxdata,100,\"bar\"\n"
+          + ",,0,2021-06-23T06:50:11.897825012Z,2021-06-25T06:50:11.897825012Z,wumpus,snipe,influxdata,-100,\"bar\"\n"
+          + "\n";
+
+        List<FluxTable> tables = parseFluxResponse(data);
+
+        Assertions.assertThat(tables).hasSize(1);
+        Assertions.assertThat(tables.get(0).getRecords().get(7).getValue()).isEqualTo("foo");
+        Assertions.assertThat(tables.get(0).getRecords().get(8).getValue()).isEqualTo(""); // -- todo make sure default value is respected
+        Assertions.assertThat(tables.get(0).getRecords().get(9).getValue()).isNotNull();
+        Assertions.assertThat(tables.get(0).getRecords().get(10).getValue()).isEqualTo("bar");
+        Assertions.assertThat(tables.get(0).getRecords().get(0).getValueByKey("owner")).isEqualTo("influxdata");
+        Assertions.assertThat(tables.get(0).getRecords().get(1).getValueByKey("owner")).isEqualTo("nana");
+        Assertions.assertThat(tables.get(0).getRecords().get(2).getValueByKey("owner")).isEqualTo("nana");
+    }
+
+    @Test
+    public void parseEmptyStringWithoutTableDefinition() throws IOException {
+
+        String data = ",result,table,_start,_stop,_time,_value,_field,_measurement,host,value\n"
+          + ",,0,1970-01-01T00:00:10Z,1970-01-01T00:00:20Z,1970-01-01T00:00:10Z,10,free,mem,A,12.25\n"
+          + ",,1,1970-01-01T00:00:10Z,1970-01-01T00:00:20Z,1970-01-01T00:00:10Z,,free,mem,,15.55\n";
+
+        parser = new FluxCsvParser(FluxCsvParser.ResponseMetadataMode.ONLY_NAMES);
+        List<FluxTable> tables = parseFluxResponse(data);
+
+        Assertions.assertThat(tables).hasSize(2);
+        Assertions.assertThat(tables.get(0).getRecords()).hasSize(1);
+        Assertions.assertThat(tables.get(0).getRecords().get(0).getValues().get("value")).isEqualTo("12.25");
+        Assertions.assertThat(tables.get(0).getRecords().get(0).getValues().get("host")).isEqualTo("A");
+        Assertions.assertThat(tables.get(0).getRecords().get(0).getValue()).isEqualTo("10");
+        Assertions.assertThat(tables.get(1).getRecords()).hasSize(1);
+        Assertions.assertThat(tables.get(1).getRecords().get(0).getValues().get("value")).isEqualTo("15.55");
+        Assertions.assertThat(tables.get(1).getRecords().get(0).getValues().get("host")).isNull();
+        Assertions.assertThat(tables.get(1).getRecords().get(0).getValue()).isNull();
+    }
+
     @Nonnull
     private List<FluxTable> parseFluxResponse(@Nonnull final String data) throws IOException {
 
@@ -712,4 +766,5 @@ class FluxCsvParserTest {
             return cancelled;
         }
     }
+
 }