Skip to content

Commit 459bd0c

Browse files
committed
feat(generator): expose REST composer helpers and add path prefix support
Expose package-private helpers on HttpJsonServiceStubClassComposer and add an overloaded getRequestFormatterExpr that supports path prefixes for reuse by resumable upload REST stubs.
1 parent e0d1fe6 commit 459bd0c

2 files changed

Lines changed: 72 additions & 15 deletions

File tree

sdk-platform-java/gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,15 @@
7979
import java.util.function.Predicate;
8080
import java.util.stream.Collectors;
8181
import org.jspecify.annotations.NullMarked;
82+
import org.jspecify.annotations.Nullable;
8283

8384
@NullMarked
8485
public class HttpJsonServiceStubClassComposer extends AbstractTransportServiceStubClassComposer {
8586
private static final HttpJsonServiceStubClassComposer INSTANCE =
8687
new HttpJsonServiceStubClassComposer();
8788

88-
private static final TypeStore FIXED_REST_TYPESTORE = createStaticTypes();
89-
private static final VariableExpr TYPE_REGISTRY_VAR_EXPR =
89+
static final TypeStore FIXED_REST_TYPESTORE = createStaticTypes();
90+
static final VariableExpr TYPE_REGISTRY_VAR_EXPR =
9091
VariableExpr.builder()
9192
.setVariable(
9293
Variable.builder()
@@ -266,7 +267,7 @@ protected List<MethodDefinition> createGetMethodDescriptorsMethod(
266267
.build());
267268
}
268269

269-
private BiFunction<String, List<Expr>, Function<MethodInvocationExpr, MethodInvocationExpr>>
270+
static BiFunction<String, List<Expr>, Function<MethodInvocationExpr, MethodInvocationExpr>>
270271
getMethodMaker() {
271272
return (mName, argExpr) ->
272273
(m) ->
@@ -277,7 +278,12 @@ protected List<MethodDefinition> createGetMethodDescriptorsMethod(
277278
.build();
278279
}
279280

280-
private List<Expr> getRequestFormatterExpr(Method protoMethod, boolean restNumericEnumsEnabled) {
281+
static List<Expr> getRequestFormatterExpr(Method protoMethod, boolean restNumericEnumsEnabled) {
282+
return getRequestFormatterExpr(protoMethod, restNumericEnumsEnabled, null);
283+
}
284+
285+
static List<Expr> getRequestFormatterExpr(
286+
Method protoMethod, boolean restNumericEnumsEnabled, @Nullable String pathPrefix) {
281287
BiFunction<String, List<Expr>, Function<MethodInvocationExpr, MethodInvocationExpr>>
282288
methodMaker = getMethodMaker();
283289

@@ -296,14 +302,22 @@ private List<Expr> getRequestFormatterExpr(Method protoMethod, boolean restNumer
296302
.setGenerics(TypeNode.STRING.reference(), TypeNode.STRING.reference())
297303
.build());
298304

305+
String pathPattern = protoMethod.httpBindings().lowerCamelPattern();
306+
if (pathPrefix != null) {
307+
String normalizedPrefix = pathPrefix.startsWith("/") ? pathPrefix : "/" + pathPrefix;
308+
if (normalizedPrefix.endsWith("/")) {
309+
normalizedPrefix = normalizedPrefix.substring(0, normalizedPrefix.length() - 1);
310+
}
311+
pathPattern =
312+
normalizedPrefix + (pathPattern.startsWith("/") ? pathPattern : "/" + pathPattern);
313+
}
314+
299315
expr =
300316
methodMaker
301317
.apply(
302318
"setPath",
303319
Arrays.asList(
304-
ValueExpr.withValue(
305-
StringObjectValue.withValue(
306-
protoMethod.httpBindings().lowerCamelPattern())),
320+
ValueExpr.withValue(StringObjectValue.withValue(pathPattern)),
307321
createFieldsExtractorClassInstance(
308322
protoMethod,
309323
extractorVarType,
@@ -318,7 +332,24 @@ private List<Expr> getRequestFormatterExpr(Method protoMethod, boolean restNumer
318332
.apply(
319333
"setAdditionalPaths",
320334
protoMethod.httpBindings().lowerCamelAdditionalPatterns().stream()
321-
.map(a -> ValueExpr.withValue(StringObjectValue.withValue(a)))
335+
.map(
336+
a -> {
337+
String additionalPath = a;
338+
if (pathPrefix != null) {
339+
String normalizedPrefix =
340+
pathPrefix.startsWith("/") ? pathPrefix : "/" + pathPrefix;
341+
if (normalizedPrefix.endsWith("/")) {
342+
normalizedPrefix =
343+
normalizedPrefix.substring(0, normalizedPrefix.length() - 1);
344+
}
345+
additionalPath =
346+
normalizedPrefix
347+
+ (additionalPath.startsWith("/")
348+
? additionalPath
349+
: "/" + additionalPath);
350+
}
351+
return ValueExpr.withValue(StringObjectValue.withValue(additionalPath));
352+
})
322353
.collect(Collectors.toList()))
323354
.apply(expr);
324355
}
@@ -371,7 +402,7 @@ private List<Expr> getRequestFormatterExpr(Method protoMethod, boolean restNumer
371402
return Collections.singletonList(expr);
372403
}
373404

374-
private List<Expr> setResponseParserExpr(Method protoMethod) {
405+
static List<Expr> setResponseParserExpr(Method protoMethod) {
375406
BiFunction<String, List<Expr>, Function<MethodInvocationExpr, MethodInvocationExpr>>
376407
methodMaker = getMethodMaker();
377408

@@ -726,7 +757,7 @@ private List<Expr> setPollingRequestFactoryExpr(
726757
.build());
727758
}
728759

729-
private Expr createBodyFieldsExtractorClassInstance(
760+
private static Expr createBodyFieldsExtractorClassInstance(
730761
Method method,
731762
TypeNode extractorReturnType,
732763
Set<HttpBinding> httpBindingFieldNames,
@@ -839,7 +870,7 @@ private Expr createBodyFieldsExtractorClassInstance(
839870
.build();
840871
}
841872

842-
private Expr createFieldsExtractorClassInstance(
873+
private static Expr createFieldsExtractorClassInstance(
843874
Method method,
844875
TypeNode extractorReturnType,
845876
Set<HttpBinding> httpBindingFieldNames,
@@ -993,7 +1024,7 @@ private Expr createFieldsExtractorClassInstance(
9931024
}
9941025

9951026
@VisibleForTesting
996-
String getBindingFieldMethodName(
1027+
static String getBindingFieldMethodName(
9971028
HttpBinding httpBindingField, int descendantFieldsLengths, int index, String currFieldName) {
9981029
if (index == descendantFieldsLengths - 1) {
9991030
if (httpBindingField.isRepeated()) {
@@ -1006,13 +1037,13 @@ String getBindingFieldMethodName(
10061037
return String.format("get%s", currFieldName);
10071038
}
10081039

1009-
private List<Expr> getHttpMethodTypeExpr(Method protoMethod) {
1040+
static List<Expr> getHttpMethodTypeExpr(Method protoMethod) {
10101041
return Collections.singletonList(
10111042
ValueExpr.withValue(
10121043
StringObjectValue.withValue(protoMethod.httpBindings().httpVerb().toString())));
10131044
}
10141045

1015-
private List<Expr> getMethodTypeExpr(Method protoMethod) {
1046+
static List<Expr> getMethodTypeExpr(Method protoMethod) {
10161047
MethodType methodType;
10171048
switch (protoMethod.stream()) {
10181049
case NONE:
@@ -1042,6 +1073,10 @@ private List<Expr> getMethodTypeExpr(Method protoMethod) {
10421073
return Collections.singletonList(expr);
10431074
}
10441075

1076+
static String getProtoRpcName(Service protoService, Method protoMethod) {
1077+
return INSTANCE.getProtoRpcFullMethodName(protoService, protoMethod);
1078+
}
1079+
10451080
@Override
10461081
protected List<Expr> createOperationsStubInitExpr(
10471082
GapicContext context,
@@ -1365,7 +1400,8 @@ private List<MethodDefinition> createInvalidClassMethods(Service service) {
13651400
.setType(FIXED_TYPESTORE.get("UnsupportedOperationException"))
13661401
.setMessageExpr(
13671402
String.format(
1368-
"Not implemented: %s(). %s transport is not implemented for this method yet.",
1403+
"Not implemented: %s(). %s transport is not implemented for"
1404+
+ " this method yet.",
13691405
callableName, getTransportContext().transport()))
13701406
.build())))
13711407
.build());

sdk-platform-java/gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposerTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@
1919
import com.google.api.CustomHttpPattern;
2020
import com.google.api.Http;
2121
import com.google.api.HttpRule;
22+
import com.google.api.generator.engine.ast.Expr;
2223
import com.google.api.generator.engine.ast.TypeNode;
2324
import com.google.api.generator.engine.writer.JavaWriterVisitor;
2425
import com.google.api.generator.gapic.model.Field;
2526
import com.google.api.generator.gapic.model.GapicClass;
2627
import com.google.api.generator.gapic.model.GapicContext;
2728
import com.google.api.generator.gapic.model.HttpBindings.HttpBinding;
29+
import com.google.api.generator.gapic.model.Method;
2830
import com.google.api.generator.gapic.model.Service;
2931
import com.google.api.generator.test.framework.Assert;
3032
import com.google.api.generator.test.framework.GoldenFileWriter;
@@ -223,4 +225,23 @@ void generateHttpJsonServiceStubClass_clientResourceNameExtractor() {
223225
Assert.assertGoldenClass(this.getClass(), clazz, "HttpJsonResourceNameExtractorStub.golden");
224226
Assert.assertEmptySamples(clazz.samples());
225227
}
228+
229+
@Test
230+
void getRequestFormatterExpr_withPathPrefix_prependsPrefix() {
231+
GapicContext context = RestTestProtoLoader.instance().parseShowcaseResumableUpload();
232+
Service service = context.services().get(0);
233+
Method uploadMethod =
234+
service.methods().stream().filter(Method::isResumableUpload).findFirst().get();
235+
236+
List<Expr> exprs =
237+
HttpJsonServiceStubClassComposer.getRequestFormatterExpr(
238+
uploadMethod, context.restNumericEnumsEnabled(), "/resumable/upload");
239+
240+
JavaWriterVisitor visitor = new JavaWriterVisitor();
241+
for (Expr expr : exprs) {
242+
expr.accept(visitor);
243+
}
244+
String code = visitor.write();
245+
Truth.assertThat(code).contains("/resumable/upload/v1beta1/files:upload");
246+
}
226247
}

0 commit comments

Comments
 (0)