diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock
index 017e772..4ec1d81 100755
--- a/.speakeasy/gen.lock
+++ b/.speakeasy/gen.lock
@@ -3,10 +3,10 @@ id: 1d22a5a4-8bac-42e3-b164-121fcacf66c9
management:
docChecksum: b7d2d41694154c8bb06badd95ee5eabf
docVersion: v1
- speakeasyVersion: 1.437.0
- generationVersion: 2.456.0
- releaseVersion: 1.2.0
- configChecksum: 09ed2850809d9e84b4ae26784404d320
+ speakeasyVersion: 1.441.0
+ generationVersion: 2.460.1
+ releaseVersion: 1.3.0
+ configChecksum: 97544bded64ebb467d8148b7b71880ba
repoURL: https://github.com/clerk/clerk-sdk-java.git
published: true
features:
@@ -14,7 +14,7 @@ features:
additionalDependencies: 0.1.0
additionalProperties: 0.0.1
constsAndDefaults: 0.1.1
- core: 3.31.0
+ core: 3.32.0
deprecations: 2.81.1
examples: 2.81.3
flattening: 2.81.1
@@ -1234,6 +1234,7 @@ generatedFiles:
- src/main/java/com/clerk/backend_api/utils/OneOfDeserializer.java
- src/main/java/com/clerk/backend_api/utils/Options.java
- src/main/java/com/clerk/backend_api/utils/PathParamsMetadata.java
+ - src/main/java/com/clerk/backend_api/utils/QueryParameter.java
- src/main/java/com/clerk/backend_api/utils/QueryParameters.java
- src/main/java/com/clerk/backend_api/utils/QueryParamsMetadata.java
- src/main/java/com/clerk/backend_api/utils/RequestBody.java
@@ -1248,6 +1249,7 @@ generatedFiles:
- src/main/java/com/clerk/backend_api/utils/SpeakeasyMetadata.java
- src/main/java/com/clerk/backend_api/utils/TypedObject.java
- src/main/java/com/clerk/backend_api/utils/Types.java
+ - src/main/java/com/clerk/backend_api/utils/Utf8UrlEncoder.java
- src/main/java/com/clerk/backend_api/utils/Utils.java
examples:
GetPublicInterstitial: {}
diff --git a/.speakeasy/gen.yaml b/.speakeasy/gen.yaml
index 95bccd9..ca30d11 100755
--- a/.speakeasy/gen.yaml
+++ b/.speakeasy/gen.yaml
@@ -13,7 +13,7 @@ generation:
oAuth2ClientCredentialsEnabled: true
oAuth2PasswordEnabled: false
java:
- version: 1.2.0
+ version: 1.3.0
additionalDependencies: []
additionalPlugins: []
artifactID: backend-api
diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock
index d0dfcbc..74cd5e6 100644
--- a/.speakeasy/workflow.lock
+++ b/.speakeasy/workflow.lock
@@ -1,20 +1,20 @@
-speakeasyVersion: 1.437.0
+speakeasyVersion: 1.441.0
sources:
clerk-java-sdk:
sourceNamespace: clerk-java-sdk
- sourceRevisionDigest: sha256:1a486565939833e7da8fd89f4dca29e4ca17f28654e44085a3363f0f1e440eeb
+ sourceRevisionDigest: sha256:5bfc2dc2bdbf8afca23882fdc2fc99541c6aa384f8ea99311727bdc12bbe0c3f
sourceBlobDigest: sha256:3a79bd76a35cec51d82efcdad7c5fffff14db6ed394011e299ac78c2f6159e12
tags:
- latest
- - main
+ - speakeasy-sdk-regen-1731969931
targets:
clerk-java:
source: clerk-java-sdk
sourceNamespace: clerk-java-sdk
- sourceRevisionDigest: sha256:1a486565939833e7da8fd89f4dca29e4ca17f28654e44085a3363f0f1e440eeb
+ sourceRevisionDigest: sha256:5bfc2dc2bdbf8afca23882fdc2fc99541c6aa384f8ea99311727bdc12bbe0c3f
sourceBlobDigest: sha256:3a79bd76a35cec51d82efcdad7c5fffff14db6ed394011e299ac78c2f6159e12
codeSamplesNamespace: clerk-java-sdk-code-samples
- codeSamplesRevisionDigest: sha256:d767573120892d3ab715b3145a54847f35113612c3817bacc394d4b02e93896d
+ codeSamplesRevisionDigest: sha256:d1becf6d0bfef998549a0d7e2547800a0c78a3b2fa6d8e625537c69afec6d8b1
my-first-target:
source: clerk-java-sdk
sourceNamespace: clerk-java-sdk
diff --git a/README.md b/README.md
index c6b970c..c0f11c3 100644
--- a/README.md
+++ b/README.md
@@ -47,7 +47,7 @@ The samples below show how a published SDK artifact is used:
Gradle:
```groovy
-implementation 'com.clerk:backend-api:1.2.0'
+implementation 'com.clerk:backend-api:1.3.0'
```
Maven:
@@ -55,7 +55,7 @@ Maven:
com.clerk
backend-api
- 1.2.0
+ 1.3.0
```
diff --git a/RELEASES.md b/RELEASES.md
index 1d3b651..872faf7 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -158,4 +158,14 @@ Based on:
### Generated
- [java v1.2.0] .
### Releases
-- [Maven Central v1.2.0] https://central.sonatype.com/artifact/com.clerk/backend-api/1.2.0 - .
\ No newline at end of file
+- [Maven Central v1.2.0] https://central.sonatype.com/artifact/com.clerk/backend-api/1.2.0 - .
+
+## 2024-11-18 22:45:28
+### Changes
+Based on:
+- OpenAPI Doc
+- Speakeasy CLI 1.441.0 (2.460.1) https://github.com/speakeasy-api/speakeasy
+### Generated
+- [java v1.3.0] .
+### Releases
+- [Maven Central v1.3.0] https://central.sonatype.com/artifact/com.clerk/backend-api/1.3.0 - .
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index aa39a35..4ec49cd 100644
--- a/build.gradle
+++ b/build.gradle
@@ -63,7 +63,7 @@ tasks.withType(Javadoc) {
}
group = "com.clerk"
-version = "1.2.0"
+version = "1.3.0"
sourcesJar {
archiveBaseName = "backend-api"
@@ -101,7 +101,7 @@ publishing {
maven(MavenPublication) {
groupId = 'com.clerk'
artifactId = 'backend-api'
- version = '1.2.0'
+ version = '1.3.0'
from components.java
diff --git a/src/main/java/com/clerk/backend_api/SDKConfiguration.java b/src/main/java/com/clerk/backend_api/SDKConfiguration.java
index 2c62f0b..65a08b7 100644
--- a/src/main/java/com/clerk/backend_api/SDKConfiguration.java
+++ b/src/main/java/com/clerk/backend_api/SDKConfiguration.java
@@ -23,8 +23,8 @@ public Optional securitySource() {
public int serverIdx = 0;
private static final String LANGUAGE = "java";
public static final String OPENAPI_DOC_VERSION = "v1";
- public static final String SDK_VERSION = "1.2.0";
- public static final String GEN_VERSION = "2.456.0";
+ public static final String SDK_VERSION = "1.3.0";
+ public static final String GEN_VERSION = "2.460.1";
private static final String BASE_PACKAGE = "com.clerk.backend_api";
public static final String USER_AGENT =
String.format("speakeasy-sdk/%s %s %s %s %s",
diff --git a/src/main/java/com/clerk/backend_api/utils/HTTPRequest.java b/src/main/java/com/clerk/backend_api/utils/HTTPRequest.java
index 5f23ced..61ea307 100644
--- a/src/main/java/com/clerk/backend_api/utils/HTTPRequest.java
+++ b/src/main/java/com/clerk/backend_api/utils/HTTPRequest.java
@@ -4,6 +4,7 @@
package com.clerk.backend_api.utils;
+import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpRequest;
import java.net.http.HttpRequest.BodyPublisher;
@@ -15,15 +16,15 @@
import java.util.Map;
import java.util.Optional;
-import org.apache.http.NameValuePair;
-import org.apache.http.client.utils.URIBuilder;
-import org.apache.http.message.BasicNameValuePair;
-
public class HTTPRequest {
+ private static final String FRAGMENT_SEGMENT_START = "#";
+ private static final String QUERY_NAME_VALUE_DELIMITER = "=";
+ private static final String QUERY_PARAMETER_DELIMITER = "&";
+ private static final String QUERY_SEGMENT_START = "?";
private final String baseURL;
private final String method;
- private final List queryParams = new ArrayList<>();
+ private final List queryParams = new ArrayList<>();
private final Map> headers = new HashMap<>();
private Optional body = Optional.empty(); // mutable
@@ -54,21 +55,21 @@ public HTTPRequest addHeaders(Map> map) {
return this;
}
- public HTTPRequest addQueryParam(String name, String value) {
- addQueryParam(new BasicNameValuePair(name, value));
+ public HTTPRequest addQueryParam(QueryParameter param) {
+ this.queryParams.add(param);
return this;
}
-
- public HTTPRequest addQueryParam(NameValuePair param) {
- this.queryParams.add(param);
+
+ public HTTPRequest addQueryParam(String key, String value, boolean allowReserved) {
+ this.queryParams.add(QueryParameter.of(key, value, allowReserved));
return this;
}
- public HTTPRequest addQueryParams(Collection params) {
+ public HTTPRequest addQueryParams(Collection params) {
params.forEach(p -> addQueryParam(p));
return this;
}
-
+
public HttpRequest build() {
HttpRequest.Builder requestBuilder = HttpRequest.newBuilder();
@@ -81,14 +82,49 @@ public HttpRequest build() {
}
requestBuilder.method(method, bodyPublisher);
try {
- URIBuilder b = new URIBuilder(this.baseURL);
- queryParams.forEach(pair -> b.addParameter(pair.getName(), pair.getValue()));
- requestBuilder.uri(b.build());
+ requestBuilder.uri(new URI(buildUrl(baseURL, queryParams)));
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
headers.forEach((k, list) -> list.forEach(v -> requestBuilder.header(k, v)));
return requestBuilder.build();
}
-
+
+ // VisibleForTesting
+ public static String buildUrl(String baseURL, Collection queryParams) {
+ if (queryParams.isEmpty()) {
+ return baseURL;
+ } else {
+ final String base;
+ final String fragment;
+ int i = baseURL.indexOf(FRAGMENT_SEGMENT_START);
+ if (i == -1) {
+ base = baseURL;
+ fragment = "";
+ } else {
+ base = baseURL.substring(0, i);
+ fragment = baseURL.substring(i);
+ }
+ StringBuilder b = new StringBuilder(base);
+ if (!base.contains(QUERY_SEGMENT_START)) {
+ b.append(QUERY_SEGMENT_START);
+ } else {
+ b.append(QUERY_PARAMETER_DELIMITER);
+ }
+ boolean first = true;
+ for (QueryParameter p : queryParams) {
+ if (!first) {
+ b.append(QUERY_PARAMETER_DELIMITER);
+ }
+ first = false;
+ // don't allow reserved characters to be unencoded in key (??)
+ b.append(Utf8UrlEncoder.DEFAULT.encode(p.name()));
+ b.append(QUERY_NAME_VALUE_DELIMITER);
+ b.append(Utf8UrlEncoder.allowReserved(p.allowReserved()).encode(p.value()));
+ }
+ b.append(fragment);
+ return b.toString();
+ }
+ }
+
}
\ No newline at end of file
diff --git a/src/main/java/com/clerk/backend_api/utils/PathParamsMetadata.java b/src/main/java/com/clerk/backend_api/utils/PathParamsMetadata.java
index 99cbca0..46818d7 100644
--- a/src/main/java/com/clerk/backend_api/utils/PathParamsMetadata.java
+++ b/src/main/java/com/clerk/backend_api/utils/PathParamsMetadata.java
@@ -8,15 +8,17 @@
class PathParamsMetadata {
+ // these fields set via reflection
+
String style = "simple";
boolean explode;
String name;
String serialization;
+ boolean allowReserved;
private PathParamsMetadata() {
}
- // pathParam:style=simple,explode=false,name=apiID
static PathParamsMetadata parse(Field field) throws IllegalArgumentException, IllegalAccessException {
return Metadata.parse("pathParam", new PathParamsMetadata(), field);
}
diff --git a/src/main/java/com/clerk/backend_api/utils/QueryParameter.java b/src/main/java/com/clerk/backend_api/utils/QueryParameter.java
new file mode 100644
index 0000000..37bf254
--- /dev/null
+++ b/src/main/java/com/clerk/backend_api/utils/QueryParameter.java
@@ -0,0 +1,62 @@
+/*
+ * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
+ */
+
+package com.clerk.backend_api.utils;
+
+import java.util.Objects;
+
+// internal class, not for public use
+// TODO move to internal package
+public final class QueryParameter {
+
+ private final String name;
+ private final String value;
+ private final boolean allowReserved;
+
+ private QueryParameter(String name, String value, boolean allowReserved) {
+ this.name = name;
+ this.value = value;
+ this.allowReserved = allowReserved;
+ }
+
+ public static QueryParameter of(String name, String value, boolean allowReserved) {
+ return new QueryParameter(name, value, allowReserved);
+ }
+
+ public String name() {
+ return name;
+ }
+
+ public String value() {
+ return value;
+ }
+
+ public boolean allowReserved() {
+ return allowReserved;
+ }
+
+ @Override
+ public String toString() {
+ return "QueryParameter [name=" + name + ", value=" + value + ", allowReserved=" + allowReserved + "]";
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(allowReserved, name, value);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ QueryParameter other = (QueryParameter) obj;
+ return allowReserved == other.allowReserved && Objects.equals(name, other.name)
+ && Objects.equals(value, other.value);
+ }
+
+}
diff --git a/src/main/java/com/clerk/backend_api/utils/QueryParameters.java b/src/main/java/com/clerk/backend_api/utils/QueryParameters.java
index 69e4157..dfa51f5 100644
--- a/src/main/java/com/clerk/backend_api/utils/QueryParameters.java
+++ b/src/main/java/com/clerk/backend_api/utils/QueryParameters.java
@@ -11,16 +11,13 @@
import java.util.Map;
import java.util.stream.Collectors;
-import org.apache.http.NameValuePair;
-import org.apache.http.message.BasicNameValuePair;
-
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class QueryParameters {
- public static List parseQueryParams(Class type, T queryParams,
+ public static List parseQueryParams(Class type, T queryParams,
Map>> globals) throws Exception {
- List allParams = new ArrayList<>();
+ List allParams = new ArrayList<>();
Field[] fields = type.getDeclaredFields();
@@ -45,20 +42,20 @@ public static List parseQueryParams(Class t
}
if (queryParamsMetadata.serialization != null && !queryParamsMetadata.serialization.isBlank()) {
- List params = parseSerializedParams(queryParamsMetadata, value);
+ List params = parseSerializedParams(queryParamsMetadata, value);
allParams.addAll(params);
} else {
switch (queryParamsMetadata.style) {
case "form":
- List formParams = parseDelimitedParams(queryParamsMetadata, value, ",");
+ List formParams = parseDelimitedParams(queryParamsMetadata, value, ",");
allParams.addAll(formParams);
break;
case "deepObject":
- List deepObjectParams = parseDeepObjectParams(queryParamsMetadata, value);
+ List deepObjectParams = parseDeepObjectParams(queryParamsMetadata, value);
allParams.addAll(deepObjectParams);
break;
case "pipeDelimited":
- List pipeDelimitedParams = parseDelimitedParams(queryParamsMetadata, value, "|");
+ List pipeDelimitedParams = parseDelimitedParams(queryParamsMetadata, value, "|");
allParams.addAll(pipeDelimitedParams);
break;
default:
@@ -70,14 +67,14 @@ public static List parseQueryParams(Class t
return allParams;
}
- private static List parseSerializedParams(QueryParamsMetadata queryParamsMetadata, Object value)
+ private static List parseSerializedParams(QueryParamsMetadata queryParamsMetadata, Object value)
throws JsonProcessingException {
- List params = new ArrayList<>();
+ List params = new ArrayList<>();
switch (queryParamsMetadata.serialization) {
case "json":
ObjectMapper mapper = JSON.getMapper();
String json = mapper.writeValueAsString(value);
- params.add(new BasicNameValuePair(queryParamsMetadata.name, json));
+ params.add(QueryParameter.of(queryParamsMetadata.name, json, queryParamsMetadata.allowReserved));
break;
default:
break;
@@ -85,9 +82,9 @@ private static List parseSerializedParams(QueryParamsMetadata que
return params;
}
- private static List parseDelimitedParams(QueryParamsMetadata queryParamsMetadata, Object value, String delimiter)
+ private static List parseDelimitedParams(QueryParamsMetadata queryParamsMetadata, Object value, String delimiter)
throws IllegalArgumentException, IllegalAccessException {
- List params = new ArrayList<>();
+ List params = new ArrayList<>();
switch (Types.getType(value.getClass())) {
case ARRAY: {
@@ -107,7 +104,7 @@ private static List parseDelimitedParams(QueryParamsMetadata quer
values.add(String.join(delimiter, items));
}
- params.addAll(values.stream().map(v -> new BasicNameValuePair(queryParamsMetadata.name, v))
+ params.addAll(values.stream().map(v -> QueryParameter.of(queryParamsMetadata.name, v, queryParamsMetadata.allowReserved))
.collect(Collectors.toList()));
break;
}
@@ -121,20 +118,20 @@ private static List parseDelimitedParams(QueryParamsMetadata quer
String val = Utils.valToString(entry.getValue());
if (queryParamsMetadata.explode) {
- params.add(new BasicNameValuePair(key, val));
+ params.add(QueryParameter.of(key, val, queryParamsMetadata.allowReserved));
} else {
items.add(String.format("%s%s%s", key, delimiter, val));
}
}
if (items.size() > 0) {
- params.add(new BasicNameValuePair(queryParamsMetadata.name, String.join(delimiter, items)));
+ params.add(QueryParameter.of(queryParamsMetadata.name, String.join(delimiter, items), queryParamsMetadata.allowReserved));
}
break;
}
case OBJECT: {
if (!Utils.allowIntrospection(value.getClass())) {
- params.add(new BasicNameValuePair(queryParamsMetadata.name, Utils.valToString(value)));
+ params.add(QueryParameter.of(queryParamsMetadata.name, Utils.valToString(value), queryParamsMetadata.allowReserved));
break;
}
Field[] fields = value.getClass().getDeclaredFields();
@@ -155,29 +152,29 @@ private static List parseDelimitedParams(QueryParamsMetadata quer
}
if (queryParamsMetadata.explode) {
- params.add(new BasicNameValuePair(metadata.name, Utils.valToString(val)));
+ params.add(QueryParameter.of(metadata.name, Utils.valToString(val), metadata.allowReserved));
} else {
items.add(String.format("%s%s%s", metadata.name, delimiter, Utils.valToString(val)));
}
}
if (items.size() > 0) {
- params.add(new BasicNameValuePair(queryParamsMetadata.name, String.join(delimiter, items)));
+ params.add(QueryParameter.of(queryParamsMetadata.name, String.join(delimiter, items), queryParamsMetadata.allowReserved));
}
break;
}
default:
- params.add(new BasicNameValuePair(queryParamsMetadata.name, Utils.valToString(value)));
+ params.add(QueryParameter.of(queryParamsMetadata.name, Utils.valToString(value), queryParamsMetadata.allowReserved));
break;
}
return params;
}
- private static List parseDeepObjectParams(QueryParamsMetadata queryParamsMetadata, Object value)
+ private static List parseDeepObjectParams(QueryParamsMetadata queryParamsMetadata, Object value)
throws Exception {
- List params = new ArrayList<>();
+ List params = new ArrayList<>();
switch (Types.getType(value.getClass())) {
case MAP: {
@@ -189,12 +186,12 @@ private static List parseDeepObjectParams(QueryParamsMetadata que
if (val instanceof List || val.getClass().isArray()) {
for (Object v : Utils.toList(val)) {
- params.add(new BasicNameValuePair(String.format("%s[%s]", queryParamsMetadata.name, key),
- Utils.valToString(v)));
+ params.add(QueryParameter.of(String.format("%s[%s]", queryParamsMetadata.name, key),
+ Utils.valToString(v), queryParamsMetadata.allowReserved));
}
} else {
- params.add(new BasicNameValuePair(String.format("%s[%s]", queryParamsMetadata.name, key),
- Utils.valToString(val)));
+ params.add(QueryParameter.of(String.format("%s[%s]", queryParamsMetadata.name, key),
+ Utils.valToString(val), queryParamsMetadata.allowReserved));
}
}
@@ -221,14 +218,14 @@ private static List parseDeepObjectParams(QueryParamsMetadata que
if (val instanceof List || val.getClass().isArray()) {
for (Object v : Utils.toList(val)) {
- params.add(new BasicNameValuePair(
+ params.add(QueryParameter.of(
String.format("%s[%s]", queryParamsMetadata.name, metadata.name),
- Utils.valToString(v)));
+ Utils.valToString(v), metadata.allowReserved));
}
} else {
params.add(
- new BasicNameValuePair(String.format("%s[%s]", queryParamsMetadata.name, metadata.name),
- Utils.valToString(val)));
+ QueryParameter.of(String.format("%s[%s]", queryParamsMetadata.name, metadata.name),
+ Utils.valToString(val), metadata.allowReserved));
}
}
diff --git a/src/main/java/com/clerk/backend_api/utils/QueryParamsMetadata.java b/src/main/java/com/clerk/backend_api/utils/QueryParamsMetadata.java
index c1bd13a..b31b33e 100644
--- a/src/main/java/com/clerk/backend_api/utils/QueryParamsMetadata.java
+++ b/src/main/java/com/clerk/backend_api/utils/QueryParamsMetadata.java
@@ -8,12 +8,14 @@
class QueryParamsMetadata {
+ // these parameters set via reflection
+
String style = "form";
boolean explode = true;
String name;
String serialization;
+ boolean allowReserved;
- // queryParam:style=simple,explode=false,name=apiID
static QueryParamsMetadata parse(Field field) throws IllegalArgumentException, IllegalAccessException {
return Metadata.parse("queryParam", new QueryParamsMetadata(), field);
}
diff --git a/src/main/java/com/clerk/backend_api/utils/Security.java b/src/main/java/com/clerk/backend_api/utils/Security.java
index 8ffc4a6..3c8b0cb 100644
--- a/src/main/java/com/clerk/backend_api/utils/Security.java
+++ b/src/main/java/com/clerk/backend_api/utils/Security.java
@@ -108,7 +108,7 @@ private static void parseSecuritySchemeValue(HTTPRequest request, SecurityMetada
break;
case "query":
request.addQueryParam(
- securityMetadata.name, Utils.valToString(value));
+ securityMetadata.name, Utils.valToString(value), false);
break;
case "cookie":
request.addHeader("Cookie",
diff --git a/src/main/java/com/clerk/backend_api/utils/Utf8UrlEncoder.java b/src/main/java/com/clerk/backend_api/utils/Utf8UrlEncoder.java
new file mode 100644
index 0000000..0f57565
--- /dev/null
+++ b/src/main/java/com/clerk/backend_api/utils/Utf8UrlEncoder.java
@@ -0,0 +1,117 @@
+/*
+ * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
+ */
+
+package com.clerk.backend_api.utils;
+
+import java.io.CharArrayWriter;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.BitSet;
+import java.util.Objects;
+
+// Internal use only
+// TODO move to an internal package
+public final class Utf8UrlEncoder {
+
+ private static final BitSet DO_NOT_ENCODE_CHARS = createDoNotEncodeChars();
+ private static final int CASE_DIFF = ('a' - 'A');
+
+ private final BitSet safeChars;
+
+ public static final Utf8UrlEncoder ALLOW_RESERVED = new Utf8UrlEncoder(":/?#[]@!$&'()*+,;=");
+ public static final Utf8UrlEncoder DEFAULT = new Utf8UrlEncoder("");
+
+ public static Utf8UrlEncoder allowReserved(boolean allowReserved) {
+ return allowReserved ? ALLOW_RESERVED : DEFAULT;
+ }
+
+ private Utf8UrlEncoder(String safeCharacters) {
+ Objects.requireNonNull(safeCharacters, "safeCharacters");
+ int max = -1;
+ for (int i = 0; i < safeCharacters.length(); i++) {
+ char ch = safeCharacters.charAt(i);
+ max = Math.max(ch, max);
+ }
+ BitSet safeChars = new BitSet(max + 1);
+ for (int i = 0; i < safeCharacters.length(); i++) {
+ char ch = safeCharacters.charAt(i);
+ safeChars.set(ch);
+ }
+ this.safeChars = safeChars;
+ }
+
+ public String encode(String s) {
+ return encode(s, StandardCharsets.UTF_8);
+ }
+
+ private String encode(String s, Charset charset) {
+ boolean changed = false;
+ StringBuilder out = new StringBuilder(s.length());
+ CharArrayWriter writer = new CharArrayWriter();
+
+ for (int i = 0; i < s.length();) {
+ int c = (int) s.charAt(i);
+ if (DO_NOT_ENCODE_CHARS.get(c) || safeChars.get(c)) {
+ out.append((char) c);
+ i++;
+ } else {
+ // convert to external encoding before hex conversion
+ do {
+ writer.write(c);
+ if (c >= 0xD800 && c <= 0xDBFF) {
+ if ((i + 1) < s.length()) {
+ int d = (int) s.charAt(i + 1);
+ if (d >= 0xDC00 && d <= 0xDFFF) {
+ writer.write(d);
+ i++;
+ }
+ }
+ }
+ i++;
+ } while (i < s.length() && !DO_NOT_ENCODE_CHARS.get((c = (int) s.charAt(i))));
+
+ writer.flush();
+ String str = new String(writer.toCharArray());
+ byte[] ba = str.getBytes(charset);
+ for (int j = 0; j < ba.length; j++) {
+ out.append('%');
+ char ch = Character.forDigit((ba[j] >> 4) & 0xF, 16);
+ // converting to use uppercase letter as part of
+ // the hex value if ch is a letter.
+ if (Character.isLetter(ch)) {
+ ch -= CASE_DIFF;
+ }
+ out.append(ch);
+ ch = Character.forDigit(ba[j] & 0xF, 16);
+ if (Character.isLetter(ch)) {
+ ch -= CASE_DIFF;
+ }
+ out.append(ch);
+ }
+ writer.reset();
+ changed = true;
+ }
+ }
+
+ return (changed ? out.toString() : s);
+ }
+
+ private static BitSet createDoNotEncodeChars() {
+ BitSet b = new BitSet(256);
+ for (int i = 'a'; i <= 'z'; i++) {
+ b.set(i);
+ }
+ for (int i = 'A'; i <= 'Z'; i++) {
+ b.set(i);
+ }
+ for (int i = '0'; i <= '9'; i++) {
+ b.set(i);
+ }
+ b.set('-');
+ b.set('_');
+ b.set('.');
+ b.set('*');
+ return b;
+ }
+}
diff --git a/src/main/java/com/clerk/backend_api/utils/Utils.java b/src/main/java/com/clerk/backend_api/utils/Utils.java
index 731cde5..612cabc 100644
--- a/src/main/java/com/clerk/backend_api/utils/Utils.java
+++ b/src/main/java/com/clerk/backend_api/utils/Utils.java
@@ -15,7 +15,6 @@
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URI;
-import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.net.http.HttpClient.Version;
import java.net.http.HttpHeaders;
@@ -144,7 +143,9 @@ public static String generateURL(Class type, String baseURL, String path,
pathParams.put(pathParamsMetadata.name,
String.join(",",
- array.stream().map(v -> valToString(v))
+ array.stream()
+ .map(v -> valToString(v))
+ .map(v -> pathEncode(v, pathParamsMetadata.allowReserved))
.collect(Collectors.toList())));
break;
case MAP:
@@ -156,17 +157,17 @@ public static String generateURL(Class type, String baseURL, String path,
pathParams.put(pathParamsMetadata.name,
String.join(",", map.entrySet().stream().map(e -> {
if (pathParamsMetadata.explode) {
- return String.format("%s=%s", valToString(e.getKey()),
- valToString(e.getValue()));
+ return String.format("%s=%s", pathEncode(valToString(e.getKey()), false),
+ pathEncode(valToString(e.getValue()), false));
} else {
- return String.format("%s,%s", valToString(e.getKey()),
- valToString(e.getValue()));
+ return String.format("%s,%s", pathEncode(valToString(e.getKey()), false),
+ pathEncode(valToString(e.getValue()), false));
}
}).collect(Collectors.toList())));
break;
case OBJECT:
if (!allowIntrospection(value.getClass())) {
- pathParams.put(pathParamsMetadata.name, valToString(value));
+ pathParams.put(pathParamsMetadata.name, pathEncode(valToString(value), pathParamsMetadata.allowReserved));
break;
}
List values = new ArrayList<>();
@@ -187,17 +188,17 @@ public static String generateURL(Class type, String baseURL, String path,
if (pathParamsMetadata.explode) {
values.add(String.format("%s=%s", valuePathParamsMetadata.name,
- valToString(val)));
+ pathEncode(valToString(val), valuePathParamsMetadata.allowReserved)));
} else {
values.add(String.format("%s,%s", valuePathParamsMetadata.name,
- valToString(val)));
+ pathEncode(valToString(val), valuePathParamsMetadata.allowReserved)));
}
}
pathParams.put(pathParamsMetadata.name, String.join(",", values));
break;
default:
- pathParams.put(pathParamsMetadata.name, valToString(value));
+ pathParams.put(pathParamsMetadata.name, pathEncode(valToString(value), pathParamsMetadata.allowReserved));
break;
}
}
@@ -206,6 +207,10 @@ public static String generateURL(Class type, String baseURL, String path,
return baseURL + templateUrl(path, pathParams);
}
+
+ private static String pathEncode(String s, boolean allowReserved) {
+ return Utf8UrlEncoder.allowReserved(allowReserved).encode(s);
+ }
public static boolean contentTypeMatches(String contentType, String pattern) {
if (contentType == null || contentType.isBlank()) {
@@ -256,7 +261,7 @@ public static SerializedBody serializeRequestBody(Object request, String request
return RequestBody.serialize(request, requestField, serializationMethod, nullable);
}
- public static List getQueryParams(Class type, Optional extends T> params,
+ public static List getQueryParams(Class type, Optional extends T> params,
Map>> globals) throws Exception {
if (params.isEmpty()) {
return Collections.emptyList();
@@ -265,7 +270,7 @@ public static List getQueryParams(Class typ
}
}
- public static List getQueryParams(Class type, JsonNullable extends T> params,
+ public static List getQueryParams(Class type, JsonNullable extends T> params,
Map>> globals) throws Exception {
if (!params.isPresent() || params.get() == null) {
return Collections.emptyList();
@@ -274,7 +279,7 @@ public static List getQueryParams(Class typ
}
}
- public static List getQueryParams(Class type, T params,
+ public static List getQueryParams(Class type, T params,
Map>> globals) throws Exception {
return QueryParameters.parseQueryParams(type, params, globals);
}
@@ -282,6 +287,8 @@ public static List getQueryParams(Class typ
public static HTTPRequest configureSecurity(HTTPRequest request, Object security) throws Exception {
return Security.configureSecurity(request, security);
}
+
+ private static final String DOLLAR_MARKER = "D9qPtyhOYzkHGu3c";
public static String templateUrl(String url, Map params) {
StringBuilder sb = new StringBuilder();
@@ -294,12 +301,16 @@ public static String templateUrl(String url, Map params) {
String key = match.substring(1, match.length() - 1);
String value = params.get(key);
if (value != null) {
- m.appendReplacement(sb, URLEncoder.encode(value, StandardCharsets.UTF_8));
+ // note that we replace $ characters in values with a marker
+ // and then replace the markers at the end with the $ characters
+ // because the presence of dollar signs can stuff up the next
+ // regex find
+ m.appendReplacement(sb, value.replace("$", DOLLAR_MARKER));
}
}
m.appendTail(sb);
- return sb.toString();
+ return sb.toString().replace(DOLLAR_MARKER, "$");
}
public static Map> getHeadersFromMetadata(Object headers, Map>> globals) throws Exception {
@@ -474,7 +485,7 @@ private static Map parseSerializedParams(PathParamsMetadata path
case "json":
ObjectMapper mapper = JSON.getMapper();
String json = mapper.writeValueAsString(value);
- params.put(pathParamsMetadata.name, json);
+ params.put(pathParamsMetadata.name, pathEncode(json, pathParamsMetadata.allowReserved));
break;
default:
break;
@@ -1167,18 +1178,18 @@ public static boolean isPresentAndNotNull(JsonNullable> x) {
return x.isPresent() && x.get() != null;
}
- private static final String OPEN_BRACKET_MARKER = UUID.randomUUID().toString().replace("-", "");
- private static final String CLOSE_BRACKET_MARKER = UUID.randomUUID().toString().replace("-", "");
-
- public static String urlEncode(String s) {
- // Ensure that complies with RFC 2732 (URLEncoder does not and we don't want to
- // encode [, ] chars)
- return URLEncoder.encode( //
- s.replace("[", OPEN_BRACKET_MARKER) //
- .replace("]", CLOSE_BRACKET_MARKER), //
- StandardCharsets.UTF_8) //
- .replace(OPEN_BRACKET_MARKER, "[") //
- .replace(CLOSE_BRACKET_MARKER, "]");
+ public static void setSseSentinel(Object o, String value) {
+ if (o == null || value.isBlank()) {
+ return;
+ } else {
+ try {
+ Field field = o.getClass().getDeclaredField("_eventSentinel");
+ field.setAccessible(true);
+ field.set(o, Optional.of(value));
+ } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
+ // ignore
+ }
+ }
}
}