From 3b7acbc8182e3d3590f1a245f11a9d3380b511a3 Mon Sep 17 00:00:00 2001 From: vkryl <6242627+vkryl@users.noreply.github.com> Date: Thu, 26 Oct 2023 16:41:42 +0300 Subject: [PATCH 1/5] Strongly typed `Client.send` in Java Interface Added new strongly typed methods to Java interface, which allow complie-time protection against function return type changes and avoiding type casting on caller side --- example/java/org/drinkless/tdlib/Client.java | 63 +++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/example/java/org/drinkless/tdlib/Client.java b/example/java/org/drinkless/tdlib/Client.java index 55d53566c3fd..edacada02491 100644 --- a/example/java/org/drinkless/tdlib/Client.java +++ b/example/java/org/drinkless/tdlib/Client.java @@ -33,6 +33,36 @@ public interface ResultHandler { void onResult(TdApi.Object object); } + /** + * Strongly typed interface for handler for results of queries to TDLib and incoming updates from TDLib. + */ + public interface TypedResultHandler { + /** + * Callback called on result of query to TDLib or incoming update from TDLib. + * + * @param object Typed result of query or null if an error has occurred. + * @param error Error received as a result of query or null if query successfully performed. + */ + void onResult(T object, TdApi.Error error); + + /** + * Converts strongly typed {@link TypedResultHandler} to weakly typed {@link ResultHandler}. + * + * @param handler Handler to be converted to {@link ResultHandler} + * @return Handler converted to {@link ResultHandler} + */ + static ResultHandler toResultHandler(TypedResultHandler handler) { + return result -> { + if (result.getConstructor() == TdApi.Error.CONSTRUCTOR) { + handler.onResult(null, (TdApi.Error) result); + } else { + //noinspection unchecked + handler.onResult((T) result, null); + } + }; + } + } + /** * Interface for handler of exceptions thrown while invoking ResultHandler. * By default, all such exceptions are ignored. @@ -113,6 +143,33 @@ public void send(TdApi.Function query, ResultHandler resultHandler) { send(query, resultHandler, null); } + /** + * Sends a request to the TDLib. + * + * @param query Object representing a query to the TDLib. + * @param resultHandler Result handler with onResult method which will be called with result + * of the query or with TdApi.Error as parameter. + * @param exceptionHandler Exception handler with onException method which will be called on + * exception thrown from resultHandler. If it is null, then + * defaultExceptionHandler will be called. + * @throws NullPointerException if query is null. + */ + public void send(TdApi.Function query, TypedResultHandler resultHandler, ExceptionHandler exceptionHandler) { + send(query, TypedResultHandler.toResultHandler(resultHandler), exceptionHandler); + } + + /** + * Sends a request to the TDLib with an empty ExceptionHandler. + * + * @param query Object representing a query to the TDLib. + * @param resultHandler Result handler with onResult method which will be called with result + * of the query or with TdApi.Error as parameter. + * @throws NullPointerException if query is null. + */ + public void send(TdApi.Function query, TypedResultHandler resultHandler) { + send(query, TypedResultHandler.toResultHandler(resultHandler), null); + } + /** * Synchronously executes a TDLib request. Only a few marked accordingly requests can be executed synchronously. * @@ -249,7 +306,11 @@ private Client(ResultHandler updateHandler, ExceptionHandler updateExceptionHand if (defaultExceptionHandler != null) { defaultExceptionHandlers.put(nativeClientId, defaultExceptionHandler); } - send(new TdApi.GetOption("version"), null, null); + send(new TdApi.GetOption("version"), (version, error) -> { + if (error != null) { + // Throw an error? + } + }, null); } private static native int createNativeClient(); From 0f359203b8224fb8862aa85f65152d32baaef76e Mon Sep 17 00:00:00 2001 From: vkryl <6242627+vkryl@users.noreply.github.com> Date: Thu, 26 Oct 2023 16:46:43 +0300 Subject: [PATCH 2/5] Avoid raw use of parametrized `TdApi.Function` --- example/java/org/drinkless/tdlib/Client.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/example/java/org/drinkless/tdlib/Client.java b/example/java/org/drinkless/tdlib/Client.java index edacada02491..7bbdbc3db14b 100644 --- a/example/java/org/drinkless/tdlib/Client.java +++ b/example/java/org/drinkless/tdlib/Client.java @@ -122,7 +122,7 @@ public static class ExecutionError extends Throwable { * defaultExceptionHandler will be called. * @throws NullPointerException if query is null. */ - public void send(TdApi.Function query, ResultHandler resultHandler, ExceptionHandler exceptionHandler) { + public void send(TdApi.Function query, ResultHandler resultHandler, ExceptionHandler exceptionHandler) { long queryId = currentQueryId.incrementAndGet(); if (resultHandler != null) { handlers.put(queryId, new Handler(resultHandler, exceptionHandler)); @@ -139,7 +139,7 @@ public void send(TdApi.Function query, ResultHandler resultHandler, ExceptionHan * defaultExceptionHandler will be called. * @throws NullPointerException if query is null. */ - public void send(TdApi.Function query, ResultHandler resultHandler) { + public void send(TdApi.Function query, ResultHandler resultHandler) { send(query, resultHandler, null); } @@ -315,11 +315,11 @@ private Client(ResultHandler updateHandler, ExceptionHandler updateExceptionHand private static native int createNativeClient(); - private static native void nativeClientSend(int nativeClientId, long eventId, TdApi.Function function); + private static native void nativeClientSend(int nativeClientId, long eventId, TdApi.Function function); private static native int nativeClientReceive(int[] clientIds, long[] eventIds, TdApi.Object[] events, double timeout); - private static native TdApi.Object nativeClientExecute(TdApi.Function function); + private static native TdApi.Object nativeClientExecute(TdApi.Function function); private static native void nativeClientSetLogMessageHandler(int maxVerbosityLevel, LogMessageHandler logMessageHandler); } From 97870b264f2b75b4a4734fe9a0025b4c4aeee6dd Mon Sep 17 00:00:00 2001 From: vkryl <6242627+vkryl@users.noreply.github.com> Date: Thu, 26 Oct 2023 17:07:39 +0300 Subject: [PATCH 3/5] Added `Client.send` without any handlers --- example/java/org/drinkless/tdlib/Client.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/example/java/org/drinkless/tdlib/Client.java b/example/java/org/drinkless/tdlib/Client.java index 7bbdbc3db14b..c97c89ee7b1f 100644 --- a/example/java/org/drinkless/tdlib/Client.java +++ b/example/java/org/drinkless/tdlib/Client.java @@ -130,6 +130,16 @@ public void send(TdApi.Function query, ResultHandler resultHandler, Exception nativeClientSend(nativeClientId, queryId, query); } + /** + * Sends a request to the TDLib with an empty ResultHandler and ExceptionHandler. + * + * @param query Object representing a query to the TDLib. + * @throws NullPointerException if query is null. + */ + public void send(TdApi.Function query) { + send(query, (ResultHandler) null, null); + } + /** * Sends a request to the TDLib with an empty ExceptionHandler. * From 9eebbcb31df6f2f832e93eeaa35e51057aac3622 Mon Sep 17 00:00:00 2001 From: vkryl <6242627+vkryl@users.noreply.github.com> Date: Thu, 26 Oct 2023 17:09:00 +0300 Subject: [PATCH 4/5] Fixed typo in documentation for Java layer When `resultHandler` is null, nothing is called --- example/java/org/drinkless/tdlib/Client.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/example/java/org/drinkless/tdlib/Client.java b/example/java/org/drinkless/tdlib/Client.java index c97c89ee7b1f..142ebcdf860b 100644 --- a/example/java/org/drinkless/tdlib/Client.java +++ b/example/java/org/drinkless/tdlib/Client.java @@ -145,8 +145,7 @@ public void send(TdApi.Function query) { * * @param query Object representing a query to the TDLib. * @param resultHandler Result handler with onResult method which will be called with result - * of the query or with TdApi.Error as parameter. If it is null, then - * defaultExceptionHandler will be called. + * of the query or with TdApi.Error as parameter. * @throws NullPointerException if query is null. */ public void send(TdApi.Function query, ResultHandler resultHandler) { From a71f73613aa7804590c8e6e69f10afe11dfdf7a3 Mon Sep 17 00:00:00 2001 From: vkryl <6242627+vkryl@users.noreply.github.com> Date: Thu, 26 Oct 2023 20:48:00 +0300 Subject: [PATCH 5/5] Allow passing `null` to `TypedResultHandler.toResultHandler` --- example/java/org/drinkless/tdlib/Client.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/example/java/org/drinkless/tdlib/Client.java b/example/java/org/drinkless/tdlib/Client.java index 142ebcdf860b..0c534d264e8b 100644 --- a/example/java/org/drinkless/tdlib/Client.java +++ b/example/java/org/drinkless/tdlib/Client.java @@ -52,6 +52,9 @@ public interface TypedResultHandler { * @return Handler converted to {@link ResultHandler} */ static ResultHandler toResultHandler(TypedResultHandler handler) { + if (handler == null) { + return null; + } return result -> { if (result.getConstructor() == TdApi.Error.CONSTRUCTOR) { handler.onResult(null, (TdApi.Error) result);