diff --git a/CHANGELOG.md b/CHANGELOG.md index e3d9a10c9d..18e7cb7db4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,9 @@ and what APIs have changed, if applicable. ## [Unreleased] +## [29.21.4] - 2021-08-30 +- Expose an API to build a URI without query params. Expose a local attr for passing query params for in-process calls. + ## [29.21.3] - 2021-08-25 - Fix a bug in SmoothRateLimiter where getEvents will always return 0 @@ -5067,7 +5070,8 @@ patch operations can re-use these classes for generating patch messages. ## [0.14.1] -[Unreleased]: https://github.com/linkedin/rest.li/compare/v29.21.3...master +[Unreleased]: https://github.com/linkedin/rest.li/compare/v29.21.4...master +[29.21.4]: https://github.com/linkedin/rest.li/compare/v29.21.3...v29.21.4 [29.21.3]: https://github.com/linkedin/rest.li/compare/v29.21.2...v29.21.3 [29.21.2]: https://github.com/linkedin/rest.li/compare/v29.21.1...v29.21.2 [29.21.1]: https://github.com/linkedin/rest.li/compare/v29.21.0...v29.21.1 diff --git a/gradle.properties b/gradle.properties index f2a6fa04d8..c979f1b557 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=29.21.3 +version=29.21.4 group=com.linkedin.pegasus org.gradle.configureondemand=true org.gradle.parallel=true diff --git a/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/AbstractRestliRequestUriBuilder.java b/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/AbstractRestliRequestUriBuilder.java index 73f29407e7..3589a58668 100644 --- a/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/AbstractRestliRequestUriBuilder.java +++ b/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/AbstractRestliRequestUriBuilder.java @@ -112,21 +112,41 @@ protected final void appendAssocKeys(UriBuilder uriBuilder) } @Override - public URI buildBaseUri() + public final URI buildBaseUri() { return URI.create(bindPathKeys()); } - public URI buildBaseUriWithPrefix() + @Override + public final URI buildWithoutQueryParams() + { + return getUriBuilderWithoutQueryParams().build(); + } + + @Override + public final URI build() { + UriBuilder b = getUriBuilderWithoutQueryParams(); + appendQueryParams(b); + return b.build(); + } + + /** + * @return The URI builder (without query params) for this request. + */ + protected UriBuilder getUriBuilderWithoutQueryParams() + { + final URI uri; if (_request.getPathKeys().isEmpty()) { // if path keys are empty we don't need to bind the path keys, we can directly use the request base uri template. - return URI_TEMPLATE_STRING_TO_URI_CACHE.get(addPrefix(_request.getBaseUriTemplate()), template -> URI.create(template)); + uri = URI_TEMPLATE_STRING_TO_URI_CACHE.get(addPrefix(_request.getBaseUriTemplate()), URI::create); } else { - return URI.create(addPrefix(bindPathKeys())); + uri = URI.create(addPrefix(bindPathKeys())); } + + return UriBuilder.fromUri(uri); } } diff --git a/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/ActionRequestUriBuilder.java b/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/ActionRequestUriBuilder.java index 27f5605cb9..ffb88851ba 100644 --- a/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/ActionRequestUriBuilder.java +++ b/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/ActionRequestUriBuilder.java @@ -18,12 +18,8 @@ import com.linkedin.jersey.api.uri.UriBuilder; -import com.linkedin.jersey.api.uri.UriComponent; import com.linkedin.restli.client.ActionRequest; import com.linkedin.restli.common.ProtocolVersion; -import com.linkedin.restli.internal.common.URIParamUtils; - -import java.net.URI; /** @@ -37,15 +33,14 @@ class ActionRequestUriBuilder extends AbstractRestliRequestUriBuilder actionRequest = getRequest(); - UriBuilder b = UriBuilder.fromUri(buildBaseUriWithPrefix()); + UriBuilder b = super.getUriBuilderWithoutQueryParams(); if (actionRequest.getId() != null) { appendKeyToPath(b, actionRequest.getId()); } - appendQueryParams(b); - return b.build(); + return b; } } diff --git a/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/BatchCreateIdEntityRequestUriBuilder.java b/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/BatchCreateIdEntityRequestUriBuilder.java index cd4b4cee2d..1dc8547b15 100644 --- a/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/BatchCreateIdEntityRequestUriBuilder.java +++ b/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/BatchCreateIdEntityRequestUriBuilder.java @@ -16,12 +16,9 @@ package com.linkedin.restli.client.uribuilders; -import com.linkedin.jersey.api.uri.UriBuilder; import com.linkedin.restli.client.BatchCreateIdEntityRequest; import com.linkedin.restli.common.ProtocolVersion; -import java.net.URI; - /** * @author Boyang Chen @@ -32,12 +29,4 @@ public class BatchCreateIdEntityRequestUriBuilder extends AbstractRestliRequestU { super(request, uriPrefix, version); } - - @Override - public URI build() - { - UriBuilder b = UriBuilder.fromUri(buildBaseUriWithPrefix()); - appendQueryParams(b); - return b.build(); - } } \ No newline at end of file diff --git a/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/BatchCreateIdRequestUriBuilder.java b/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/BatchCreateIdRequestUriBuilder.java index 1fe89c9a36..722e5742bb 100644 --- a/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/BatchCreateIdRequestUriBuilder.java +++ b/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/BatchCreateIdRequestUriBuilder.java @@ -16,13 +16,9 @@ package com.linkedin.restli.client.uribuilders; - -import com.linkedin.jersey.api.uri.UriBuilder; import com.linkedin.restli.client.BatchCreateIdRequest; import com.linkedin.restli.common.ProtocolVersion; -import java.net.URI; - /** * URI Builder for {@link com.linkedin.restli.client.BatchCreateIdRequest} @@ -34,12 +30,4 @@ public class BatchCreateIdRequestUriBuilder extends AbstractRestliRequestUriBuil { super(request, uriPrefix, version); } - - @Override - public URI build() - { - UriBuilder b = UriBuilder.fromUri(buildBaseUriWithPrefix()); - appendQueryParams(b); - return b.build(); - } } diff --git a/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/BatchCreateRequestUriBuilder.java b/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/BatchCreateRequestUriBuilder.java index 30a500f954..cafa531fb4 100644 --- a/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/BatchCreateRequestUriBuilder.java +++ b/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/BatchCreateRequestUriBuilder.java @@ -16,11 +16,8 @@ package com.linkedin.restli.client.uribuilders; - -import com.linkedin.jersey.api.uri.UriBuilder; import com.linkedin.restli.client.BatchCreateRequest; import com.linkedin.restli.common.ProtocolVersion; -import java.net.URI; /** @@ -32,12 +29,4 @@ class BatchCreateRequestUriBuilder extends AbstractRestliRequestUriBuilder request, Stri { super(request, uriPrefix, version); } - - @Override - public URI build() - { - final UriBuilder builder = UriBuilder.fromUri(buildBaseUriWithPrefix()); - appendQueryParams(builder); - return builder.build(); - } } diff --git a/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/BatchGetKVRequestUriBuilder.java b/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/BatchGetKVRequestUriBuilder.java index c19b467c38..9d24ee3fe6 100644 --- a/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/BatchGetKVRequestUriBuilder.java +++ b/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/BatchGetKVRequestUriBuilder.java @@ -16,11 +16,8 @@ package com.linkedin.restli.client.uribuilders; - -import com.linkedin.jersey.api.uri.UriBuilder; import com.linkedin.restli.client.BatchGetKVRequest; import com.linkedin.restli.common.ProtocolVersion; -import java.net.URI; /** @@ -32,12 +29,4 @@ public BatchGetKVRequestUriBuilder(BatchGetKVRequest request, String uriPr { super(request, uriPrefix, version); } - - @Override - public URI build() - { - UriBuilder b = UriBuilder.fromUri(buildBaseUriWithPrefix()); - appendQueryParams(b); - return b.build(); - } } diff --git a/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/BatchGetRequestUriBuilder.java b/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/BatchGetRequestUriBuilder.java index 390ef415ad..dd21776a9e 100644 --- a/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/BatchGetRequestUriBuilder.java +++ b/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/BatchGetRequestUriBuilder.java @@ -16,11 +16,8 @@ package com.linkedin.restli.client.uribuilders; - -import com.linkedin.jersey.api.uri.UriBuilder; import com.linkedin.restli.client.BatchGetRequest; import com.linkedin.restli.common.ProtocolVersion; -import java.net.URI; /** @@ -32,12 +29,4 @@ class BatchGetRequestUriBuilder extends AbstractRestliRequestUriBuilder deleteRequest = getRequest(); - UriBuilder b = UriBuilder.fromUri(buildBaseUriWithPrefix()); + UriBuilder b = super.getUriBuilderWithoutQueryParams(); appendKeyToPath(b, deleteRequest.getId()); - appendQueryParams(b); - return b.build(); + return b; } } diff --git a/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/FindRequestUriBuilder.java b/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/FindRequestUriBuilder.java index e805b92598..e55476ab35 100644 --- a/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/FindRequestUriBuilder.java +++ b/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/FindRequestUriBuilder.java @@ -16,11 +16,9 @@ package com.linkedin.restli.client.uribuilders; - import com.linkedin.jersey.api.uri.UriBuilder; import com.linkedin.restli.client.FindRequest; import com.linkedin.restli.common.ProtocolVersion; -import java.net.URI; /** @@ -34,11 +32,10 @@ class FindRequestUriBuilder extends AbstractRestliRequestUriBuilder } @Override - public URI build() + protected UriBuilder getUriBuilderWithoutQueryParams() { GetRequest getRequest = getRequest(); - UriBuilder b = UriBuilder.fromUri(buildBaseUriWithPrefix()); + UriBuilder b = super.getUriBuilderWithoutQueryParams(); appendKeyToPath(b, getRequest.getObjectId()); - appendQueryParams(b); - return b.build(); + return b; } } diff --git a/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/MultiplexerUriBuilder.java b/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/MultiplexerUriBuilder.java index 6de7d068ec..e55f0d6759 100644 --- a/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/MultiplexerUriBuilder.java +++ b/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/MultiplexerUriBuilder.java @@ -43,6 +43,12 @@ public URI buildBaseUri() return build(); } + @Override + public URI buildWithoutQueryParams() + { + return build(); + } + @Override public URI build() { diff --git a/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/OptionsRequestUriBuilder.java b/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/OptionsRequestUriBuilder.java index 0f4adaa2f8..c066736a43 100644 --- a/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/OptionsRequestUriBuilder.java +++ b/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/OptionsRequestUriBuilder.java @@ -16,11 +16,8 @@ package com.linkedin.restli.client.uribuilders; - -import com.linkedin.jersey.api.uri.UriBuilder; import com.linkedin.restli.client.OptionsRequest; import com.linkedin.restli.common.ProtocolVersion; -import java.net.URI; /** @@ -33,12 +30,4 @@ class OptionsRequestUriBuilder extends AbstractRestliRequestUriBuilder partialUpdateEntityRequest = getRequest(); - UriBuilder b = UriBuilder.fromUri(buildBaseUriWithPrefix()); + UriBuilder b = super.getUriBuilderWithoutQueryParams(); appendKeyToPath(b, partialUpdateEntityRequest.getId()); - appendQueryParams(b); - return b.build(); + return b; } } diff --git a/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/PartialUpdateRequestUriBuilder.java b/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/PartialUpdateRequestUriBuilder.java index fb72c47789..9209b3a160 100644 --- a/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/PartialUpdateRequestUriBuilder.java +++ b/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/PartialUpdateRequestUriBuilder.java @@ -16,11 +16,9 @@ package com.linkedin.restli.client.uribuilders; - import com.linkedin.jersey.api.uri.UriBuilder; import com.linkedin.restli.client.PartialUpdateRequest; import com.linkedin.restli.common.ProtocolVersion; -import java.net.URI; /** @@ -34,12 +32,11 @@ class PartialUpdateRequestUriBuilder extends AbstractRestliRequestUriBuilder partialUpdateRequest = getRequest(); - UriBuilder b = UriBuilder.fromUri(buildBaseUriWithPrefix()); + UriBuilder b = super.getUriBuilderWithoutQueryParams(); appendKeyToPath(b, partialUpdateRequest.getId()); - appendQueryParams(b); - return b.build(); + return b; } } diff --git a/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/RestliUriBuilder.java b/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/RestliUriBuilder.java index 3f21e8145b..b73d184d26 100644 --- a/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/RestliUriBuilder.java +++ b/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/RestliUriBuilder.java @@ -27,14 +27,21 @@ public interface RestliUriBuilder { /** - * Build the complete URI (including query parameters) + * Build the complete URI (including query parameters and path keys) * * @return the complete URI */ URI build(); /** - * Build the base URI, i.e. the URI without query params + * Build the URI (including path keys but excluding query params) + * + * @return the built URI + */ + URI buildWithoutQueryParams(); + + /** + * Build the base URI, i.e. the URI without path keys or query params * * @return the base URI */ diff --git a/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/UpdateRequestUriBuilder.java b/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/UpdateRequestUriBuilder.java index f6924bcf44..5aeca25cca 100644 --- a/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/UpdateRequestUriBuilder.java +++ b/restli-client/src/main/java/com/linkedin/restli/client/uribuilders/UpdateRequestUriBuilder.java @@ -16,11 +16,9 @@ package com.linkedin.restli.client.uribuilders; - import com.linkedin.jersey.api.uri.UriBuilder; import com.linkedin.restli.client.UpdateRequest; import com.linkedin.restli.common.ProtocolVersion; -import java.net.URI; /** @@ -34,12 +32,11 @@ public class UpdateRequestUriBuilder extends AbstractRestliRequestUriBuilder updateRequest = getRequest(); - UriBuilder b = UriBuilder.fromUri(buildBaseUriWithPrefix()); + UriBuilder b = super.getUriBuilderWithoutQueryParams(); appendKeyToPath(b, updateRequest.getId()); - appendQueryParams(b); - return b.build(); + return b; } } diff --git a/restli-internal-testutils/src/test/java/com/linkedin/restli/internal/testutils/URIDetails.java b/restli-internal-testutils/src/test/java/com/linkedin/restli/internal/testutils/URIDetails.java index 53248a601c..9c44dd5f66 100644 --- a/restli-internal-testutils/src/test/java/com/linkedin/restli/internal/testutils/URIDetails.java +++ b/restli-internal-testutils/src/test/java/com/linkedin/restli/internal/testutils/URIDetails.java @@ -125,26 +125,40 @@ public ProtocolVersion getProtocolVersion() * Tests the deprecated API for getting the URI of a request, as well as the new way of constructing the URI using * a builder. Requires an URIDetails object with the broken down URI to make sure that out of URIs are still considered * valid. - * - * @param request - * @param expectedURIDetails */ @SuppressWarnings({"deprecation"}) public static void testUriGeneration(Request request, URIDetails expectedURIDetails) { final ProtocolVersion version = expectedURIDetails.getProtocolVersion(); final String createdURIString = RestliUriBuilderUtil.createUriBuilder(request, version).build().toString(); - testUriGeneration(createdURIString, expectedURIDetails); + testUriGeneration(createdURIString, expectedURIDetails, true); + + final String createdURIStringWithoutQueryParams = + RestliUriBuilderUtil.createUriBuilder(request, version).buildWithoutQueryParams().toString(); + testUriGeneration(createdURIStringWithoutQueryParams, expectedURIDetails, false); + } + + /** + * Tests the construction and validity of the provided URI. Requires an URIDetails object with the broken down URI. + */ + public static void testUriGeneration(String createdURIString, URIDetails expectedURIDetails) + { + testUriGeneration(createdURIString, expectedURIDetails, true); } /** * Tests the construction and validity of the provided URI. Requires an URIDetails object with the broken down URI. * - * @param createdURIString - * @param expectedURIDetails + * @param createdURIString The created URI string. + * @param expectedURIDetails URIDetails object with the broken down URI to make sure that out of URIs are still + * considered valid. + * @param includesQueryParams Whether the created URI includes query params or not. If true, we will verify that + * params match the ones in URI details. If false, we will validate that params is + * empty. */ @SuppressWarnings({"unchecked"}) - public static void testUriGeneration(String createdURIString, URIDetails expectedURIDetails) + private static void testUriGeneration(String createdURIString, URIDetails expectedURIDetails, + boolean includesQueryParams) { final ProtocolVersion version = expectedURIDetails.getProtocolVersion(); @@ -158,6 +172,13 @@ public static void testUriGeneration(String createdURIString, URIDetails expecte //We will parse the created URI into memory and compare it to what's inside the URI details final DataMap actualURIDataMap; + // If query params are not included, verify that the raw query is null. + if (!includesQueryParams) + { + Assert.assertNull(createdURI.getRawQuery()); + return; + } + //Compare the DataMaps created by parsing the URI into memory vs the ones created in the test. //Note that the actualURIDataMap that is created is composed of query parameters (including ids) and fields try diff --git a/restli-server/src/main/java/com/linkedin/restli/internal/server/ResourceContextImpl.java b/restli-server/src/main/java/com/linkedin/restli/internal/server/ResourceContextImpl.java index d87845ee36..71ef3c09d2 100644 --- a/restli-server/src/main/java/com/linkedin/restli/internal/server/ResourceContextImpl.java +++ b/restli-server/src/main/java/com/linkedin/restli/internal/server/ResourceContextImpl.java @@ -169,7 +169,12 @@ public ResourceContextImpl(final MutablePathKeys pathKeys, try { - if (_protocolVersion.compareTo(AllProtocolVersions.RESTLI_PROTOCOL_2_0_0.getProtocolVersion()) >= 0) + DataMap contextQueryParams = (DataMap) requestContext.getLocalAttr(CONTEXT_QUERY_PARAMS_KEY); + if (contextQueryParams != null) + { + _parameters = contextQueryParams; + } + else if (_protocolVersion.compareTo(AllProtocolVersions.RESTLI_PROTOCOL_2_0_0.getProtocolVersion()) >= 0) { TimingContextUtil.beginTiming(requestContext, FrameworkTimingKeys.SERVER_REQUEST_RESTLI_URI_PARSE_2.key()); diff --git a/restli-server/src/main/java/com/linkedin/restli/internal/server/ServerResourceContext.java b/restli-server/src/main/java/com/linkedin/restli/internal/server/ServerResourceContext.java index 0e1b98094c..0ef0f6abc8 100644 --- a/restli-server/src/main/java/com/linkedin/restli/internal/server/ServerResourceContext.java +++ b/restli-server/src/main/java/com/linkedin/restli/internal/server/ServerResourceContext.java @@ -52,6 +52,11 @@ public interface ServerResourceContext extends ResourceContext */ String CONTEXT_COOKIES_KEY = ServerResourceContext.class.getName() + ".cookie"; + /** + * Local attribute key for query params datamap. Value should be a {@link DataMap}. + */ + String CONTEXT_QUERY_PARAMS_KEY = ServerResourceContext.class.getName() + ".queryParams"; + /** * Local attribute key for projection masks. Value should be a * {@link LocalRequestProjectionMask} instance. diff --git a/restli-server/src/test/java/com/linkedin/restli/internal/server/TestResourceContextImpl.java b/restli-server/src/test/java/com/linkedin/restli/internal/server/TestResourceContextImpl.java index 001743c4cc..544c1bed73 100644 --- a/restli-server/src/test/java/com/linkedin/restli/internal/server/TestResourceContextImpl.java +++ b/restli-server/src/test/java/com/linkedin/restli/internal/server/TestResourceContextImpl.java @@ -134,6 +134,22 @@ public void testCookiesLocalAttr() throws Exception Assert.assertSame(resourceContext.getRequestCookies(), localCookies); } + @Test + public void testQueryParamsLocalAttr() throws Exception + { + URI uri = URI.create("resources"); + + RequestContext requestContext = new RequestContext(); + DataMap queryParams = new DataMap(Collections.singletonMap("testKey", "testValue")); + requestContext.putLocalAttr(ServerResourceContext.CONTEXT_QUERY_PARAMS_KEY, queryParams); + + ServerResourceContext resourceContext = new ResourceContextImpl( + new PathKeysImpl(), new TestResourceContext.MockRequest(uri), requestContext); + + // Assert that query params are retrieved from the local attribute. + Assert.assertSame(resourceContext.getParameters(), queryParams); + } + @DataProvider private static Object[][] overrideMaskData() {