Repository: mjaakko/NeoStumbler (language: kotlin)

Issue:
Ichnaea incompatibility since 1.4.0 (null values in JSON request)
### Description

Since 1.4.0 report upload to an Ichnaea instance is broken, the following is a (redacted and shortened) JSON request:
```json
{
    "items":
    [
        {
            "bluetoothBeacons": null,
            "cellTowers": null,
            "position":
            {
                "accuracy": 128.0,
                "age": 24,
                "altitude": xx.xx,
                "altitudeAccuracy": null,
                "heading": null,
                "latitude": xx.xx,
                "longitude": xx.xx,
                "pressure": null,
                "source": "gps",
                "speed": xx.xx
            },
            "timestamp": 1733504109567,
            "wifiAccessPoints":
            [
                {
                    "age": 7550,
                    "channel": null,
                    "frequency": 2437,
                    "macAddress": "xx:xx:xx:xx:xx:xx",
                    "radioType": "802.11n",
                    "signalStrength": -66,
                    "signalToNoiseRatio": null,
                    "ssid": "xxxxxxx"
                }
            ]
        }
    ]
}
```

And it's response:
```json
{
    "details": {
        "validation": {
            "items.0.bluetoothBeacons": "\"None\" is not iterable",
            "items.0.cellTowers": "\"None\" is not iterable",
        }
    },
    "error": {
        "code": 400,
        "errors": [
            {
                "domain": "global",
                "message": "Parse Error",
                "reason": "parseError"
            }
        ],
        "message": "Parse Error"
    }
}
```

If I do this request manually with curl but remove

```json
"bluetoothBeacons": null,
"cellTowers": null,
```

it works fine.


I think in general we should not add keys with null values but simply leave out empty keys?

### App variant

full

### Version

1.4.0

### Device

SM-A310F

### Android version

LineageOS 18.1 (Android 11)

### Logs

_No response_

### New bug

- [X] I have checked that this bug has not been reported before


Discussion hints:
nan

Pull request: Fix Ichnaea compatibility by not encoding null values
Fixes #337 

Test command: ./gradlew :app:testFullDebugUnitTest --tests "xyz.malkki.neostumbler.geosubmit.MLSGeosubmitTest"

Fix patch:
diff --git a/app/src/main/java/xyz/malkki/neostumbler/geosubmit/MLSGeosubmit.kt b/app/src/main/java/xyz/malkki/neostumbler/geosubmit/MLSGeosubmit.kt
index e9d6495e..372291fc 100644
--- a/app/src/main/java/xyz/malkki/neostumbler/geosubmit/MLSGeosubmit.kt
+++ b/app/src/main/java/xyz/malkki/neostumbler/geosubmit/MLSGeosubmit.kt
@@ -20,6 +20,10 @@ class MLSGeosubmit(
     private val httpClient: Call.Factory,
     private val geosubmitParams: GeosubmitParams
 ) : Geosubmit {
+    companion object {
+        private val JSON_ENCODER = Json { explicitNulls = false }
+    }
+
     override suspend fun sendReports(reports: List<Report>) {
         val url = geosubmitParams.toUrl()
         require(url != null) {
@@ -48,7 +52,7 @@ class MLSGeosubmit(
                 GZIPOutputStream(CloseShieldOutputStream.wrap(sink.outputStream()), BUFFER_SIZE)
                     .buffered()
                     .use {
-                        Json.encodeToStream(ReportItems(reports), it)
+                        JSON_ENCODER.encodeToStream(ReportItems(reports), it)
                     }
             }
         }


Test patch:
diff --git a/app/src/test/java/xyz/malkki/neostumbler/geosubmit/MLSGeosubmitTest.kt b/app/src/test/java/xyz/malkki/neostumbler/geosubmit/MLSGeosubmitTest.kt
index d06002cc..50f4faf3 100644
--- a/app/src/test/java/xyz/malkki/neostumbler/geosubmit/MLSGeosubmitTest.kt
+++ b/app/src/test/java/xyz/malkki/neostumbler/geosubmit/MLSGeosubmitTest.kt
@@ -7,6 +7,7 @@ import okhttp3.OkHttpClient
 import okhttp3.mockwebserver.MockResponse
 import okhttp3.mockwebserver.MockWebServer
 import org.junit.After
+import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
 import org.junit.Before
 import org.junit.Test
@@ -83,5 +84,8 @@ class MLSGeosubmitTest {
 
         val requestBody = GZIPInputStream(request.body.inputStream()).use { it.readAllBytes().toString(StandardCharsets.UTF_8) }
         assertTrue(requestBody.contains("01:01:01:01:01:01"))
+
+        //Check that request body does not contain nulls -> Ichnaea servers don't accept them
+        assertFalse(requestBody.contains("null"))
     }
 }
\ No newline at end of file