Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 15 additions & 33 deletions src/main/java/com/stripe/net/FormEncoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static HttpContent createHttpContent(Map<String, Object> params) throws I
return HttpContent.buildFormURLEncodedContent(new ArrayList<KeyValuePair<String, String>>());
}

Collection<KeyValuePair<String, Object>> flatParams = flattenParams(params, false);
Collection<KeyValuePair<String, Object>> flatParams = flattenParams(params);

// If all parameters have been encoded as strings, then the content can be represented
// with application/x-www-form-url-encoded encoding. Otherwise, use
Expand All @@ -46,24 +46,12 @@ public static HttpContent createHttpContent(Map<String, Object> params) throws I
* @return The query string.
*/
public static String createQueryString(Map<String, Object> params) {
return FormEncoder.createQueryString(params, false);
}

/**
* Creates the HTTP query string for a given map of parameters.
*
* @param params The map of parameters.
* @param arraysAsRepeated Whether to encode arrays as repeated value ({@code a=1&a=2}) defaults
* to brackets encoding ({@code a[]=1,2}).
* @return The query string.
*/
public static String createQueryString(Map<String, Object> params, boolean arraysAsRepeated) {
if (params == null) {
return "";
}

Collection<KeyValuePair<String, String>> flatParams =
flattenParams(params, arraysAsRepeated).stream()
flattenParams(params).stream()
.filter(kvp -> kvp.getValue() instanceof String)
.map(kvp -> new KeyValuePair<String, String>(kvp.getKey(), (String) kvp.getValue()))
.collect(Collectors.toList());
Expand Down Expand Up @@ -117,13 +105,10 @@ public static String createQueryString(
* }</pre>
*
* @param params The map of parameters.
* @param arraysAsRepeated Whether to encode arrays as repeated value ({@code a=1&a=2}) defaults
* to brackets encoding ({@code a[]=1,2}).
* @return The flattened list of parameters.
*/
public static List<KeyValuePair<String, Object>> flattenParams(
Map<String, Object> params, boolean arraysAsRepeated) {
return flattenParamsValue(params, null, arraysAsRepeated);
public static List<KeyValuePair<String, Object>> flattenParams(Map<String, Object> params) {
return flattenParamsValue(params, null);
}

/**
Expand Down Expand Up @@ -157,12 +142,10 @@ private static String urlEncode(String value) {
*
* @param value The value for which to create the list of parameters.
* @param keyPrefix The key under which new keys should be nested, if any.
* @param arraysAsRepeated Whether to encode arrays as repeated value ({@code a=1&a=2}) defaults
* to brackets encoding ({@code a[]=1,2}).
* @return The list of parameters.
*/
private static List<KeyValuePair<String, Object>> flattenParamsValue(
Object value, String keyPrefix, boolean arraysAsRepeated) {
Object value, String keyPrefix) {
List<KeyValuePair<String, Object>> flatParams = null;

// I wish Java had pattern matching :(
Expand All @@ -171,7 +154,7 @@ private static List<KeyValuePair<String, Object>> flattenParamsValue(
flatParams = singleParam(keyPrefix, "");

} else if (value instanceof Map<?, ?>) {
flatParams = flattenParamsMap((Map<?, ?>) value, keyPrefix, arraysAsRepeated);
flatParams = flattenParamsMap((Map<?, ?>) value, keyPrefix);

} else if (value instanceof String) {
flatParams = singleParam(keyPrefix, value);
Expand All @@ -183,12 +166,12 @@ private static List<KeyValuePair<String, Object>> flattenParamsValue(
flatParams = singleParam(keyPrefix, value);

} else if (value instanceof Collection<?>) {
flatParams = flattenParamsCollection((Collection<?>) value, keyPrefix, arraysAsRepeated);
flatParams = flattenParamsCollection((Collection<?>) value, keyPrefix);

} else if (value.getClass().isArray()) {
Object[] array = getArrayForObject(value);
Collection<?> collection = Arrays.stream(array).collect(Collectors.toList());
flatParams = flattenParamsCollection(collection, keyPrefix, arraysAsRepeated);
flatParams = flattenParamsCollection(collection, keyPrefix);

} else if (value.getClass().isEnum()) {
flatParams =
Expand All @@ -211,7 +194,7 @@ private static List<KeyValuePair<String, Object>> flattenParamsValue(
* @return The list of parameters.
*/
private static List<KeyValuePair<String, Object>> flattenParamsMap(
Map<?, ?> map, String keyPrefix, boolean arraysAsRepeated) {
Map<?, ?> map, String keyPrefix) {
List<KeyValuePair<String, Object>> flatParams = new ArrayList<KeyValuePair<String, Object>>();
if (map == null) {
return flatParams;
Expand All @@ -223,7 +206,7 @@ private static List<KeyValuePair<String, Object>> flattenParamsMap(

String newPrefix = newPrefix(key, keyPrefix);

flatParams.addAll(flattenParamsValue(value, newPrefix, arraysAsRepeated));
flatParams.addAll(flattenParamsValue(value, newPrefix));
}

return flatParams;
Expand All @@ -236,28 +219,27 @@ private static List<KeyValuePair<String, Object>> flattenParamsMap(
*
* @param collection The collection for which to create the list of parameters.
* @param keyPrefix The key under which new keys should be nested.
* @param arraysAsRepeated Whether to encode arrays as repeated value ({@code a=1&a=2}) defaults
* to brackets encoding ({@code a[]=1,2}).
* @return The list of parameters.
*/
private static List<KeyValuePair<String, Object>> flattenParamsCollection(
Collection<?> collection, String keyPrefix, boolean arraysAsRepeated) {
Collection<?> collection, String keyPrefix) {
List<KeyValuePair<String, Object>> flatParams = new ArrayList<KeyValuePair<String, Object>>();
if (collection == null) {
return flatParams;
}

int index = 0;
for (Object value : collection) {
String newPrefix = arraysAsRepeated ? keyPrefix : String.format("%s[%d]", keyPrefix, index);
flatParams.addAll(flattenParamsValue(value, newPrefix, arraysAsRepeated));
// Always use indexed format for arrays
String newPrefix = String.format("%s[%d]", keyPrefix, index);
flatParams.addAll(flattenParamsValue(value, newPrefix));
index += 1;
}

/* Because application/x-www-form-urlencoded cannot represent an empty list, convention
* is to take the list parameter and just set it to an empty string. (E.g. A regular
* list might look like `a[0]=1&b[1]=2`. Emptying it would look like `a=`.) */
if (!arraysAsRepeated && flatParams.isEmpty()) {
if (flatParams.isEmpty()) {
flatParams.add(new KeyValuePair<String, Object>(keyPrefix, ""));
}

Expand Down
9 changes: 4 additions & 5 deletions src/main/java/com/stripe/net/StripeRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ private StripeRequest(
this.params = (params != null) ? Collections.unmodifiableMap(params) : null;
this.options = (options != null) ? options : RequestOptions.getDefault();
this.method = method;
this.url = buildURL(method, url, params, apiMode);
this.url = buildURL(method, url, params);
this.headers = buildHeaders(method, this.options, this.content, apiMode);
this.apiMode = apiMode;
} catch (IOException e) {
Expand Down Expand Up @@ -107,7 +107,7 @@ private StripeRequest(
this.params = (params != null) ? Collections.unmodifiableMap(params) : null;
this.options = options;
this.method = method;
this.url = buildURL(method, url, params, apiMode);
this.url = buildURL(method, url, params);
this.content = buildContent(method, params, apiMode);
this.headers = buildHeaders(method, this.options, this.content, apiMode);
this.apiMode = apiMode;
Expand Down Expand Up @@ -219,7 +219,7 @@ public StripeRequest withAdditionalHeader(String name, String value) {
}

private static URL buildURL(
ApiResource.RequestMethod method, String spec, Map<String, Object> params, ApiMode apiMode)
ApiResource.RequestMethod method, String spec, Map<String, Object> params)
throws IOException {
StringBuilder sb = new StringBuilder();

Expand All @@ -229,8 +229,7 @@ private static URL buildURL(
String specQueryString = specUrl.getQuery();

if ((method != ApiResource.RequestMethod.POST) && (params != null)) {
String queryString =
FormEncoder.createQueryString(params, apiMode == ApiMode.V2 ? true : false);
String queryString = FormEncoder.createQueryString(params);

if (queryString != null && !queryString.isEmpty()) {
if (specQueryString != null && !specQueryString.isEmpty()) {
Expand Down
20 changes: 6 additions & 14 deletions src/test/java/com/stripe/net/FormEncoderTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,8 @@
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import javax.annotation.Nullable;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.hamcrest.CoreMatchers;
import org.junit.jupiter.api.Test;

Expand Down Expand Up @@ -130,12 +128,10 @@ public void testCreateQueryString() {
org.junit.Assume.assumeTrue(!System.getProperty("java.version").startsWith("10."));

@Data
@RequiredArgsConstructor
@AllArgsConstructor
class TestCase {
private final Map<String, Object> data;
private final String want;
@Nullable private Boolean arrayAsRepeated = false;
}

List<TestCase> testCases =
Expand Down Expand Up @@ -376,18 +372,16 @@ class TestCase {
"array", new Object[] {new String[] {"foo", "bar"}, new int[] {1, 2, 3}}),
"array[0][0]=foo&array[0][1]=bar&array[1][0]=1&array[1][1]=2&array[1][2]=3"));

// Array (arrayAsRepeated)
add(new TestCase(Collections.singletonMap("array", new String[] {}), "", true));
// Array
add(new TestCase(Collections.singletonMap("array", new String[] {}), "array="));
add(
new TestCase(
Collections.singletonMap("array", new String[] {"1", "2", "3"}),
"array=1&array=2&array=3",
true));
"array[0]=1&array[1]=2&array[2]=3"));
add(
new TestCase(
Collections.singletonMap("array", new Object[] {123, "foo"}),
"array=123&array=foo",
true));
"array[0]=123&array[1]=foo"));
// Collection
add(
new TestCase(
Expand Down Expand Up @@ -429,9 +423,7 @@ class TestCase {
};

for (TestCase testCase : testCases) {
assertEquals(
testCase.getWant(),
FormEncoder.createQueryString(testCase.getData(), testCase.getArrayAsRepeated()));
assertEquals(testCase.getWant(), FormEncoder.createQueryString(testCase.getData()));
}
}

Expand Down Expand Up @@ -481,7 +473,7 @@ class TestCase {
};

for (TestCase testCase : testCases) {
assertEquals(testCase.getWant(), FormEncoder.flattenParams(testCase.getData(), false));
assertEquals(testCase.getWant(), FormEncoder.flattenParams(testCase.getData()));
}
}

Expand Down
Loading