Skip to content

Commit

Permalink
Strong typed API for synchronous TDLib method execution in Java inter…
Browse files Browse the repository at this point in the history
…face

`Client.execute` in Java interface is now strongly typed: returned TDLib object type depends on the return type defined in the corresponding Function class.

When TDLib error is occurred, method now throws `Client.ExecutionError`.

This change adds compile-time protection against return type change and allows using this pattern:

```
try {
  TdApi.SpecificReturnType result = Client.execute(function);
  // work with strongly typed resultl without casting and type checks
} catch (Client.ExecutionError error) {
  // Handle error
}
```
  • Loading branch information
vkryl authored and levlam committed Oct 26, 2023
1 parent c031818 commit dd77e46
Showing 1 changed file with 29 additions and 2 deletions.
31 changes: 29 additions & 2 deletions example/java/org/drinkless/tdlib/Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,24 @@ public interface LogMessageHandler {
void onLogMessage(int verbosityLevel, String message);
}

/**
* Exception class thrown when TDLib error occurred while performing {@link #execute(TdApi.Function)}.
*/
public static class ExecutionError extends Throwable {
/**
* Original TDLib error occurred when performing one of the synchronous functions.
*/
public final TdApi.Error error;

/**
* @param error TDLib error occurred while performing {@link #execute(TdApi.Function)}.
*/
ExecutionError (TdApi.Error error) {
super(error.code + ": " + error.message);
this.error = error;
}
}

/**
* Sends a request to the TDLib.
*
Expand Down Expand Up @@ -102,8 +120,17 @@ public void send(TdApi.Function query, ResultHandler resultHandler) {
* @return request result.
* @throws NullPointerException if query is null.
*/
public static TdApi.Object execute(TdApi.Function query) {
return nativeClientExecute(query);
public static <T extends TdApi.Object> T execute(TdApi.Function<T> query) throws ExecutionError {

This comment has been minimized.

Copy link
@eugeneRover

eugeneRover Nov 3, 2023

This breaks java Example compilation.
The following code :

        if (Client.execute(new TdApi.SetLogStream(new TdApi.LogStreamFile("tdlib.log", 1 << 27, false))) instanceof TdApi.Error) {
            throw new IOError(new IOException("Write access to the current directory is required"));
        }

now fails to compile with an error:

[ 60%] Building Java code
/home/user/my-workspace/td/example/java/org/drinkless/tdlib/example/Example.java:306: error: incompatible types: Ok cannot be converted to Error
        if (Client.execute(new TdApi.SetLogStream(new TdApi.LogStreamFile("tdlib.log", 1 << 27, false))) instanceof TdApi.Error) {
                          ^
Note: /home/user/my-workspace/td/example/java/org/drinkless/tdlib/Client.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
1 error
gmake[2]: *** [CMakeFiles/build_java.dir/build.make:77: CMakeFiles/build_java] Ошибка 1
gmake[1]: *** [CMakeFiles/Makefile2:154: CMakeFiles/build_java.dir/all] Ошибка 2
gmake: *** [Makefile:149: all] Ошибка 2
TdApi.Object object = nativeClientExecute(query);
if (object instanceof TdApi.Error) {
throw new ExecutionError((TdApi.Error) object);
}
if (object == null) {
// unreachable
throw new NullPointerException();
}
//noinspection unchecked
return (T) object;
}

/**
Expand Down

0 comments on commit dd77e46

Please sign in to comment.