From a111fdd62d57f565f4a54c92cb042de989b66f14 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 23 Oct 2025 15:48:27 +0200 Subject: [PATCH 1/3] simplify logic in extension Signed-off-by: alperozturk # Conflicts: # app/src/main/java/it/niedermann/owncloud/notes/persistence/CapabilitiesClient.java # app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesServerSyncTask.java --- .../owncloud/notes/util/ThrowableExtensions.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 app/src/main/java/it/niedermann/owncloud/notes/util/ThrowableExtensions.kt diff --git a/app/src/main/java/it/niedermann/owncloud/notes/util/ThrowableExtensions.kt b/app/src/main/java/it/niedermann/owncloud/notes/util/ThrowableExtensions.kt new file mode 100644 index 000000000..f98c2a308 --- /dev/null +++ b/app/src/main/java/it/niedermann/owncloud/notes/util/ThrowableExtensions.kt @@ -0,0 +1,14 @@ +/* + * Nextcloud Notes - Android Client + * + * SPDX-FileCopyrightText: 2021-2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package it.niedermann.owncloud.notes.util + +import com.nextcloud.android.sso.api.EmptyResponse + +fun Throwable.isEmptyResponseCast(): Boolean { + return this is ClassCastException && + (message?.contains(EmptyResponse::class.simpleName ?: "") == true) +} From 52b170e6bfcb03ceeea30853d2262e81cd7c92e4 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 23 Oct 2025 16:16:21 +0200 Subject: [PATCH 2/3] add documentation Signed-off-by: alperozturk --- .../owncloud/notes/util/ThrowableExtensions.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/util/ThrowableExtensions.kt b/app/src/main/java/it/niedermann/owncloud/notes/util/ThrowableExtensions.kt index f98c2a308..aff3cb05c 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/util/ThrowableExtensions.kt +++ b/app/src/main/java/it/niedermann/owncloud/notes/util/ThrowableExtensions.kt @@ -8,6 +8,19 @@ package it.niedermann.owncloud.notes.util import com.nextcloud.android.sso.api.EmptyResponse +/** + * Extension function to detect a specific ClassCastException caused by an empty API response. + * + * This is used to identify cases where the API returns an empty response body, + * which leads to a `ClassCastException` when attempting to deserialize it into a non-nullable type. + * + * In particular, when the API processes an empty Reader (e.g., no changes detected), + * it may result in a `JsonSyntaxException` or similar parsing error. + * This function helps to safely ignore such cases by checking if the exception + * is a `ClassCastException` involving the `EmptyResponse` class. + * + * @return `true` if the Throwable is a ClassCastException referencing `EmptyResponse`, otherwise `false`. + */ fun Throwable.isEmptyResponseCast(): Boolean { return this is ClassCastException && (message?.contains(EmptyResponse::class.simpleName ?: "") == true) From fc594189dec878b57b80b288a769cf5afc299638 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 24 Oct 2025 09:37:47 +0200 Subject: [PATCH 3/3] solve git conflict Signed-off-by: alperozturk --- .../notes/persistence/CapabilitiesClient.java | 22 +++++++++---------- .../persistence/NotesServerSyncTask.java | 6 +++++ 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/CapabilitiesClient.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/CapabilitiesClient.java index bd3d66027..ad62b9dfd 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/CapabilitiesClient.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/CapabilitiesClient.java @@ -13,16 +13,10 @@ import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; -import com.nextcloud.android.sso.api.ParsedResponse; import com.nextcloud.android.sso.model.SingleSignOnAccount; -import java.util.Map; - -import it.niedermann.owncloud.notes.persistence.sync.OcsAPI; import it.niedermann.owncloud.notes.shared.model.Capabilities; -import it.niedermann.owncloud.notes.shared.model.OcsResponse; -import it.niedermann.owncloud.notes.shared.model.OcsUser; -import retrofit2.Response; +import it.niedermann.owncloud.notes.util.ThrowableExtensionsKt; @WorkerThread public class CapabilitiesClient { @@ -34,6 +28,8 @@ public class CapabilitiesClient { @WorkerThread public static Capabilities getCapabilities(@NonNull Context context, @NonNull SingleSignOnAccount ssoAccount, @Nullable String lastETag, @NonNull ApiProvider apiProvider) throws Throwable { final var ocsAPI = apiProvider.getOcsAPI(context, ssoAccount); + final var repository = NotesRepository.getInstance(context); + try { final var response = ocsAPI.getCapabilities(lastETag).blockingSingle(); final var capabilities = response.getResponse().ocs.data; @@ -44,16 +40,20 @@ public static Capabilities getCapabilities(@NonNull Context context, @NonNull Si Log.w(TAG, "Response headers of capabilities are null"); } - final var repository = NotesRepository.getInstance(context); repository.insertCapabilities(capabilities); return capabilities; - } catch (RuntimeException e) { - final var cause = e.getCause(); + } catch (Throwable t) { + if (ThrowableExtensionsKt.isEmptyResponseCast(t)) { + Log.d(TAG, "Server returned empty response - Notes not modified."); + return repository.getCapabilities(); + } + + final var cause = t.getCause(); if (cause != null) { throw cause; } else { - throw e; + throw t; } } } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesServerSyncTask.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesServerSyncTask.java index 03d151a77..c4ff990a3 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesServerSyncTask.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesServerSyncTask.java @@ -42,6 +42,7 @@ import it.niedermann.owncloud.notes.shared.model.ISyncCallback; import it.niedermann.owncloud.notes.shared.model.SyncResultStatus; import it.niedermann.owncloud.notes.shared.util.ApiVersionUtil; +import it.niedermann.owncloud.notes.util.ThrowableExtensionsKt; /** @@ -280,6 +281,11 @@ private boolean pullRemoteChanges() { return true; } catch (Throwable t) { final Throwable cause = t.getCause(); + if (ThrowableExtensionsKt.isEmptyResponseCast(t)) { + Log.d(TAG, "Server returned empty response - Notes not modified."); + return true; + } + if (t.getClass() == RuntimeException.class && cause != null) { if (cause.getClass() == NextcloudHttpRequestFailedException.class || cause instanceof NextcloudHttpRequestFailedException) { final NextcloudHttpRequestFailedException httpException = (NextcloudHttpRequestFailedException) cause;