diff --git a/.github/workflows/downstream-native-image.yaml b/.github/workflows/downstream-native-image.yaml new file mode 100644 index 000000000..4a4f947ee --- /dev/null +++ b/.github/workflows/downstream-native-image.yaml @@ -0,0 +1,41 @@ +on: + push: + branches: + - main + pull_request: + +# Keeping this file separate as the dependencies check would use more +# repositories than needed this downstream check for GraalVM native image +# compilation. +name: downstream +jobs: + # GraalVM job ensures the compatibility of GraaVM version + graalvm: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + graalvm: [22.1.0, 22.0.0.2, 21.3.2] + java: [11, 17] + repo: + # GAPIC library that doesn't use a real GCP project in integration tests + - orgpolicy + steps: + - uses: actions/checkout@v2 + - uses: stCarolas/setup-maven@v4 + with: + maven-version: 3.8.1 + - uses: ayltai/setup-graalvm@v1 + with: + java-version: ${{matrix.java}} + # When a new version of native-maven-plugin fails to run in a downstream + # library, it's likely to be an incompatibility with the GraalVM version. + # In that case, you need to upgrade the Docker container used in the + # tests in the downstream repositories (not just this value below). + # Example: https://github.com/googleapis/testing-infra-docker/pull/195 + graalvm-version: ${{matrix.graalvm}} + native-image: true + - run: java -version + - run: sudo apt-get update -y + - run: sudo apt-get install libxml2-utils + - run: .kokoro/downstream-client-library-check.sh ${{matrix.repo}} graalvm \ No newline at end of file diff --git a/.github/workflows/downstream.yaml b/.github/workflows/downstream.yaml index b521e571d..45e45fa25 100644 --- a/.github/workflows/downstream.yaml +++ b/.github/workflows/downstream.yaml @@ -11,7 +11,7 @@ jobs: strategy: fail-fast: false matrix: - java: [8] + java: [11] repo: # This list needs to be updated manually until an automated solution is in place. - accessapproval @@ -141,4 +141,4 @@ jobs: - run: java -version - run: sudo apt-get update -y - run: sudo apt-get install libxml2-utils - - run: .kokoro/downstream-client-library-check.sh ${{matrix.repo}} + - run: .kokoro/downstream-client-library-check.sh ${{matrix.repo}} test diff --git a/.kokoro/downstream-client-library-check.sh b/.kokoro/downstream-client-library-check.sh index 51c23d1c0..7916e1c08 100755 --- a/.kokoro/downstream-client-library-check.sh +++ b/.kokoro/downstream-client-library-check.sh @@ -18,6 +18,9 @@ set -eo pipefail set -x CLIENT_LIBRARY=$1 + +# Example JOB_TYPE: "test" or "graalvm" +export JOB_TYPE=$2 ## Get the directory of the build script scriptDir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")" ## cd to the parent directory, i.e. the root of the git repo @@ -86,7 +89,9 @@ if [[ $CLIENT_LIBRARY == "bigtable" ]]; then popd fi -mvn verify install -B -V -ntp -fae \ --Dmaven.javadoc.skip=true \ --Dgcloud.download.skip=true \ --Denforcer.skip=true +echo "Modification on the shared dependencies BOM:" +git diff +echo + +# This reads the JOB_TYPE environmental variable ("test" or "graalvm") +.kokoro/build.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index e5728e152..d0ac384f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## [2.18.0](https://github.com/googleapis/gax-java/compare/v2.17.0...v2.18.0) (2022-05-18) + + +### Features + +* [REGAPIC] Add support for additional bindings ([#1680](https://github.com/googleapis/gax-java/issues/1680)) ([59b3699](https://github.com/googleapis/gax-java/commit/59b3699b6acbc98c55dc043bf8665b457a0615a9)) +* upgrade graal-sdk to 22.1.0 ([#1683](https://github.com/googleapis/gax-java/issues/1683)) ([46f899d](https://github.com/googleapis/gax-java/commit/46f899de06e60a792f5a6c1dc617673f0f180c00)) + + +### Bug Fixes + +* **java:** remove conflicting reflection configuration to address UnsupportedFeatureException with GraalVM 22.1.0 ([#1682](https://github.com/googleapis/gax-java/issues/1682)) ([97c6c8b](https://github.com/googleapis/gax-java/commit/97c6c8bfa0d5397e30d3699e92f823e09ee283e6)) +* remove svm dependency ([#1679](https://github.com/googleapis/gax-java/issues/1679)) ([c1b88e3](https://github.com/googleapis/gax-java/commit/c1b88e3788ab866bcc1ba3db94c2998198a0b35e)) + + +### Dependencies + +* update dependency com.google.api:api-common to 2.2.0 ([#1685](https://github.com/googleapis/gax-java/issues/1685)) ([a5a316b](https://github.com/googleapis/gax-java/commit/a5a316bde322733eb5a80093206eb12b36945580)) + ## [2.17.0](https://github.com/googleapis/gax-java/compare/v2.16.0...v2.17.0) (2022-05-10) diff --git a/build.gradle b/build.gradle index 8d2e06d7e..05cabe4a1 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,7 @@ plugins { } // TODO: Populate this from dependencies.properties version property (for proper Gradle-Bazel sync) -project.version = "2.17.0" // {x-version-update:gax:current} +project.version = "2.18.0" // {x-version-update:gax:current} allprojects { group = 'com.google.api' diff --git a/dependencies.properties b/dependencies.properties index 5ce365af1..fbc282273 100644 --- a/dependencies.properties +++ b/dependencies.properties @@ -8,16 +8,16 @@ # Versions of oneself # {x-version-update-start:gax:current} -version.gax=2.17.0 +version.gax=2.18.0 # {x-version-update-end} # {x-version-update-start:gax:current} -version.gax_grpc=2.17.0 +version.gax_grpc=2.18.0 # {x-version-update-end} # {x-version-update-start:gax:current} -version.gax_bom=2.17.0 +version.gax_bom=2.18.0 # {x-version-update-end} # {x-version-update-start:gax-httpjson:current} -version.gax_httpjson=0.102.0 +version.gax_httpjson=0.103.0 # {x-version-update-end} # Versions for dependencies which actual artifacts differ between Bazel and Gradle. @@ -62,16 +62,15 @@ maven.com_google_errorprone_error_prone_annotations=com.google.errorprone:error_ maven.com_google_j2objc_j2objc_annotations=com.google.j2objc:j2objc-annotations:1.3 maven.com_google_auto_value_auto_value=com.google.auto.value:auto-value:1.9 maven.com_google_auto_value_auto_value_annotations=com.google.auto.value:auto-value-annotations:1.9 -maven.com_google_api_api_common=com.google.api:api-common:2.1.5 +maven.com_google_api_api_common=com.google.api:api-common:2.2.0 maven.org_threeten_threetenbp=org.threeten:threetenbp:1.5.0 -maven.com_google_api_grpc_grpc_google_iam_v1=com.google.api.grpc:grpc-google-iam-v1:1.0.9 -maven.com_google_api_grpc_proto_google_iam_v1=com.google.api.grpc:proto-google-iam-v1:1.0.9 +maven.com_google_api_grpc_grpc_google_iam_v1=com.google.api.grpc:grpc-google-iam-v1:1.3.4 +maven.com_google_api_grpc_proto_google_iam_v1=com.google.api.grpc:proto-google-iam-v1:1.3.4 maven.com_google_http_client_google_http_client=com.google.http-client:google-http-client:1.41.5 maven.com_google_http_client_google_http_client_gson=com.google.http-client:google-http-client-gson:1.41.5 maven.org_codehaus_mojo_animal_sniffer_annotations=org.codehaus.mojo:animal-sniffer-annotations:1.18 maven.javax_annotation_javax_annotation_api=javax.annotation:javax.annotation-api:1.3.2 -maven.org_graalvm_nativeimage_svm=org.graalvm.nativeimage:svm:22.0.0.2 -maven.org_graalvm_sdk=org.graalvm.sdk:graal-sdk:21.3.2 +maven.org_graalvm_sdk=org.graalvm.sdk:graal-sdk:22.1.0 # Testing maven artifacts maven.junit_junit=junit:junit:4.13.2 diff --git a/gax-bom/build.gradle b/gax-bom/build.gradle index c99f109fb..07d5b5e8a 100644 --- a/gax-bom/build.gradle +++ b/gax-bom/build.gradle @@ -5,7 +5,7 @@ plugins { archivesBaseName = 'gax-bom' -project.version = "2.17.0" // {x-version-update:gax-bom:current} +project.version = "2.18.0" // {x-version-update:gax-bom:current} def mavenJavaDir = "$buildDir/publications/mavenJava" def mavenJavaBomOutputFile = file(mavenJavaDir + '/pom-default.xml') diff --git a/gax-bom/pom.xml b/gax-bom/pom.xml index f5b7eb41e..f4fda7366 100644 --- a/gax-bom/pom.xml +++ b/gax-bom/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.api gax-bom - 2.17.0 + 2.18.0 pom GAX (Google Api eXtensions) for Java Google Api eXtensions for Java @@ -33,34 +33,34 @@ com.google.api gax - 2.17.0 + 2.18.0 com.google.api gax - 2.17.0 + 2.18.0 testlib com.google.api gax-grpc - 2.17.0 + 2.18.0 com.google.api gax-grpc - 2.17.0 + 2.18.0 testlib com.google.api gax-httpjson - 0.102.0 + 0.103.0 com.google.api gax-httpjson - 0.102.0 + 0.103.0 testlib diff --git a/gax-grpc/BUILD.bazel b/gax-grpc/BUILD.bazel index 5ae856c4f..f1dfe02fc 100644 --- a/gax-grpc/BUILD.bazel +++ b/gax-grpc/BUILD.bazel @@ -31,7 +31,6 @@ _COMPILE_DEPS = [ "@io_netty_netty_tcnative_boringssl_static//jar", "@javax_annotation_javax_annotation_api//jar", "//gax:gax", - "@org_graalvm_nativeimage_svm//jar", "@org_graalvm_sdk//jar" ] diff --git a/gax-grpc/build.gradle b/gax-grpc/build.gradle index b31066aff..b15d901b2 100644 --- a/gax-grpc/build.gradle +++ b/gax-grpc/build.gradle @@ -1,7 +1,7 @@ archivesBaseName = 'gax-grpc' // TODO: Populate this from dependencies.properties version property (for proper Gradle-Bazel sync) -project.version = "2.17.0" // {x-version-update:gax-grpc:current} +project.version = "2.18.0" // {x-version-update:gax-grpc:current} dependencies { api(project(':gax'), @@ -23,8 +23,7 @@ dependencies { runtimeOnly libraries['maven.io_grpc_grpc_googleapis'] compileOnly(libraries['maven.com_google_auto_value_auto_value'], - libraries['maven.org_graalvm_sdk'], - libraries['maven.org_graalvm_nativeimage_svm']) + libraries['maven.org_graalvm_sdk']) testImplementation( project(':gax').sourceSets.test.output, libraries['maven.junit_junit'], diff --git a/gax-grpc/src/main/java/com/google/api/gax/grpc/nativeimage/GrpcNettyFeature.java b/gax-grpc/src/main/java/com/google/api/gax/grpc/nativeimage/GrpcNettyFeature.java index 62ddd609b..c2cf0a28d 100644 --- a/gax-grpc/src/main/java/com/google/api/gax/grpc/nativeimage/GrpcNettyFeature.java +++ b/gax-grpc/src/main/java/com/google/api/gax/grpc/nativeimage/GrpcNettyFeature.java @@ -124,7 +124,5 @@ private static void loadMiscClasses(BeforeAnalysisAccess access) { registerClassForReflection(access, "com.google.api.FieldBehavior"); registerForUnsafeFieldAccess(access, "javax.net.ssl.SSLContext", "contextSpi"); - registerClassForReflection(access, "java.lang.management.ManagementFactory"); - registerClassForReflection(access, "java.lang.management.RuntimeMXBean"); } } diff --git a/gax-grpc/src/main/java/com/google/api/gax/grpc/nativeimage/substitutions/NettyInternalLoggerFactorySubstitutions.java b/gax-grpc/src/main/java/com/google/api/gax/grpc/nativeimage/substitutions/NettyInternalLoggerFactorySubstitutions.java deleted file mode 100644 index b81a0c171..000000000 --- a/gax-grpc/src/main/java/com/google/api/gax/grpc/nativeimage/substitutions/NettyInternalLoggerFactorySubstitutions.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google LLC nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package com.google.api.gax.grpc.nativeimage.substitutions; - -import com.oracle.svm.core.annotate.Substitute; -import com.oracle.svm.core.annotate.TargetClass; -import io.grpc.netty.shaded.io.netty.util.internal.logging.InternalLoggerFactory; -import io.grpc.netty.shaded.io.netty.util.internal.logging.JdkLoggerFactory; -import java.util.function.BooleanSupplier; - -/** - * Substitutions for {@link InternalLoggerFactory} which are needed to avoid dynamic loading of - * logging library. - */ -@TargetClass( - className = "io.grpc.netty.shaded.io.netty.util.internal.logging.InternalLoggerFactory", - onlyWith = NettyInternalLoggerFactorySubstitutions.OnlyIfInClassPath.class) -final class NettyInternalLoggerFactorySubstitutions { - - private NettyInternalLoggerFactorySubstitutions() {} - - @Substitute - private static InternalLoggerFactory newDefaultFactory(String name) { - return JdkLoggerFactory.INSTANCE; - } - - static class OnlyIfInClassPath implements BooleanSupplier { - - @Override - public boolean getAsBoolean() { - try { - // Note: Set initialize = false to avoid initializing the class when looking it up. - Class.forName( - "io.grpc.netty.shaded.io.netty.util.internal.logging.InternalLoggerFactory", - false, - Thread.currentThread().getContextClassLoader()); - return true; - } catch (ClassNotFoundException e) { - return false; - } - } - } -} diff --git a/gax-grpc/src/main/resources/META-INF/native-image/com.google.api/gax-grpc/native-image.properties b/gax-grpc/src/main/resources/META-INF/native-image/com.google.api/gax-grpc/native-image.properties index 33ea6695b..116da7f46 100644 --- a/gax-grpc/src/main/resources/META-INF/native-image/com.google.api/gax-grpc/native-image.properties +++ b/gax-grpc/src/main/resources/META-INF/native-image/com.google.api/gax-grpc/native-image.properties @@ -3,6 +3,8 @@ Args = --initialize-at-run-time=io.grpc.netty.shaded.io.netty.handler.ssl.OpenSs io.grpc.netty.shaded.io.netty.internal.tcnative.CertificateVerifier,\ io.grpc.netty.shaded.io.netty.internal.tcnative.SSLPrivateKeyMethod,\ io.grpc.netty.shaded.io.netty.internal.tcnative.AsyncSSLPrivateKeyMethod,\ + io.grpc.netty.shaded.io.netty.util.internal.logging.Slf4JLoggerFactory,\ + io.grpc.netty.shaded.io.netty.util.internal.logging.Log4JLogger,\ io.grpc.netty.shaded.io.grpc.netty,\ io.grpc.netty.shaded.io.netty.channel.epoll,\ io.grpc.netty.shaded.io.netty.channel.unix,\ diff --git a/gax-httpjson/build.gradle b/gax-httpjson/build.gradle index d2e931b34..4c62ef38c 100644 --- a/gax-httpjson/build.gradle +++ b/gax-httpjson/build.gradle @@ -1,7 +1,7 @@ archivesBaseName = 'gax-httpjson' // TODO: Populate this from dependencies.properties version property (for proper Gradle-Bazel sync) -project.version = "0.102.0" // {x-version-update:gax-httpjson:current} +project.version = "0.103.0" // {x-version-update:gax-httpjson:current} dependencies { api(project(':gax'), diff --git a/gax-httpjson/src/main/java/com/google/api/gax/httpjson/HttpRequestFormatter.java b/gax-httpjson/src/main/java/com/google/api/gax/httpjson/HttpRequestFormatter.java index 3d42b313d..a60bf08e9 100644 --- a/gax-httpjson/src/main/java/com/google/api/gax/httpjson/HttpRequestFormatter.java +++ b/gax-httpjson/src/main/java/com/google/api/gax/httpjson/HttpRequestFormatter.java @@ -29,7 +29,9 @@ */ package com.google.api.gax.httpjson; +import com.google.api.core.BetaApi; import com.google.api.pathtemplate.PathTemplate; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -48,4 +50,10 @@ public interface HttpRequestFormatter { /** Path template for endpoint URL path. */ PathTemplate getPathTemplate(); + + /** Additional (alternative) path templates for endpoint URL path. */ + @BetaApi + default List getAdditionalPathTemplates() { + return Collections.emptyList(); + } } diff --git a/gax-httpjson/src/main/java/com/google/api/gax/httpjson/ProtoMessageRequestFormatter.java b/gax-httpjson/src/main/java/com/google/api/gax/httpjson/ProtoMessageRequestFormatter.java index f0d31ac07..f04a16edb 100644 --- a/gax-httpjson/src/main/java/com/google/api/gax/httpjson/ProtoMessageRequestFormatter.java +++ b/gax-httpjson/src/main/java/com/google/api/gax/httpjson/ProtoMessageRequestFormatter.java @@ -29,11 +29,14 @@ */ package com.google.api.gax.httpjson; +import com.google.api.core.BetaApi; import com.google.api.core.InternalApi; import com.google.api.pathtemplate.PathTemplate; import com.google.protobuf.Message; +import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; /** Creates parts of a HTTP request from a protobuf message. */ public class ProtoMessageRequestFormatter @@ -47,28 +50,35 @@ public class ProtoMessageRequestFormatter private final String rawPath; private final PathTemplate pathTemplate; private final FieldsExtractor> pathVarsExtractor; + private final List additionalRawPaths; + private final List additionalPathTemplates; private ProtoMessageRequestFormatter( FieldsExtractor requestBodyExtractor, FieldsExtractor>> queryParamsExtractor, String rawPath, PathTemplate pathTemplate, - FieldsExtractor> pathVarsExtractor) { + FieldsExtractor> pathVarsExtractor, + List additionalRawPaths, + List additionalPathTemplates) { this.requestBodyExtractor = requestBodyExtractor; this.queryParamsExtractor = queryParamsExtractor; this.rawPath = rawPath; this.pathTemplate = pathTemplate; this.pathVarsExtractor = pathVarsExtractor; + this.additionalRawPaths = additionalRawPaths; + this.additionalPathTemplates = additionalPathTemplates; } public static ProtoMessageRequestFormatter.Builder newBuilder() { - return new Builder<>(); + return new Builder().setAdditionalPaths(); } public Builder toBuilder() { return new Builder() .setPath(rawPath, pathVarsExtractor) + .setAdditionalPaths(additionalRawPaths.toArray(new String[] {})) .setQueryParamsExtractor(queryParamsExtractor) .setRequestBodyExtractor(requestBodyExtractor); } @@ -91,6 +101,12 @@ public String getPath(RequestT apiMessage) { return pathTemplate.instantiate(pathVarsExtractor.extract(apiMessage)); } + @BetaApi + @Override + public List getAdditionalPathTemplates() { + return additionalPathTemplates; + } + /* {@inheritDoc} */ @Override public PathTemplate getPathTemplate() { @@ -104,6 +120,7 @@ public static class Builder { private FieldsExtractor>> queryParamsExtractor; private String rawPath; private FieldsExtractor> pathVarsExtractor; + private List rawAdditionalPaths; public Builder setRequestBodyExtractor( FieldsExtractor requestBodyExtractor) { @@ -124,6 +141,12 @@ public Builder setPath( return this; } + @BetaApi + public Builder setAdditionalPaths(String... rawAdditionalPaths) { + this.rawAdditionalPaths = Arrays.asList(rawAdditionalPaths); + return this; + } + @InternalApi public Builder updateRawPath(String target, String replacement) { this.rawPath = this.rawPath.replace(target, replacement); @@ -136,7 +159,9 @@ public ProtoMessageRequestFormatter build() { queryParamsExtractor, rawPath, PathTemplate.create(rawPath), - pathVarsExtractor); + pathVarsExtractor, + rawAdditionalPaths, + rawAdditionalPaths.stream().map(PathTemplate::create).collect(Collectors.toList())); } } } diff --git a/gax-httpjson/src/test/java/com/google/api/gax/httpjson/HttpJsonDirectCallableTest.java b/gax-httpjson/src/test/java/com/google/api/gax/httpjson/HttpJsonDirectCallableTest.java index 310f13e4a..ca3e8893e 100644 --- a/gax-httpjson/src/test/java/com/google/api/gax/httpjson/HttpJsonDirectCallableTest.java +++ b/gax-httpjson/src/test/java/com/google/api/gax/httpjson/HttpJsonDirectCallableTest.java @@ -65,13 +65,14 @@ public class HttpJsonDirectCallableTest { .setRequestFormatter( ProtoMessageRequestFormatter.newBuilder() .setPath( - "/fake/v1/name/{name}", + "/fake/v1/name/{name=bob/*}", request -> { Map fields = new HashMap<>(); ProtoRestSerializer serializer = ProtoRestSerializer.create(); serializer.putPathParam(fields, "name", request.getName()); return fields; }) + .setAdditionalPaths("/fake/v1/name/{name=john/*}") .setQueryParamsExtractor( request -> { Map> fields = new HashMap<>(); @@ -212,7 +213,7 @@ public void testErrorNullContentFailedResponse() throws InterruptedException { private Field createTestMessage() { return Field.newBuilder() // "echo" service - .setName("imTheBestField") + .setName("john/imTheBestField") .setNumber(2) .setCardinality(Cardinality.CARDINALITY_OPTIONAL) .setDefaultValue("blah") diff --git a/gax-httpjson/src/test/java/com/google/api/gax/httpjson/ProtoMessageRequestFormatterTest.java b/gax-httpjson/src/test/java/com/google/api/gax/httpjson/ProtoMessageRequestFormatterTest.java index 69b96065d..8a8c0ac66 100644 --- a/gax-httpjson/src/test/java/com/google/api/gax/httpjson/ProtoMessageRequestFormatterTest.java +++ b/gax-httpjson/src/test/java/com/google/api/gax/httpjson/ProtoMessageRequestFormatterTest.java @@ -44,7 +44,7 @@ public class ProtoMessageRequestFormatterTest { private Field field; - private HttpRequestFormatter formatter; + private ProtoMessageRequestFormatter formatter; @Before public void setUp() { @@ -60,36 +60,28 @@ public void setUp() { formatter = ProtoMessageRequestFormatter.newBuilder() .setPath( - "/api/v1/names/{name}/aggregated", - new FieldsExtractor>() { - @Override - public Map extract(Field request) { - Map fields = new HashMap<>(); - ProtoRestSerializer serializer = ProtoRestSerializer.create(); - serializer.putPathParam(fields, "name", request.getName()); - serializer.putPathParam(fields, "kindValue", request.getKindValue()); - return fields; - } + "/api/v1/names/{name=field_name1/**}/aggregated", + request -> { + Map fields = new HashMap<>(); + ProtoRestSerializer serializer = ProtoRestSerializer.create(); + serializer.putPathParam(fields, "name", request.getName()); + serializer.putPathParam(fields, "kindValue", request.getKindValue()); + return fields; }) .setQueryParamsExtractor( - new FieldsExtractor>>() { - @Override - public Map> extract(Field request) { - Map> fields = new HashMap<>(); - ProtoRestSerializer serializer = ProtoRestSerializer.create(); - serializer.putQueryParam(fields, "number", request.getNumber()); - serializer.putQueryParam(fields, "typeUrl", request.getTypeUrl()); - return fields; - } + request -> { + Map> fields = new HashMap<>(); + ProtoRestSerializer serializer = ProtoRestSerializer.create(); + serializer.putQueryParam(fields, "number", request.getNumber()); + serializer.putQueryParam(fields, "typeUrl", request.getTypeUrl()); + return fields; }) .setRequestBodyExtractor( - new FieldsExtractor() { - @Override - public String extract(Field request) { - ProtoRestSerializer serializer = ProtoRestSerializer.create(); - return serializer.toBody("field", request); - } + request -> { + ProtoRestSerializer serializer = ProtoRestSerializer.create(); + return serializer.toBody("field", request); }) + .setAdditionalPaths("/api/v1/names/{name=field_name1/**}/hello") .build(); } @@ -100,6 +92,12 @@ public void getQueryParamNames() { expected.put("number", Arrays.asList("2")); expected.put("typeUrl", Arrays.asList("")); Truth.assertThat(queryParamNames).isEqualTo(expected); + + // Test toBuilder() case + queryParamNames = formatter.toBuilder().build().getQueryParamNames(field); + expected.put("number", Arrays.asList("2")); + expected.put("typeUrl", Arrays.asList("")); + Truth.assertThat(queryParamNames).isEqualTo(expected); } @Test @@ -117,12 +115,20 @@ public void getRequestBody() { + " }]\n" + "}"; Truth.assertThat(bodyJson).isEqualTo(expectedBodyJson); + + // Test toBuilder() case + formatter.toBuilder().build().getRequestBody(field); + Truth.assertThat(bodyJson).isEqualTo(expectedBodyJson); } @Test public void getPath() { String path = formatter.getPath(field); Truth.assertThat(path).isEqualTo("api/v1/names/field_name1/aggregated"); + + // Test toBuilder() case + path = formatter.toBuilder().build().getPath(field); + Truth.assertThat(path).isEqualTo("api/v1/names/field_name1/aggregated"); } @Test @@ -130,5 +136,40 @@ public void getPathTemplate() { String path = formatter.getPathTemplate().instantiate(Collections.singletonMap("name", "field_name1")); Truth.assertThat(path).isEqualTo("api/v1/names/field_name1/aggregated"); + + // Test toBuilder() case + path = + formatter + .toBuilder() + .build() + .getPathTemplate() + .instantiate(Collections.singletonMap("name", "field_name1")); + Truth.assertThat(path).isEqualTo("api/v1/names/field_name1/aggregated"); + } + + @Test + public void getPathTemplates() { + String path = + formatter + .getAdditionalPathTemplates() + .get(0) + .instantiate(Collections.singletonMap("name", "field_name1")); + Truth.assertThat(path).isEqualTo("api/v1/names/field_name1/hello"); + + // Test toBuilder() case + path = + formatter + .toBuilder() + .build() + .getAdditionalPathTemplates() + .get(0) + .instantiate(Collections.singletonMap("name", "field_name1")); + Truth.assertThat(path).isEqualTo("api/v1/names/field_name1/hello"); + } + + @Test + public void updateRawPath() { + String path = formatter.toBuilder().updateRawPath("/v1/", "/v1beta1/").build().getPath(field); + Truth.assertThat(path).isEqualTo("api/v1beta1/names/field_name1/aggregated"); } } diff --git a/gax-httpjson/src/test/java/com/google/api/gax/httpjson/testing/MockHttpService.java b/gax-httpjson/src/test/java/com/google/api/gax/httpjson/testing/MockHttpService.java index 3a4d81ceb..b2ebee14d 100644 --- a/gax-httpjson/src/test/java/com/google/api/gax/httpjson/testing/MockHttpService.java +++ b/gax-httpjson/src/test/java/com/google/api/gax/httpjson/testing/MockHttpService.java @@ -208,8 +208,11 @@ public MockLowLevelHttpResponse getHttpResponse(String httpMethod, String fullTa } PathTemplate pathTemplate = methodDescriptor.getRequestFormatter().getPathTemplate(); - // Server figures out which RPC method is called based on the endpoint path pattern. - if (!pathTemplate.matches(relativePath)) { + List additionalPathTemplates = + methodDescriptor.getRequestFormatter().getAdditionalPathTemplates(); + // Server figures out which RPC method is called based on the endpoint path pattern(s). + if (!pathTemplate.matches(relativePath) + && additionalPathTemplates.stream().noneMatch(pt -> pt.matches(relativePath))) { continue; } diff --git a/gax/BUILD.bazel b/gax/BUILD.bazel index ede88dee4..0152f2503 100644 --- a/gax/BUILD.bazel +++ b/gax/BUILD.bazel @@ -26,7 +26,6 @@ _COMPILE_DEPS = [ "@com_google_code_gson_gson//jar", "@com_google_guava_failureaccess//jar", "@javax_annotation_javax_annotation_api//jar", - "@org_graalvm_nativeimage_svm//jar", "@org_graalvm_sdk//jar" ] diff --git a/gax/build.gradle b/gax/build.gradle index c8fb03548..ce55a2829 100644 --- a/gax/build.gradle +++ b/gax/build.gradle @@ -1,7 +1,7 @@ archivesBaseName = "gax" // TODO: Populate this from dependencies.properties version property (for proper Gradle-Bazel sync) -project.version = "2.17.0" // {x-version-update:gax:current} +project.version = "2.18.0" // {x-version-update:gax:current} dependencies { api(libraries['maven.com_google_api_api_common'], @@ -15,13 +15,13 @@ dependencies { libraries['maven.io_opencensus_opencensus_api']) compileOnly(libraries['maven.com_google_auto_value_auto_value'], - libraries['maven.org_graalvm_sdk'], - libraries['maven.org_graalvm_nativeimage_svm']) + libraries['maven.org_graalvm_sdk']) testImplementation(libraries['maven.junit_junit'], libraries['maven.org_mockito_mockito_core'], libraries['maven.com_google_truth_truth'], - libraries['maven.com_google_auto_value_auto_value']) + libraries['maven.com_google_auto_value_auto_value'], + libraries['maven.org_graalvm_sdk']) annotationProcessor libraries['maven.com_google_auto_value_auto_value'] testAnnotationProcessor libraries['maven.com_google_auto_value_auto_value'] diff --git a/gax/src/main/java/com/google/api/gax/core/GaxProperties.java b/gax/src/main/java/com/google/api/gax/core/GaxProperties.java index 5d3bf40e8..483cbe9c8 100644 --- a/gax/src/main/java/com/google/api/gax/core/GaxProperties.java +++ b/gax/src/main/java/com/google/api/gax/core/GaxProperties.java @@ -29,6 +29,9 @@ */ package com.google.api.gax.core; +import static org.graalvm.nativeimage.ImageInfo.PROPERTY_IMAGE_CODE_KEY; +import static org.graalvm.nativeimage.ImageInfo.PROPERTY_IMAGE_CODE_VALUE_RUNTIME; + import com.google.api.core.InternalApi; import java.io.IOException; import java.io.InputStream; @@ -81,6 +84,12 @@ public static String getLibraryVersion(Class libraryClass, String propertyNam /** Returns the version of the running JVM */ public static String getJavaVersion() { + // When running the application as a native image, append `-graalvm` to the + // version. + String imageCode = System.getProperty(PROPERTY_IMAGE_CODE_KEY); + if (imageCode != null && imageCode.equals(PROPERTY_IMAGE_CODE_VALUE_RUNTIME)) { + return System.getProperty("java.version") + "-graalvm"; + } return JAVA_VERSION; } diff --git a/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java b/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java index 222f58264..baa4bac92 100644 --- a/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java +++ b/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java @@ -32,10 +32,7 @@ import static com.google.api.gax.nativeimage.NativeImageUtils.registerClassForReflection; -import com.oracle.svm.core.configure.ResourcesRegistry; -import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.hosted.Feature; -import org.graalvm.nativeimage.impl.ConfigurationCondition; /** Configures Native Image settings for the Google JSON Client. */ final class GoogleJsonClientFeature implements Feature { @@ -69,17 +66,6 @@ private void loadApiClient(BeforeAnalysisAccess access) { access.registerSubtypeReachabilityHandler( (duringAccess, subtype) -> registerClassForReflection(access, subtype.getName()), access.findClassByName(GOOGLE_API_CLIENT_REQUEST_CLASS)); - - // Resources - ResourcesRegistry resourcesRegistry = ImageSingletons.lookup(ResourcesRegistry.class); - resourcesRegistry.addResources( - ConfigurationCondition.alwaysTrue(), - "\\Qcom/google/api/client/googleapis/google-api-client.properties\\E"); - resourcesRegistry.addResources( - ConfigurationCondition.alwaysTrue(), "\\Qcom/google/api/client/googleapis/google.p12\\E"); - resourcesRegistry.addResources( - ConfigurationCondition.alwaysTrue(), - "\\Qcom/google/api/client/http/google-http-client.properties\\E"); } } diff --git a/gax/src/main/java/com/google/api/gax/nativeimage/substitutions/ApiClientVersionSubstitutions.java b/gax/src/main/java/com/google/api/gax/nativeimage/substitutions/ApiClientVersionSubstitutions.java deleted file mode 100644 index c054bf03d..000000000 --- a/gax/src/main/java/com/google/api/gax/nativeimage/substitutions/ApiClientVersionSubstitutions.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google LLC nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package com.google.api.gax.nativeimage.substitutions; - -import com.oracle.svm.core.annotate.Alias; -import com.oracle.svm.core.annotate.Substitute; -import com.oracle.svm.core.annotate.TargetClass; -import java.util.function.BooleanSupplier; - -/** Substitution for setting Java version correctly in the Google Java Http Client. */ -@TargetClass( - className = - "com.google.api.client.googleapis.services.AbstractGoogleClientRequest$ApiClientVersion", - onlyWith = ApiClientVersionSubstitutions.OnlyIfInClassPath.class) -final class ApiClientVersionSubstitutions { - - @Alias private String versionString; - - @Substitute - public String toString() { - String[] tokens = versionString.split(" "); - - if (tokens.length > 0 && tokens[0].startsWith("gl-java")) { - tokens[0] += "-graalvm"; - return String.join(" ", tokens); - } else { - return versionString; - } - } - - private ApiClientVersionSubstitutions() {} - - static class OnlyIfInClassPath implements BooleanSupplier { - - @Override - public boolean getAsBoolean() { - try { - // Note: Set initialize = false to avoid initializing the class when looking it up. - Class.forName( - "com.google.api.client.googleapis.services." - + "AbstractGoogleClientRequest$ApiClientVersion", - false, - Thread.currentThread().getContextClassLoader()); - return true; - } catch (ClassNotFoundException e) { - return false; - } - } - } -} diff --git a/gax/src/main/java/com/google/api/gax/nativeimage/substitutions/GaxPropertiesSubstitutions.java b/gax/src/main/java/com/google/api/gax/nativeimage/substitutions/GaxPropertiesSubstitutions.java deleted file mode 100644 index 611b36c84..000000000 --- a/gax/src/main/java/com/google/api/gax/nativeimage/substitutions/GaxPropertiesSubstitutions.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google LLC nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package com.google.api.gax.nativeimage.substitutions; - -import com.oracle.svm.core.annotate.Alias; -import com.oracle.svm.core.annotate.RecomputeFieldValue; -import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind; -import com.oracle.svm.core.annotate.TargetClass; -import java.util.function.BooleanSupplier; - -/** - * This file contains the GaxProperties substitution to correctly set the Java language string in - * API call headers for Native Image users. - */ -@TargetClass( - className = "com.google.api.gax.core.GaxProperties", - onlyWith = GaxPropertiesSubstitutions.OnlyIfInClassPath.class) -final class GaxPropertiesSubstitutions { - - @Alias - @RecomputeFieldValue(kind = Kind.FromAlias) - private static String JAVA_VERSION = System.getProperty("java.version") + "-graalvm"; - - private GaxPropertiesSubstitutions() {} - - static class OnlyIfInClassPath implements BooleanSupplier { - - @Override - public boolean getAsBoolean() { - try { - // Note: Set initialize = false to avoid initializing the class when looking it up. - Class.forName( - "com.google.api.gax.core.GaxProperties", - false, - Thread.currentThread().getContextClassLoader()); - return true; - } catch (ClassNotFoundException e) { - return false; - } - } - } -} diff --git a/gax/src/main/resources/META-INF/native-image/com.google.api/gax/resource-config.json b/gax/src/main/resources/META-INF/native-image/com.google.api/gax/resource-config.json index fdc788936..bc40a95d5 100644 --- a/gax/src/main/resources/META-INF/native-image/com.google.api/gax/resource-config.json +++ b/gax/src/main/resources/META-INF/native-image/com.google.api/gax/resource-config.json @@ -1,6 +1,9 @@ { "resources":[ {"pattern":"\\QMETA-INF/services/jdk.vm.ci.services.JVMCIServiceLocator\\E"}, - {"pattern":"\\Qdependencies.properties\\E"}], + {"pattern":"\\Qdependencies.properties\\E"}, + {"pattern":"\\Qcom/google/api/client/googleapis/google-api-client.properties\\E"}, + {"pattern":"\\Qcom/google/api/client/googleapis/google.p12\\E"}, + {"pattern":"\\Qcom/google/api/client/http/google-http-client.properties\\E"}], "bundles":[] } diff --git a/gax/src/test/java/com/google/api/gax/core/GaxPropertiesTest.java b/gax/src/test/java/com/google/api/gax/core/GaxPropertiesTest.java index a748b9aee..27d942e69 100644 --- a/gax/src/test/java/com/google/api/gax/core/GaxPropertiesTest.java +++ b/gax/src/test/java/com/google/api/gax/core/GaxPropertiesTest.java @@ -29,6 +29,8 @@ */ package com.google.api.gax.core; +import static org.graalvm.nativeimage.ImageInfo.PROPERTY_IMAGE_CODE_KEY; +import static org.graalvm.nativeimage.ImageInfo.PROPERTY_IMAGE_CODE_VALUE_RUNTIME; import static org.junit.Assert.assertTrue; import java.util.regex.Pattern; @@ -54,4 +56,11 @@ public void testGaxVersion() { assertTrue(minor >= 56); } } + + @Test + public void testGetVersion_nativeImage() { + System.setProperty(PROPERTY_IMAGE_CODE_KEY, PROPERTY_IMAGE_CODE_VALUE_RUNTIME); + String javaVersion = GaxProperties.getJavaVersion(); + assertTrue(javaVersion.endsWith("-graalvm")); + } } diff --git a/versions.txt b/versions.txt index 97713765f..3c7613a42 100644 --- a/versions.txt +++ b/versions.txt @@ -1,7 +1,7 @@ # Format: # module:released-version:current-version -gax:2.17.0:2.17.0 -gax-bom:2.17.0:2.17.0 -gax-grpc:2.17.0:2.17.0 -gax-httpjson:0.102.0:0.102.0 +gax:2.18.0:2.18.0 +gax-bom:2.18.0:2.18.0 +gax-grpc:2.18.0:2.18.0 +gax-httpjson:0.103.0:0.103.0