From c9b7bd7b1285e8feb902daa208eacd7655a380ee Mon Sep 17 00:00:00 2001 From: Alex Kormukhin Date: Fri, 18 Feb 2022 21:04:14 +0300 Subject: THRIFT-5519 Java async client loses exceptions in void methods Client: java (cherry picked from commit c4d3e36ed4db97fb6213cc13a4e611a4e658b4b7) --- .../cpp/src/thrift/generate/t_java_generator.cc | 4 + lib/java/gradle/generateTestThrift.gradle | 1 + .../test/voidmethexceptions/ServiceAsyncImp.java | 85 ++++ .../test/voidmethexceptions/ServiceBase.java | 44 ++ .../test/voidmethexceptions/ServiceSyncImp.java | 72 +++ .../voidmethexceptions/TestVoidMethExceptions.java | 549 +++++++++++++++++++++ test/Makefile.am | 1 + test/VoidMethExceptionsTest.thrift | 13 + 8 files changed, 769 insertions(+) create mode 100644 lib/java/test/org/apache/thrift/test/voidmethexceptions/ServiceAsyncImp.java create mode 100644 lib/java/test/org/apache/thrift/test/voidmethexceptions/ServiceBase.java create mode 100644 lib/java/test/org/apache/thrift/test/voidmethexceptions/ServiceSyncImp.java create mode 100644 lib/java/test/org/apache/thrift/test/voidmethexceptions/TestVoidMethExceptions.java create mode 100644 test/VoidMethExceptionsTest.thrift diff --git a/compiler/cpp/src/thrift/generate/t_java_generator.cc b/compiler/cpp/src/thrift/generate/t_java_generator.cc index ceabe6687..3fa5f5783 100644 --- a/compiler/cpp/src/thrift/generate/t_java_generator.cc +++ b/compiler/cpp/src/thrift/generate/t_java_generator.cc @@ -3250,6 +3250,10 @@ void t_java_generator::generate_service_async_client(t_service* tservice) { "client.getProtocolFactory().getProtocol(memoryTransport);" << endl; indent(f_service_); if (ret_type->is_void()) { // NB: Includes oneways which always return void. + if (!(*f_iter)->is_oneway()) { + f_service_ << "(new Client(prot)).recv" + sep + javaname + "();" << endl; + indent(f_service_); + } f_service_ << "return null;" << endl; } else { f_service_ << "return (new Client(prot)).recv" + sep + javaname + "();" << endl; diff --git a/lib/java/gradle/generateTestThrift.gradle b/lib/java/gradle/generateTestThrift.gradle index 4b712ca23..996c5fa10 100644 --- a/lib/java/gradle/generateTestThrift.gradle +++ b/lib/java/gradle/generateTestThrift.gradle @@ -81,6 +81,7 @@ task generateJava(group: 'Build') { thriftCompile(it, 'JavaDeepCopyTest.thrift') thriftCompile(it, 'EnumContainersTest.thrift') thriftCompile(it, 'JavaBinaryDefault.thrift') + thriftCompile(it, 'VoidMethExceptionsTest.thrift') thriftCompile(it, 'partial/thrift_test_schema.thrift') } diff --git a/lib/java/test/org/apache/thrift/test/voidmethexceptions/ServiceAsyncImp.java b/lib/java/test/org/apache/thrift/test/voidmethexceptions/ServiceAsyncImp.java new file mode 100644 index 000000000..419e327de --- /dev/null +++ b/lib/java/test/org/apache/thrift/test/voidmethexceptions/ServiceAsyncImp.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.thrift.test.voidmethexceptions; + +import org.apache.thrift.TApplicationException; +import org.apache.thrift.TException; +import org.apache.thrift.async.AsyncMethodCallback; +import thrift.test.voidmethexceptions.TAppService01; +import thrift.test.voidmethexceptions.TExampleException; + +public class ServiceAsyncImp extends ServiceBase implements TAppService01.AsyncIface { + + @Override + public void returnString(String msg, + boolean throwException, + AsyncMethodCallback resultHandler) throws TException { + if (throwException) { + resultHandler.onError(new TExampleException(msg)); + } else { + resultHandler.onComplete(msg); + } + } + + @Override + public void returnVoidThrows(String msg, + boolean throwException, + AsyncMethodCallback resultHandler) throws TException { + if (throwException) { + resultHandler.onError(new TExampleException(msg)); + } else { + resultHandler.onComplete(null); + } + } + + @Override + public void returnVoidNoThrowsRuntimeException(String msg, + boolean throwException, + AsyncMethodCallback resultHandler) throws TException { + if (throwException) { + resultHandler.onError(new RuntimeException(msg)); + } else { + resultHandler.onComplete(null); + } + } + + @Override + public void returnVoidNoThrowsTApplicationException(String msg, + boolean throwException, + AsyncMethodCallback resultHandler) throws TException { + if (throwException) { + resultHandler.onError(new TApplicationException(TApplicationException.INTERNAL_ERROR, msg)); + } else { + resultHandler.onComplete(null); + } + } + + @Override + public void onewayVoidNoThrows(String msg, + boolean throwException, + AsyncMethodCallback resultHandler) throws TException { + if (throwException) { + resultHandler.onError(new TApplicationException(TApplicationException.INTERNAL_ERROR, msg)); + } else { + // simulate hang up + } + } + +} diff --git a/lib/java/test/org/apache/thrift/test/voidmethexceptions/ServiceBase.java b/lib/java/test/org/apache/thrift/test/voidmethexceptions/ServiceBase.java new file mode 100644 index 000000000..5502b09cd --- /dev/null +++ b/lib/java/test/org/apache/thrift/test/voidmethexceptions/ServiceBase.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.thrift.test.voidmethexceptions; + +public class ServiceBase { + + private volatile boolean cancelled = false; + + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + protected void waitForCancel() { + while (!isCancelled()) { + try { + Thread.sleep(10L); + } catch (InterruptedException x) { + break; + } + } + } + +} diff --git a/lib/java/test/org/apache/thrift/test/voidmethexceptions/ServiceSyncImp.java b/lib/java/test/org/apache/thrift/test/voidmethexceptions/ServiceSyncImp.java new file mode 100644 index 000000000..a8a08b5b9 --- /dev/null +++ b/lib/java/test/org/apache/thrift/test/voidmethexceptions/ServiceSyncImp.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.thrift.test.voidmethexceptions; + +import org.apache.thrift.TApplicationException; +import org.apache.thrift.TException; +import thrift.test.voidmethexceptions.TAppService01; +import thrift.test.voidmethexceptions.TExampleException; + +public class ServiceSyncImp extends ServiceBase implements TAppService01.Iface { + + @Override + public String returnString(String msg, + boolean throwException) throws TExampleException, TException { + if (throwException) { + throw new TExampleException(msg); + } + return msg; + } + + @Override + public void returnVoidThrows(String msg, + boolean throwException) throws TExampleException, TException { + if (throwException) { + throw new TExampleException(msg); + } + } + + @Override + public void returnVoidNoThrowsRuntimeException(String msg, + boolean throwException) throws TException { + if (throwException) { + throw new RuntimeException(msg); + } + } + + @Override + public void returnVoidNoThrowsTApplicationException(String msg, + boolean throwException) throws TException { + if (throwException) { + throw new TApplicationException(TApplicationException.INTERNAL_ERROR, msg); + } + } + + @Override + public void onewayVoidNoThrows(String msg, boolean throwException) throws TException { + if (throwException) { + throw new TApplicationException(TApplicationException.INTERNAL_ERROR, msg); + } else { + // simulate hang up + waitForCancel(); + } + } + +} diff --git a/lib/java/test/org/apache/thrift/test/voidmethexceptions/TestVoidMethExceptions.java b/lib/java/test/org/apache/thrift/test/voidmethexceptions/TestVoidMethExceptions.java new file mode 100644 index 000000000..af39262bb --- /dev/null +++ b/lib/java/test/org/apache/thrift/test/voidmethexceptions/TestVoidMethExceptions.java @@ -0,0 +1,549 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.thrift.test.voidmethexceptions; + +import org.apache.commons.lang3.tuple.Pair; +import org.apache.thrift.TApplicationException; +import org.apache.thrift.TConfiguration; +import org.apache.thrift.TProcessor; +import org.apache.thrift.async.AsyncMethodCallback; +import org.apache.thrift.async.TAsyncClientManager; +import org.apache.thrift.protocol.TBinaryProtocol; +import org.apache.thrift.server.TNonblockingServer; +import org.apache.thrift.server.TServer; +import org.apache.thrift.transport.TNonblockingServerSocket; +import org.apache.thrift.transport.TNonblockingSocket; +import org.apache.thrift.transport.TSocket; +import org.apache.thrift.transport.TTransport; +import org.apache.thrift.transport.layered.TFramedTransport; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import thrift.test.voidmethexceptions.TAppService01; +import thrift.test.voidmethexceptions.TExampleException; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; + +@RunWith(Parameterized.class) +public class TestVoidMethExceptions { + + private static final Logger log = LoggerFactory.getLogger(TestVoidMethExceptions.class); + + private static final int TIMEOUT_MILLIS = 5_000; + + private final ServerImplementationType serverImplementationType; + + private TServer server; + private Thread serverThread; + private int serverPort; + + + public TestVoidMethExceptions(ServerImplementationType serverImplementationType) { + Assert.assertNotNull(serverImplementationType); + this.serverImplementationType = serverImplementationType; + } + + + @Parameters(name = "serverImplementationType = {0}") + public static Object[][] parameters() { + return new Object[][]{{ServerImplementationType.SYNC_SERVER}, + {ServerImplementationType.ASYNC_SERVER}}; + } + + + @Before + public void setUp() throws Exception { + serverPort = -1; + serverImplementationType.service.setCancelled(false); + CompletableFuture futureServerStarted = new CompletableFuture<>(); + TNonblockingServerSocket serverTransport = new TNonblockingServerSocket(0); + TNonblockingServer.Args args = new TNonblockingServer.Args(serverTransport); + args.processor(serverImplementationType.processor); + server = new TNonblockingServer(args) { + + @Override + protected void setServing(boolean serving) { + super.setServing(serving); + + if (serving) { + serverPort = serverTransport.getPort(); + futureServerStarted.complete(null); + } + } + + }; + + serverThread = new Thread(() -> { + server.serve(); + }, "thrift-server"); + serverThread.setDaemon(true); + serverThread.start(); + futureServerStarted.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); + } + + @After + public void tearDown() throws Exception { + serverImplementationType.service.setCancelled(true); + server.stop(); + serverThread.join(TIMEOUT_MILLIS); + } + + + @Test + public void testSyncClientMustReturnResultReturnString() throws Exception { + checkSyncClient("returnString", + "sent msg", + false, + "sent msg", + null, + null, + (client, msg, throwException) -> { + return client.returnString(msg, throwException); + }); + } + + @Test + public void testSyncClientMustReturnResultReturnVoidThrows() throws Exception { + checkSyncClient("returnVoidThrows", + "sent msg", + false, + null, + null, + null, + (client, msg, throwException) -> { + client.returnVoidThrows(msg, throwException); + return null; + }); + } + + @Test + public void testSyncClientMustReturnResultReturnVoidNoThrowsRuntimeException() throws Exception { + checkSyncClient("returnVoidNoThrowsRuntimeException", + "sent msg", + false, + null, + null, + null, + (client, msg, throwException) -> { + client.returnVoidNoThrowsRuntimeException(msg, throwException); + return null; + }); + } + + @Test + public void testSyncClientMustReturnResultReturnVoidNoThrowsTApplicationException() throws Exception { + checkSyncClient("returnVoidNoThrowsTApplicationException", + "sent msg", + false, + null, + null, + null, + (client, msg, throwException) -> { + client.returnVoidNoThrowsTApplicationException(msg, throwException); + return null; + }); + } + + + @Test + public void testSyncClientMustThrowExceptionReturnString() throws Exception { + checkSyncClient("returnString", + "sent msg", + true, + null, + TExampleException.class, + "sent msg", + (client, msg, throwException) -> { + return client.returnString(msg, throwException); + }); + } + + @Test + public void testSyncClientMustThrowExceptionReturnVoidThrows() throws Exception { + checkSyncClient("returnVoidThrows", + "sent msg", + true, + null, + TExampleException.class, + "sent msg", + (client, msg, throwException) -> { + client.returnVoidThrows(msg, throwException); + return null; + }); + } + + @Test + public void testSyncClientMustThrowExceptionReturnVoidNoThrowsRuntimeException() throws Exception { + checkSyncClient("returnVoidNoThrowsRuntimeException", + "sent msg", + true, + null, + TApplicationException.class, + serverImplementationType == ServerImplementationType.ASYNC_SERVER ? "sent msg" + : null, // sync server return "Internal error processing returnVoidNoThrowsRuntimeException" message + (client, msg, throwException) -> { + client.returnVoidNoThrowsRuntimeException(msg, throwException); + return null; + }); + } + + @Test + public void testSyncClientMustThrowExceptionReturnVoidNoThrowsTApplicationException() throws Exception { + checkSyncClient("returnVoidNoThrowsTApplicationException", + "sent msg", + true, + null, + TApplicationException.class, + "sent msg", + (client, msg, throwException) -> { + client.returnVoidNoThrowsTApplicationException(msg, throwException); + return null; + }); + } + + + @Test + public void testAsyncClientMustReturnResultReturnString() throws Throwable { + checkAsyncClient("returnString", + "sent msg", + false, + "sent msg", + null, + null, + (client, msg, throwException, resultHandler) -> { + client.returnString(msg, throwException, resultHandler); + }); + } + + @Test + public void testAsyncClientMustReturnResultReturnVoidThrows() throws Throwable { + checkAsyncClient("returnVoidThrows", + "sent msg", + false, + (Void) null, + null, + null, + (client, msg, throwException, resultHandler) -> { + client.returnVoidThrows(msg, throwException, resultHandler); + }); + } + + @Test + public void testAsyncClientMustReturnResultReturnVoidNoThrowsRuntimeException() throws Throwable { + checkAsyncClient("returnVoidNoThrowsRuntimeException", + "sent msg", + false, + (Void) null, + null, + null, + (client, msg, throwException, resultHandler) -> { + client.returnVoidNoThrowsRuntimeException(msg, throwException, resultHandler); + }); + } + + @Test + public void testAsyncClientMustReturnResultReturnVoidNoThrowsTApplicationException() throws Throwable { + checkAsyncClient("returnVoidNoThrowsTApplicationException", + "sent msg", + false, + (Void) null, + null, + null, + (client, msg, throwException, resultHandler) -> { + client.returnVoidNoThrowsTApplicationException(msg, throwException, resultHandler); + }); + } + + + @Test + public void testAsyncClientMustThrowExceptionReturnString() throws Throwable { + checkAsyncClient("returnString", + "sent msg", + true, + (String) null, + TExampleException.class, + "sent msg", + (client, msg, throwException, resultHandler) -> { + client.returnString(msg, throwException, resultHandler); + }); + } + + @Test + public void testAsyncClientMustThrowExceptionReturnVoidThrows() throws Throwable { + checkAsyncClient("returnVoidThrows", + "sent msg", + true, + (Void) null, + TExampleException.class, + "sent msg", + (client, msg, throwException, resultHandler) -> { + client.returnVoidThrows(msg, throwException, resultHandler); + }); + } + + @Test + public void testAsyncClientMustThrowExceptionReturnVoidNoThrowsRuntimeException() throws Throwable { + checkAsyncClient("returnVoidNoThrowsRuntimeException", + "sent msg", + true, + (Void) null, + TApplicationException.class, + serverImplementationType == ServerImplementationType.ASYNC_SERVER ? "sent msg" + : null, // sync server return "Internal error processing returnVoidNoThrowsRuntimeException" message + (client, msg, throwException, resultHandler) -> { + client.returnVoidNoThrowsRuntimeException(msg, throwException, resultHandler); + }); + } + + @Test + public void testAsyncClientMustThrowExceptionReturnVoidNoThrowsTApplicationException() throws Throwable { + checkAsyncClient("returnVoidNoThrowsTApplicationException", + "sent msg", + true, + (Void) null, + TApplicationException.class, + "sent msg", + (client, msg, throwException, resultHandler) -> { + client.returnVoidNoThrowsTApplicationException(msg, throwException, resultHandler); + }); + } + + + @Test + public void testSyncClientNoWaitForResultNoExceptionOnewayVoidNoThrows() throws Exception { + checkSyncClient("onewayVoidNoThrows", + "sent msg", + false, + null, + null, + null, + (client, msg, throwException) -> { + client.onewayVoidNoThrows(msg, throwException); + return null; + }); + } + + @Test + public void testSyncClientNoWaitForResultExceptionOnewayVoidNoThrows() throws Exception { + checkSyncClient("onewayVoidNoThrows", + "sent msg", + true, + null, + null, + null, + (client, msg, throwException) -> { + client.onewayVoidNoThrows(msg, throwException); + return null; + }); + } + + @Test + public void testAsyncClientNoWaitForResultNoExceptionOnewayVoidNoThrows() throws Throwable { + checkAsyncClient("onewayVoidNoThrows", + "sent msg", + false, + (Void) null, + null, + null, + (client, msg, throwException, resultHandler) -> { + client.onewayVoidNoThrows(msg, throwException, resultHandler); + }); + } + + @Test + public void testAsyncClientNoWaitForResultExceptionOnewayVoidNoThrows() throws Throwable { + checkAsyncClient("onewayVoidNoThrows", + "sent msg", + true, + (Void) null, + null, + null, + (client, msg, throwException, resultHandler) -> { + client.onewayVoidNoThrows(msg, throwException, resultHandler); + }); + } + + + private void checkSyncClient(String desc, + String msg, + boolean throwException, + String expectedResult, + Class expectedExceptionClass, + String expectedExceptionMsg, + SyncCall call) throws Exception { + if (log.isInfoEnabled()) { + log.info("start test checkSyncClient::" + desc + ", throwException: " + throwException + + ", serverImplementationType: " + + serverImplementationType); + } + Assert.assertNotEquals(-1, serverPort); + try (TTransport clientTransport = new TFramedTransport(new TSocket(new TConfiguration(), + "localhost", + serverPort, + TIMEOUT_MILLIS))) { + clientTransport.open(); + TAppService01.Iface client = new TAppService01.Client(new TBinaryProtocol(clientTransport)); + + try { + + String result = call.apply(client, msg, throwException); + + if (throwException && expectedExceptionClass != null) { + Assert.fail("No exception, but must!!!"); + } else { + // expected + Assert.assertEquals(expectedResult, result); + } + } catch (TExampleException | TApplicationException x) { + if (log.isInfoEnabled()) { + log.info("Exception: " + x, x); + } + if (throwException) { + // expected + Assert.assertEquals(expectedExceptionClass, x.getClass()); + if (expectedExceptionMsg != null) { + Assert.assertEquals(expectedExceptionMsg, x.getMessage()); + } + } else { + Assert.fail(); + } + } + } + } + + private void checkAsyncClient(String desc, + String msg, + boolean throwException, + T expectedResult, + Class expectedExceptionClass, + String expectedExceptionMsg, + AsyncCall> call) throws Throwable { + if (log.isInfoEnabled()) { + log.info("start test checkAsyncClient::" + desc + ", throwException: " + throwException + + ", serverImplementationType: " + + serverImplementationType); + } + Assert.assertNotEquals(serverPort, -1); + try (TNonblockingSocket clientTransportAsync = new TNonblockingSocket("localhost", serverPort, TIMEOUT_MILLIS)) { + TAsyncClientManager asyncClientManager = new TAsyncClientManager(); + try { + TAppService01.AsyncClient asyncClient = new TAppService01.AsyncClient(new TBinaryProtocol.Factory(), + asyncClientManager, + clientTransportAsync); + asyncClient.setTimeout(TIMEOUT_MILLIS); + + CompletableFuture futureResult = new CompletableFuture<>(); + + call.apply(asyncClient, msg, throwException, new AsyncMethodCallback() { + + @Override + public void onError(Exception exception) { + futureResult.completeExceptionally(exception); + } + + @Override + public void onComplete(T response) { + futureResult.complete(response); + } + + }); + + try { + T result; + try { + result = futureResult.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); + } catch (ExecutionException x) { + throw x.getCause(); + } + + if (throwException && expectedExceptionClass != null) { + Assert.fail("No exception, but must!!!"); + } else { + // expected + Assert.assertEquals(expectedResult, result); + } + } catch (TExampleException | TApplicationException x) { + if (log.isInfoEnabled()) { + log.info("Exception: " + x, x); + } + if (throwException) { + // expected + Assert.assertEquals(expectedExceptionClass, x.getClass()); + if (expectedExceptionMsg != null) { + Assert.assertEquals(expectedExceptionMsg, x.getMessage()); + } + } else { + Assert.fail(); + } + } + } finally { + asyncClientManager.stop(); + } + } + } + + + private enum ServerImplementationType { + + SYNC_SERVER(() -> { + ServiceSyncImp service = new ServiceSyncImp(); + return Pair.of(new TAppService01.Processor<>(service), service); + }), + ASYNC_SERVER(() -> { + ServiceAsyncImp service = new ServiceAsyncImp(); + return Pair.of(new TAppService01.AsyncProcessor<>(service), service); + }); + + final TProcessor processor; + final ServiceBase service; + + ServerImplementationType(Supplier> supplier) { + Pair pair = supplier.get(); + this.processor = pair.getLeft(); + this.service = pair.getRight(); + } + } + + + @FunctionalInterface + private interface SyncCall { + + R apply(T t, U u, V v) throws Exception; + + } + + + @FunctionalInterface + private interface AsyncCall { + + void apply(T t, U u, V v, X x) throws Exception; + + } + +} diff --git a/test/Makefile.am b/test/Makefile.am index 2199f1e11..6bf12b813 100755 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -167,6 +167,7 @@ EXTRA_DIST = \ UnsafeTypes.thrift \ Service.thrift \ SpecificNameTest.thrift \ + VoidMethExceptionsTest.thrift \ partial/thrift_test_schema.thrift \ known_failures_Linux.json \ test.py \ diff --git a/test/VoidMethExceptionsTest.thrift b/test/VoidMethExceptionsTest.thrift new file mode 100644 index 000000000..fc759767f --- /dev/null +++ b/test/VoidMethExceptionsTest.thrift @@ -0,0 +1,13 @@ +namespace java thrift.test.voidmethexceptions + +exception TExampleException { + 1: required string message; +} + +service TAppService01 { + string returnString(1: string msg, 2: bool throwException) throws (1:TExampleException error); + void returnVoidThrows(1: string msg, 2: bool throwException) throws (1:TExampleException error); + void returnVoidNoThrowsRuntimeException(1: string msg, 2: bool throwException); + void returnVoidNoThrowsTApplicationException(1: string msg, 2: bool throwException); + oneway void onewayVoidNoThrows(1: string msg, 2: bool throwException); +} -- cgit v1.2.1