diff --git a/src/main/java/com/google/api/generator/engine/ast/ThrowExpr.java b/src/main/java/com/google/api/generator/engine/ast/ThrowExpr.java index 5f86e69d3f..5e4808d28a 100644 --- a/src/main/java/com/google/api/generator/engine/ast/ThrowExpr.java +++ b/src/main/java/com/google/api/generator/engine/ast/ThrowExpr.java @@ -22,6 +22,9 @@ public abstract class ThrowExpr implements Expr { // TODO(miraleung): Refactor with StringObjectValue and possibly with NewObjectExpr. + @Nullable + public abstract Expr throwExpr(); + @Override public abstract TypeNode type(); @@ -42,6 +45,9 @@ public static Builder builder() { @AutoValue.Builder public abstract static class Builder { + public abstract Builder setThrowExpr(Expr throwExpr); + + // No-op if setThrowExpr is called. public abstract Builder setType(TypeNode type); public Builder setMessageExpr(String message) { @@ -53,6 +59,8 @@ public Builder setMessageExpr(String message) { public abstract Builder setCauseExpr(Expr expr); // Private. + abstract Expr throwExpr(); + abstract TypeNode type(); abstract Expr messageExpr(); @@ -62,6 +70,24 @@ public Builder setMessageExpr(String message) { abstract ThrowExpr autoBuild(); public ThrowExpr build() { + if (throwExpr() != null) { + setType(throwExpr().type()); + Preconditions.checkState( + messageExpr() == null && causeExpr() == null, + "Only one of throwExpr or [messageExpr or causeExpr, inclusive] can be present."); + + if (throwExpr() instanceof VariableExpr) { + Preconditions.checkState( + !((VariableExpr) throwExpr()).isDecl(), "Cannot throw a variable declaration"); + } + + Preconditions.checkState( + TypeNode.isExceptionType(throwExpr().type()), + String.format("Only exception types can be thrown, found %s", throwExpr().type())); + + return autoBuild(); + } + Preconditions.checkState( TypeNode.isExceptionType(type()), String.format("Type %s must be an exception type", type())); diff --git a/src/main/java/com/google/api/generator/engine/ast/TryCatchStatement.java b/src/main/java/com/google/api/generator/engine/ast/TryCatchStatement.java index 3634374259..1280635e38 100644 --- a/src/main/java/com/google/api/generator/engine/ast/TryCatchStatement.java +++ b/src/main/java/com/google/api/generator/engine/ast/TryCatchStatement.java @@ -17,8 +17,10 @@ import com.google.auto.value.AutoValue; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; +import java.util.ArrayList; import java.util.Collections; import java.util.List; +import javax.annotation.Nonnull; import javax.annotation.Nullable; @AutoValue @@ -26,11 +28,12 @@ public abstract class TryCatchStatement implements Statement { // Required. public abstract ImmutableList tryBody(); + // Optional only if the sample code bit is set (i.e. this is sample code). - @Nullable - public abstract VariableExpr catchVariableExpr(); + public abstract List catchVariableExprs(); // Optional only if the sample code bit is set (i.e. this is sample code). - public abstract ImmutableList catchBody(); + public abstract List> catchBlocks(); + // Optional. @Nullable public abstract AssignmentExpr tryResourceExpr(); @@ -44,8 +47,9 @@ public void accept(AstNodeVisitor visitor) { public static Builder builder() { return new AutoValue_TryCatchStatement.Builder() - .setIsSampleCode(false) - .setCatchBody(Collections.emptyList()); + .setCatchVariableExprs(Collections.emptyList()) + .setCatchBlocks(Collections.emptyList()) + .setIsSampleCode(false); } @AutoValue.Builder @@ -54,32 +58,61 @@ public abstract static class Builder { public abstract Builder setTryBody(List body); - public abstract Builder setCatchVariableExpr(VariableExpr variableExpr); + public abstract Builder setIsSampleCode(boolean isSampleCode); - public abstract Builder setCatchBody(List body); + public Builder addCatch(@Nonnull VariableExpr variableExpr, List body) { + List catchVarExprs = new ArrayList<>(catchVariableExprs()); + catchVarExprs.add(variableExpr); + setCatchVariableExprs(catchVarExprs); - public abstract Builder setIsSampleCode(boolean isSampleCode); + List> blocks = new ArrayList<>(catchBlocks()); + blocks.add(body); + return setCatchBlocks(blocks); + } + + // Private. + abstract Builder setCatchVariableExprs(List variableExpr); + + abstract Builder setCatchBlocks(List> body); + + abstract ImmutableList tryBody(); + + abstract boolean isSampleCode(); + + abstract List catchVariableExprs(); + + abstract List> catchBlocks(); abstract TryCatchStatement autoBuild(); public TryCatchStatement build() { - TryCatchStatement tryCatchStatement = autoBuild(); - NodeValidator.checkNoNullElements(tryCatchStatement.tryBody(), "try body", "try-catch"); - NodeValidator.checkNoNullElements(tryCatchStatement.catchBody(), "catch body", "try-catch"); + NodeValidator.checkNoNullElements(tryBody(), "try body", "try-catch"); + NodeValidator.checkNoNullElements( + catchVariableExprs(), "catch variable expressions", "try-catch"); + catchBlocks() + .forEach(body -> NodeValidator.checkNoNullElements(body, "catch body", "try-catch")); - if (!tryCatchStatement.isSampleCode()) { - Preconditions.checkNotNull( - tryCatchStatement.catchVariableExpr(), + if (!isSampleCode()) { + Preconditions.checkState( + !catchVariableExprs().isEmpty(), "Catch variable expression must be set for real, non-sample try-catch blocks."); Preconditions.checkState( - tryCatchStatement.catchVariableExpr().isDecl(), - "Catch variable expression must be a declaration"); + catchVariableExprs().stream().allMatch(v -> v.isDecl()), + "Catch variable expressions must all be declarations"); Preconditions.checkState( - TypeNode.isExceptionType(tryCatchStatement.catchVariableExpr().variable().type()), - "Catch variable must be an Exception object reference"); + catchVariableExprs().stream() + .allMatch(v -> TypeNode.isExceptionType(v.variable().type())), + "Catch variables must be an Exception object references"); } - return tryCatchStatement; + // Catch any potential future breakage due to changing addCatch above. + Preconditions.checkState( + catchVariableExprs().size() == catchBlocks().size(), + String.format( + "%d catch variables found and %d blocks found, but these numbers must be equal", + catchVariableExprs().size(), catchBlocks().size())); + + return autoBuild(); } } } diff --git a/src/main/java/com/google/api/generator/engine/writer/ImportWriterVisitor.java b/src/main/java/com/google/api/generator/engine/writer/ImportWriterVisitor.java index 259a027402..58fb2b9aa4 100644 --- a/src/main/java/com/google/api/generator/engine/writer/ImportWriterVisitor.java +++ b/src/main/java/com/google/api/generator/engine/writer/ImportWriterVisitor.java @@ -231,6 +231,13 @@ public void visit(AnonymousClassExpr anonymousClassExpr) { @Override public void visit(ThrowExpr throwExpr) { throwExpr.type().accept(this); + // If throwExpr is present, then messageExpr and causeExpr will not be present. Relies on AST + // build-time checks. + if (throwExpr.throwExpr() != null) { + throwExpr.throwExpr().accept(this); + return; + } + if (throwExpr.messageExpr() != null) { throwExpr.messageExpr().accept(this); } @@ -355,11 +362,13 @@ public void visit(TryCatchStatement tryCatchStatement) { statements(tryCatchStatement.tryBody()); Preconditions.checkState( - !tryCatchStatement.isSampleCode() && tryCatchStatement.catchVariableExpr() != null, + !tryCatchStatement.isSampleCode() && !tryCatchStatement.catchVariableExprs().isEmpty(), "Import generation should not be invoked on sample code, but was found when visiting a" + " try-catch block"); - tryCatchStatement.catchVariableExpr().accept(this); - statements(tryCatchStatement.catchBody()); + for (int i = 0; i < tryCatchStatement.catchVariableExprs().size(); i++) { + tryCatchStatement.catchVariableExprs().get(i).accept(this); + statements(tryCatchStatement.catchBlocks().get(i)); + } } @Override diff --git a/src/main/java/com/google/api/generator/engine/writer/JavaWriterVisitor.java b/src/main/java/com/google/api/generator/engine/writer/JavaWriterVisitor.java index 11ddff441d..a52b584da1 100644 --- a/src/main/java/com/google/api/generator/engine/writer/JavaWriterVisitor.java +++ b/src/main/java/com/google/api/generator/engine/writer/JavaWriterVisitor.java @@ -392,6 +392,13 @@ public void visit(AnonymousClassExpr anonymousClassExpr) { public void visit(ThrowExpr throwExpr) { buffer.append(THROW); space(); + // If throwExpr is present, then messageExpr and causeExpr will not be present. Relies on AST + // build-time checks. + if (throwExpr.throwExpr() != null) { + throwExpr.throwExpr().accept(this); + return; + } + buffer.append(NEW); space(); throwExpr.type().accept(this); @@ -696,17 +703,17 @@ public void visit(TryCatchStatement tryCatchStatement) { statements(tryCatchStatement.tryBody()); rightBrace(); - if (tryCatchStatement.catchVariableExpr() != null) { + for (int i = 0; i < tryCatchStatement.catchVariableExprs().size(); i++) { space(); buffer.append(CATCH); space(); leftParen(); - tryCatchStatement.catchVariableExpr().accept(this); + tryCatchStatement.catchVariableExprs().get(i).accept(this); rightParen(); space(); leftBrace(); newline(); - statements(tryCatchStatement.catchBody()); + statements(tryCatchStatement.catchBlocks().get(i)); rightBrace(); } newline(); diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientTestClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientTestClassComposer.java index 8333a37f64..7d01cfbca3 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientTestClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientTestClassComposer.java @@ -536,7 +536,8 @@ private MethodDefinition createRpcTestMethod( TypeNode.withReference( ConcreteReference.builder() .setClazz(List.class) - .setGenerics(Arrays.asList(repeatedPagedResultsField.type().reference())) + .setGenerics( + Arrays.asList(repeatedPagedResultsField.type().reference())) .build())) .setName("resources") .build()); @@ -824,8 +825,7 @@ protected List createRpcExceptionTestStatements( tryBodyExprs.stream() .map(e -> ExprStatement.withExpr(e)) .collect(Collectors.toList())) - .setCatchVariableExpr(catchExceptionVarExpr.toBuilder().setIsDecl(true).build()) - .setCatchBody(catchBody) + .addCatch(catchExceptionVarExpr.toBuilder().setIsDecl(true).build(), catchBody) .build(); return Arrays.asList(EMPTY_LINE_STATEMENT, tryCatchBlock); diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java index a2ac589a65..034c94c949 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java @@ -40,6 +40,8 @@ import com.google.api.generator.engine.ast.ScopeNode; import com.google.api.generator.engine.ast.Statement; import com.google.api.generator.engine.ast.ThisObjectValue; +import com.google.api.generator.engine.ast.ThrowExpr; +import com.google.api.generator.engine.ast.TryCatchStatement; import com.google.api.generator.engine.ast.TypeNode; import com.google.api.generator.engine.ast.ValueExpr; import com.google.api.generator.engine.ast.Variable; @@ -791,6 +793,34 @@ private List createStubOverrideMethods( .build()) .build(); + // Generate the close() method: + // @Override + // public final void close() { + // try { + // backgroundResources.close(); + // } catch (RuntimeException e) { + // throw e; + // } catch (Exception e) { + // throw new IllegalStateException("Failed to close resource", e); + // } + // } + + VariableExpr catchRuntimeExceptionVarExpr = + VariableExpr.builder() + .setVariable( + Variable.builder() + .setType(TypeNode.withExceptionClazz(RuntimeException.class)) + .setName("e") + .build()) + .build(); + VariableExpr catchExceptionVarExpr = + VariableExpr.builder() + .setVariable( + Variable.builder() + .setType(TypeNode.withExceptionClazz(Exception.class)) + .setName("e") + .build()) + .build(); List javaMethods = new ArrayList<>(); javaMethods.add( methodMakerStarterFn @@ -799,8 +829,33 @@ private List createStubOverrideMethods( .setReturnType(TypeNode.VOID) .setBody( Arrays.asList( - ExprStatement.withExpr( - MethodInvocationExpr.builder().setMethodName("shutdown").build()))) + TryCatchStatement.builder() + .setTryBody( + Arrays.asList( + ExprStatement.withExpr( + MethodInvocationExpr.builder() + .setExprReferenceExpr(backgroundResourcesVarExpr) + .setMethodName("close") + .build()))) + .addCatch( + catchRuntimeExceptionVarExpr.toBuilder().setIsDecl(true).build(), + Arrays.asList( + ExprStatement.withExpr( + ThrowExpr.builder() + .setThrowExpr(catchRuntimeExceptionVarExpr) + .build()))) + .addCatch( + catchExceptionVarExpr.toBuilder().setIsDecl(true).build(), + Arrays.asList( + ExprStatement.withExpr( + ThrowExpr.builder() + .setType( + TypeNode.withExceptionClazz( + IllegalStateException.class)) + .setMessageExpr(String.format("Failed to close resource")) + .setCauseExpr(catchExceptionVarExpr) + .build()))) + .build())) .build()); javaMethods.add(voidMethodMakerFn.apply("shutdown")); javaMethods.add(booleanMethodMakerFn.apply("isShutdown")); diff --git a/src/main/java/com/google/api/generator/gapic/composer/grpc/ServiceClientTestClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/grpc/ServiceClientTestClassComposer.java index 49d7164a55..15b05ee765 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/grpc/ServiceClientTestClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/grpc/ServiceClientTestClassComposer.java @@ -1046,8 +1046,9 @@ protected List createStreamingRpcExceptionTestStatements( tryBodyExprs.stream() .map(e -> ExprStatement.withExpr(e)) .collect(Collectors.toList())) - .setCatchVariableExpr(catchExceptionVarExpr.toBuilder().setIsDecl(true).build()) - .setCatchBody(createRpcLroExceptionTestCatchBody(catchExceptionVarExpr, true)) + .addCatch( + catchExceptionVarExpr.toBuilder().setIsDecl(true).build(), + createRpcLroExceptionTestCatchBody(catchExceptionVarExpr, true)) .build(); statements.add(tryCatchBlock); diff --git a/src/test/java/com/google/api/generator/engine/JavaCodeGeneratorTest.java b/src/test/java/com/google/api/generator/engine/JavaCodeGeneratorTest.java index 8ed58c13cb..6f1e80ca70 100644 --- a/src/test/java/com/google/api/generator/engine/JavaCodeGeneratorTest.java +++ b/src/test/java/com/google/api/generator/engine/JavaCodeGeneratorTest.java @@ -606,8 +606,8 @@ private MethodDefinition createPrintShelfListToFile() { loopShelfList, ExprStatement.withExpr(writeToFileWriter), ExprStatement.withExpr(closeFileWriter))) - .setCatchVariableExpr(createVarDeclExpr(ioException)) - .setCatchBody(Arrays.asList(ExprStatement.withExpr(printError))) + .addCatch( + createVarDeclExpr(ioException), Arrays.asList(ExprStatement.withExpr(printError))) .build(); return MethodDefinition.builder() diff --git a/src/test/java/com/google/api/generator/engine/ast/ThrowExprTest.java b/src/test/java/com/google/api/generator/engine/ast/ThrowExprTest.java index f27d000113..7bc1589feb 100644 --- a/src/test/java/com/google/api/generator/engine/ast/ThrowExprTest.java +++ b/src/test/java/com/google/api/generator/engine/ast/ThrowExprTest.java @@ -14,6 +14,7 @@ package com.google.api.generator.engine.ast; +import static junit.framework.Assert.assertEquals; import static org.junit.Assert.assertThrows; import org.junit.Test; @@ -24,7 +25,24 @@ public void createThrowExpr_basic() { TypeNode npeType = TypeNode.withExceptionClazz(NullPointerException.class); ThrowExpr.builder().setType(npeType).build(); // No exception thrown, we're good. + } + @Test + public void createThrowExpr_basicExpr() { + TypeNode npeType = TypeNode.withExceptionClazz(NullPointerException.class); + VariableExpr throwVarExpr = + VariableExpr.builder() + .setVariable( + Variable.builder() + .setName("e") + .setType(TypeNode.withExceptionClazz(RuntimeException.class)) + .build()) + .build(); + ThrowExpr throwExpr = ThrowExpr.builder().setThrowExpr(throwVarExpr).build(); + assertEquals(throwVarExpr.variable().type(), throwExpr.type()); + // Setting the type doesn't matter. + throwExpr = ThrowExpr.builder().setThrowExpr(throwVarExpr).setType(npeType).build(); + assertEquals(throwVarExpr.variable().type(), throwExpr.type()); } @Test @@ -123,4 +141,75 @@ public void createThrowExpr_messageAndCauseExpr() { .build(); // Successfully created a ThrowExpr. } + + @Test + public void createThrowExpr_cannotThrowVariableDeclaration() { + VariableExpr throwVarExpr = + VariableExpr.builder() + .setVariable( + Variable.builder() + .setName("e") + .setType(TypeNode.withExceptionClazz(RuntimeException.class)) + .build()) + .build(); + assertThrows( + IllegalStateException.class, + () -> + ThrowExpr.builder() + .setThrowExpr(throwVarExpr.toBuilder().setIsDecl(true).build()) + .build()); + } + + @Test + public void createThrowExpr_cannotThrowNonExceptionTypedExpr() { + VariableExpr throwVarExpr = + VariableExpr.builder() + .setVariable(Variable.builder().setName("str").setType(TypeNode.STRING).build()) + .build(); + assertThrows( + IllegalStateException.class, () -> ThrowExpr.builder().setThrowExpr(throwVarExpr).build()); + } + + @Test + public void createThrowExpr_cannotHaveThrowVariableAndMessageExprPresent() { + Expr messageExpr = + MethodInvocationExpr.builder() + .setMethodName("foobar") + .setReturnType(TypeNode.STRING) + .build(); + VariableExpr throwVarExpr = + VariableExpr.builder() + .setVariable( + Variable.builder() + .setName("e") + .setType(TypeNode.withExceptionClazz(RuntimeException.class)) + .build()) + .build(); + assertThrows( + IllegalStateException.class, + () -> ThrowExpr.builder().setThrowExpr(throwVarExpr).setMessageExpr(messageExpr).build()); + } + + @Test + public void createThrowExpr_cannotHaveThrowVariableAndCauseExprPresent() { + VariableExpr throwVarExpr = + VariableExpr.builder() + .setVariable( + Variable.builder() + .setName("e") + .setType(TypeNode.withExceptionClazz(RuntimeException.class)) + .build()) + .build(); + assertThrows( + IllegalStateException.class, + () -> + ThrowExpr.builder() + .setThrowExpr(throwVarExpr) + .setCauseExpr( + NewObjectExpr.builder() + .setType( + TypeNode.withReference(ConcreteReference.withClazz(Throwable.class))) + .build()) + .build()); + } } diff --git a/src/test/java/com/google/api/generator/engine/ast/TryCatchStatementTest.java b/src/test/java/com/google/api/generator/engine/ast/TryCatchStatementTest.java index db406aa9eb..f19722f182 100644 --- a/src/test/java/com/google/api/generator/engine/ast/TryCatchStatementTest.java +++ b/src/test/java/com/google/api/generator/engine/ast/TryCatchStatementTest.java @@ -15,9 +15,11 @@ package com.google.api.generator.engine.ast; import static com.google.common.truth.Truth.assertThat; +import static junit.framework.Assert.assertEquals; import static org.junit.Assert.assertThrows; import java.util.Arrays; +import java.util.Collections; import org.junit.Test; public class TryCatchStatementTest { @@ -32,9 +34,36 @@ public void validTryCatchStatement_simple() { TryCatchStatement tryCatch = TryCatchStatement.builder() .setTryBody(Arrays.asList(ExprStatement.withExpr(createAssignmentExpr()))) - .setCatchVariableExpr(variableExpr) + .addCatch(variableExpr, Collections.emptyList()) .build(); - assertThat(tryCatch.catchVariableExpr()).isEqualTo(variableExpr); + assertEquals(1, tryCatch.catchVariableExprs().size()); + assertThat(tryCatch.catchVariableExprs().get(0)).isEqualTo(variableExpr); + } + + @Test + public void validTryCatchStatement_simpleMultiBlock() { + VariableExpr firstCatchVarExpr = + VariableExpr.builder() + .setVariable( + createVariable("e", TypeNode.withExceptionClazz(IllegalArgumentException.class))) + .setIsDecl(true) + .build(); + VariableExpr secondCatchVarExpr = + VariableExpr.builder() + .setVariable(createVariable("e", TypeNode.withExceptionClazz(RuntimeException.class))) + .setIsDecl(true) + .build(); + + TryCatchStatement tryCatch = + TryCatchStatement.builder() + .setTryBody(Arrays.asList(ExprStatement.withExpr(createAssignmentExpr()))) + .addCatch(firstCatchVarExpr, Collections.emptyList()) + .addCatch(secondCatchVarExpr, Collections.emptyList()) + .build(); + + assertEquals(2, tryCatch.catchVariableExprs().size()); + assertThat(tryCatch.catchVariableExprs().get(0)).isEqualTo(firstCatchVarExpr); + assertThat(tryCatch.catchVariableExprs().get(1)).isEqualTo(secondCatchVarExpr); } @Test @@ -49,9 +78,9 @@ public void validTryCatchStatement_withResources() { TryCatchStatement.builder() .setTryResourceExpr(assignmentExpr) .setTryBody(Arrays.asList(ExprStatement.withExpr(assignmentExpr))) - .setCatchVariableExpr(variableExpr) + .addCatch(variableExpr, Collections.emptyList()) .build(); - assertThat(tryCatch.catchVariableExpr()).isEqualTo(variableExpr); + assertThat(tryCatch.catchVariableExprs().get(0)).isEqualTo(variableExpr); assertThat(tryCatch.tryResourceExpr()).isEqualTo(assignmentExpr); } @@ -67,7 +96,7 @@ public void validTryCatchStatement_sampleCode() { .setTryBody(Arrays.asList(ExprStatement.withExpr(createAssignmentExpr()))) .setIsSampleCode(true) .build(); - assertThat(tryCatch.catchVariableExpr()).isNull(); + assertThat(tryCatch.catchVariableExprs()).isEmpty(); } @Test @@ -78,7 +107,7 @@ public void invalidTryCatchStatement_missingCatchVariable() { VariableExpr.builder().setVariable(createVariable("e", type)).setIsDecl(true).build(); assertThrows( - NullPointerException.class, + IllegalStateException.class, () -> { TryCatchStatement.builder() .setTryBody(Arrays.asList(ExprStatement.withExpr(createAssignmentExpr()))) @@ -99,7 +128,7 @@ public void invalidTryCatchStatement_catchVariableNotDecl() { TryCatchStatement tryCatch = TryCatchStatement.builder() .setTryBody(Arrays.asList(ExprStatement.withExpr(createAssignmentExpr()))) - .setCatchVariableExpr(variableExpr) + .addCatch(variableExpr, Collections.emptyList()) .build(); }); } @@ -117,7 +146,7 @@ public void invalidTryCatchStatement_nonExceptionReference() { TryCatchStatement tryCatch = TryCatchStatement.builder() .setTryBody(Arrays.asList(ExprStatement.withExpr(createAssignmentExpr()))) - .setCatchVariableExpr(variableExpr) + .addCatch(variableExpr, Collections.emptyList()) .build(); }); } diff --git a/src/test/java/com/google/api/generator/engine/writer/ImportWriterVisitorTest.java b/src/test/java/com/google/api/generator/engine/writer/ImportWriterVisitorTest.java index 053ea774d5..6b9d20ff0b 100644 --- a/src/test/java/com/google/api/generator/engine/writer/ImportWriterVisitorTest.java +++ b/src/test/java/com/google/api/generator/engine/writer/ImportWriterVisitorTest.java @@ -449,6 +449,26 @@ public void writeThrowExprImports_basic() { assertEquals("import java.io.IOException;\n\n", writerVisitor.write()); } + @Test + public void writeThrowExprImports_throwExpr() { + Expr exprToThrow = + MethodInvocationExpr.builder() + .setStaticReferenceType( + TypeNode.withReference(ConcreteReference.withClazz(Statement.class))) + .setMethodName("createException") + .setReturnType(TypeNode.withExceptionClazz(Exception.class)) + .build(); + + TypeNode ignoredExceptionType = + TypeNode.withReference(ConcreteReference.withClazz(IOException.class)); + ThrowExpr throwExpr = + ThrowExpr.builder().setType(ignoredExceptionType).setThrowExpr(exprToThrow).build(); + throwExpr.accept(writerVisitor); + assertEquals( + LineFormatter.lines("import com.google.api.generator.engine.ast.Statement;\n\n"), + writerVisitor.write()); + } + @Test public void writeThrowExprImports_messageExpr() { TypeNode npeType = TypeNode.withExceptionClazz(NullPointerException.class); diff --git a/src/test/java/com/google/api/generator/engine/writer/JavaWriterVisitorTest.java b/src/test/java/com/google/api/generator/engine/writer/JavaWriterVisitorTest.java index c07fbd32cf..902f3ee4a8 100644 --- a/src/test/java/com/google/api/generator/engine/writer/JavaWriterVisitorTest.java +++ b/src/test/java/com/google/api/generator/engine/writer/JavaWriterVisitorTest.java @@ -73,6 +73,7 @@ import com.google.common.base.Function; import java.io.IOException; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -1031,6 +1032,21 @@ public void writeThrowExpr_basic() { assertEquals("throw new NullPointerException()", writerVisitor.write()); } + @Test + public void writeThrowExpr_basicThrowExpr() { + Expr exprToThrow = + MethodInvocationExpr.builder() + .setStaticReferenceType( + TypeNode.withReference(ConcreteReference.withClazz(Statement.class))) + .setMethodName("createException") + .setReturnType(TypeNode.withExceptionClazz(Exception.class)) + .build(); + + ThrowExpr throwExpr = ThrowExpr.builder().setThrowExpr(exprToThrow).build(); + throwExpr.accept(writerVisitor); + assertEquals("throw Statement.createException()", writerVisitor.write()); + } + @Test public void writeThrowExpr_basicWithMessage() { TypeNode npeType = @@ -1454,7 +1470,7 @@ public void writeTryCatchStatement_simple() { TryCatchStatement.builder() .setTryBody( Arrays.asList(ExprStatement.withExpr(createAssignmentExpr("x", "3", TypeNode.INT)))) - .setCatchVariableExpr(variableExpr) + .addCatch(variableExpr, Collections.emptyList()) .build(); tryCatch.accept(writerVisitor); @@ -1465,6 +1481,72 @@ public void writeTryCatchStatement_simple() { writerVisitor.write()); } + @Test + public void writeTryCatchStatement_simpleMultiCatch() { + VariableExpr firstCatchVarExpr = + VariableExpr.builder() + .setVariable( + createVariable("e", TypeNode.withExceptionClazz(IllegalArgumentException.class))) + .build(); + VariableExpr secondCatchVarExpr = + VariableExpr.builder() + .setVariable(createVariable("e", TypeNode.withExceptionClazz(RuntimeException.class))) + .build(); + + TryCatchStatement tryCatch = + TryCatchStatement.builder() + .setTryBody( + Arrays.asList(ExprStatement.withExpr(createAssignmentExpr("x", "3", TypeNode.INT)))) + .addCatch( + firstCatchVarExpr.toBuilder().setIsDecl(true).build(), Collections.emptyList()) + .addCatch( + secondCatchVarExpr.toBuilder().setIsDecl(true).build(), Collections.emptyList()) + .build(); + + tryCatch.accept(writerVisitor); + assertEquals( + LineFormatter.lines( + "try {\n", + "int x = 3;\n", + "} catch (IllegalArgumentException e) {\n", + "} catch (RuntimeException e) {\n", + "}\n"), + writerVisitor.write()); + } + + @Test + public void writeTryCatchStatement_simpleMultiCatchOrderMatters() { + VariableExpr firstCatchVarExpr = + VariableExpr.builder() + .setVariable( + createVariable("e", TypeNode.withExceptionClazz(IllegalArgumentException.class))) + .build(); + VariableExpr secondCatchVarExpr = + VariableExpr.builder() + .setVariable(createVariable("e", TypeNode.withExceptionClazz(RuntimeException.class))) + .build(); + + TryCatchStatement tryCatch = + TryCatchStatement.builder() + .setTryBody( + Arrays.asList(ExprStatement.withExpr(createAssignmentExpr("x", "3", TypeNode.INT)))) + .addCatch( + secondCatchVarExpr.toBuilder().setIsDecl(true).build(), Collections.emptyList()) + .addCatch( + firstCatchVarExpr.toBuilder().setIsDecl(true).build(), Collections.emptyList()) + .build(); + + tryCatch.accept(writerVisitor); + assertEquals( + LineFormatter.lines( + "try {\n", + "int x = 3;\n", + "} catch (RuntimeException e) {\n", + "} catch (IllegalArgumentException e) {\n", + "}\n"), + writerVisitor.write()); + } + @Test public void writeTryCatchStatement_withResources() { Reference exceptionReference = ConcreteReference.withClazz(IllegalArgumentException.class); @@ -1477,8 +1559,8 @@ public void writeTryCatchStatement_withResources() { .setTryResourceExpr(createAssignmentExpr("aBool", "false", TypeNode.BOOLEAN)) .setTryBody( Arrays.asList(ExprStatement.withExpr(createAssignmentExpr("y", "4", TypeNode.INT)))) - .setCatchVariableExpr(variableExpr) - .setCatchBody( + .addCatch( + variableExpr, Arrays.asList( ExprStatement.withExpr(createAssignmentExpr("foobar", "123", TypeNode.INT)))) .build(); @@ -1526,8 +1608,8 @@ public void writeTryCatchStatement_sampleCodeWithCatch() { .setTryResourceExpr(createAssignmentExpr("aBool", "false", TypeNode.BOOLEAN)) .setTryBody( Arrays.asList(ExprStatement.withExpr(createAssignmentExpr("y", "4", TypeNode.INT)))) - .setCatchVariableExpr(variableExpr) - .setCatchBody( + .addCatch( + variableExpr, Arrays.asList( ExprStatement.withExpr(createAssignmentExpr("foobar", "123", TypeNode.INT)))) .build(); diff --git a/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/GrpcDeprecatedServiceStub.golden b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/GrpcDeprecatedServiceStub.golden index 431b6688f5..b472790622 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/GrpcDeprecatedServiceStub.golden +++ b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/GrpcDeprecatedServiceStub.golden @@ -125,7 +125,13 @@ public class GrpcDeprecatedServiceStub extends DeprecatedServiceStub { @Override public final void close() { - shutdown(); + try { + backgroundResources.close(); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new IllegalStateException("Failed to close resource", e); + } } @Override diff --git a/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/GrpcEchoStub.golden b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/GrpcEchoStub.golden index d1a4a303bd..940ab7d4c4 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/GrpcEchoStub.golden +++ b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/GrpcEchoStub.golden @@ -341,7 +341,13 @@ public class GrpcEchoStub extends EchoStub { @Override public final void close() { - shutdown(); + try { + backgroundResources.close(); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new IllegalStateException("Failed to close resource", e); + } } @Override diff --git a/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/GrpcPublisherStub.golden b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/GrpcPublisherStub.golden index 9e221ab5a2..84cc56d029 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/GrpcPublisherStub.golden +++ b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/GrpcPublisherStub.golden @@ -430,7 +430,13 @@ public class GrpcPublisherStub extends PublisherStub { @Override public final void close() { - shutdown(); + try { + backgroundResources.close(); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new IllegalStateException("Failed to close resource", e); + } } @Override diff --git a/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/GrpcTestingStub.golden b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/GrpcTestingStub.golden index ed6f22313a..b22b976287 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/GrpcTestingStub.golden +++ b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/GrpcTestingStub.golden @@ -382,7 +382,13 @@ public class GrpcTestingStub extends TestingStub { @Override public final void close() { - shutdown(); + try { + backgroundResources.close(); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new IllegalStateException("Failed to close resource", e); + } } @Override diff --git a/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceStub.golden b/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceStub.golden index 1ddcb3bf39..15b0a124b1 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceStub.golden +++ b/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceStub.golden @@ -484,7 +484,13 @@ public class HttpJsonComplianceStub extends ComplianceStub { @Override public final void close() { - shutdown(); + try { + backgroundResources.close(); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new IllegalStateException("Failed to close resource", e); + } } @Override diff --git a/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/GrpcAssetServiceStub.java b/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/GrpcAssetServiceStub.java index 712d328088..082fb7fa95 100644 --- a/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/GrpcAssetServiceStub.java +++ b/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/GrpcAssetServiceStub.java @@ -598,7 +598,13 @@ public UnaryCallable deleteFeedCallable() { @Override public final void close() { - shutdown(); + try { + backgroundResources.close(); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new IllegalStateException("Failed to close resource", e); + } } @Override diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java index 53a0eb8425..11ebe42475 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java @@ -403,7 +403,13 @@ public UnaryCallable listPagedCallable( @Override public final void close() { - shutdown(); + try { + backgroundResources.close(); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new IllegalStateException("Failed to close resource", e); + } } @Override diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsStub.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsStub.java index 0be8cf4d03..7e3217b1cb 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsStub.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsStub.java @@ -167,7 +167,13 @@ public UnaryCallable getCallable() { @Override public final void close() { - shutdown(); + try { + backgroundResources.close(); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new IllegalStateException("Failed to close resource", e); + } } @Override diff --git a/test/integration/goldens/credentials/com/google/cloud/iam/credentials/v1/stub/GrpcIamCredentialsStub.java b/test/integration/goldens/credentials/com/google/cloud/iam/credentials/v1/stub/GrpcIamCredentialsStub.java index 48731cd53d..39e6e722c0 100644 --- a/test/integration/goldens/credentials/com/google/cloud/iam/credentials/v1/stub/GrpcIamCredentialsStub.java +++ b/test/integration/goldens/credentials/com/google/cloud/iam/credentials/v1/stub/GrpcIamCredentialsStub.java @@ -239,7 +239,13 @@ public UnaryCallable signJwtCallable() { @Override public final void close() { - shutdown(); + try { + backgroundResources.close(); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new IllegalStateException("Failed to close resource", e); + } } @Override diff --git a/test/integration/goldens/iam/com/google/iam/v1/stub/GrpcIAMPolicyStub.java b/test/integration/goldens/iam/com/google/iam/v1/stub/GrpcIAMPolicyStub.java index f40c2bfffe..5b5440bd25 100644 --- a/test/integration/goldens/iam/com/google/iam/v1/stub/GrpcIAMPolicyStub.java +++ b/test/integration/goldens/iam/com/google/iam/v1/stub/GrpcIAMPolicyStub.java @@ -197,7 +197,13 @@ public UnaryCallable getIamPolicyCallable() { @Override public final void close() { - shutdown(); + try { + backgroundResources.close(); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new IllegalStateException("Failed to close resource", e); + } } @Override diff --git a/test/integration/goldens/kms/com/google/cloud/kms/v1/stub/GrpcKeyManagementServiceStub.java b/test/integration/goldens/kms/com/google/cloud/kms/v1/stub/GrpcKeyManagementServiceStub.java index 19065361ed..499771b0f6 100644 --- a/test/integration/goldens/kms/com/google/cloud/kms/v1/stub/GrpcKeyManagementServiceStub.java +++ b/test/integration/goldens/kms/com/google/cloud/kms/v1/stub/GrpcKeyManagementServiceStub.java @@ -1119,7 +1119,13 @@ public UnaryCallable getLocationCallable() { @Override public final void close() { - shutdown(); + try { + backgroundResources.close(); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new IllegalStateException("Failed to close resource", e); + } } @Override diff --git a/test/integration/goldens/library/com/google/cloud/example/library/v1/stub/GrpcLibraryServiceStub.java b/test/integration/goldens/library/com/google/cloud/example/library/v1/stub/GrpcLibraryServiceStub.java index c912a9b7b3..8a5429cefb 100644 --- a/test/integration/goldens/library/com/google/cloud/example/library/v1/stub/GrpcLibraryServiceStub.java +++ b/test/integration/goldens/library/com/google/cloud/example/library/v1/stub/GrpcLibraryServiceStub.java @@ -450,7 +450,13 @@ public UnaryCallable moveBookCallable() { @Override public final void close() { - shutdown(); + try { + backgroundResources.close(); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new IllegalStateException("Failed to close resource", e); + } } @Override diff --git a/test/integration/goldens/logging/com/google/cloud/logging/v2/stub/GrpcConfigServiceV2Stub.java b/test/integration/goldens/logging/com/google/cloud/logging/v2/stub/GrpcConfigServiceV2Stub.java index 91ddb14f6a..e8e5bf647e 100644 --- a/test/integration/goldens/logging/com/google/cloud/logging/v2/stub/GrpcConfigServiceV2Stub.java +++ b/test/integration/goldens/logging/com/google/cloud/logging/v2/stub/GrpcConfigServiceV2Stub.java @@ -889,7 +889,13 @@ public UnaryCallable updateCmekSettings @Override public final void close() { - shutdown(); + try { + backgroundResources.close(); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new IllegalStateException("Failed to close resource", e); + } } @Override diff --git a/test/integration/goldens/logging/com/google/cloud/logging/v2/stub/GrpcLoggingServiceV2Stub.java b/test/integration/goldens/logging/com/google/cloud/logging/v2/stub/GrpcLoggingServiceV2Stub.java index feb0ed3086..80c6b53aea 100644 --- a/test/integration/goldens/logging/com/google/cloud/logging/v2/stub/GrpcLoggingServiceV2Stub.java +++ b/test/integration/goldens/logging/com/google/cloud/logging/v2/stub/GrpcLoggingServiceV2Stub.java @@ -328,7 +328,13 @@ public UnaryCallable listLogsPagedCallab @Override public final void close() { - shutdown(); + try { + backgroundResources.close(); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new IllegalStateException("Failed to close resource", e); + } } @Override diff --git a/test/integration/goldens/logging/com/google/cloud/logging/v2/stub/GrpcMetricsServiceV2Stub.java b/test/integration/goldens/logging/com/google/cloud/logging/v2/stub/GrpcMetricsServiceV2Stub.java index fe15cf6052..6d5eefc13d 100644 --- a/test/integration/goldens/logging/com/google/cloud/logging/v2/stub/GrpcMetricsServiceV2Stub.java +++ b/test/integration/goldens/logging/com/google/cloud/logging/v2/stub/GrpcMetricsServiceV2Stub.java @@ -279,7 +279,13 @@ public UnaryCallable deleteLogMetricCallable() { @Override public final void close() { - shutdown(); + try { + backgroundResources.close(); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new IllegalStateException("Failed to close resource", e); + } } @Override diff --git a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/stub/GrpcPublisherStub.java b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/stub/GrpcPublisherStub.java index 2b5ce28a06..950b722377 100644 --- a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/stub/GrpcPublisherStub.java +++ b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/stub/GrpcPublisherStub.java @@ -549,7 +549,13 @@ public UnaryCallable getIamPolicyCallable() { @Override public final void close() { - shutdown(); + try { + backgroundResources.close(); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new IllegalStateException("Failed to close resource", e); + } } @Override diff --git a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/stub/GrpcSchemaServiceStub.java b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/stub/GrpcSchemaServiceStub.java index 11bac90c7d..0ca41b379b 100644 --- a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/stub/GrpcSchemaServiceStub.java +++ b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/stub/GrpcSchemaServiceStub.java @@ -412,7 +412,13 @@ public UnaryCallable getIamPolicyCallable() { @Override public final void close() { - shutdown(); + try { + backgroundResources.close(); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new IllegalStateException("Failed to close resource", e); + } } @Override diff --git a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/stub/GrpcSubscriberStub.java b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/stub/GrpcSubscriberStub.java index 8580e626f8..878a2ad7d2 100644 --- a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/stub/GrpcSubscriberStub.java +++ b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/stub/GrpcSubscriberStub.java @@ -762,7 +762,13 @@ public UnaryCallable getIamPolicyCallable() { @Override public final void close() { - shutdown(); + try { + backgroundResources.close(); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new IllegalStateException("Failed to close resource", e); + } } @Override diff --git a/test/integration/goldens/redis/com/google/cloud/redis/v1beta1/stub/GrpcCloudRedisStub.java b/test/integration/goldens/redis/com/google/cloud/redis/v1beta1/stub/GrpcCloudRedisStub.java index 24c34f9b6e..4e6c502571 100644 --- a/test/integration/goldens/redis/com/google/cloud/redis/v1beta1/stub/GrpcCloudRedisStub.java +++ b/test/integration/goldens/redis/com/google/cloud/redis/v1beta1/stub/GrpcCloudRedisStub.java @@ -505,7 +505,13 @@ public OperationCallable deleteInstanceOperat @Override public final void close() { - shutdown(); + try { + backgroundResources.close(); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new IllegalStateException("Failed to close resource", e); + } } @Override diff --git a/test/integration/goldens/storage/com/google/storage/v2/stub/GrpcStorageStub.java b/test/integration/goldens/storage/com/google/storage/v2/stub/GrpcStorageStub.java index a0ae53ba0e..3097e32c82 100644 --- a/test/integration/goldens/storage/com/google/storage/v2/stub/GrpcStorageStub.java +++ b/test/integration/goldens/storage/com/google/storage/v2/stub/GrpcStorageStub.java @@ -201,7 +201,13 @@ public ClientStreamingCallable writeObj @Override public final void close() { - shutdown(); + try { + backgroundResources.close(); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new IllegalStateException("Failed to close resource", e); + } } @Override