QueryStringBuilder.java
/*
* #%L
* wcm.io
* %%
* Copyright (C) 2018 wcm.io
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package io.wcm.sling.commons.request;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.osgi.annotation.versioning.ProviderType;
import io.wcm.sling.commons.util.Escape;
/**
* Builds a property URL-encoded query string.
*/
@ProviderType
public final class QueryStringBuilder {
private static final String PARAM_SEPARATOR = "&";
private static final String VALUE_SEPARATOR = "=";
private final List<NameValuePair> params = new ArrayList<>();
/**
* Add parameter to query string.
* @param name Parameter name
* @param value Parameter value. Will be converted to string.
* If value is an array or {@link Iterable} the value items will be added as separate parameters.
* @return this
*/
@SuppressWarnings("unchecked")
public @NotNull QueryStringBuilder param(@NotNull String name, @Nullable Object value) {
if (value instanceof Iterable) {
Iterable<Object> valueItems = (Iterable)value;
for (Object valueItem : valueItems) {
params.add(new NameValuePair(name, valueItem));
}
}
else if (isArray(value)) {
int length = Array.getLength(value);
for (int i = 0; i < length; i++) {
Object valueItem = Array.get(value, i);
params.add(new NameValuePair(name, valueItem));
}
}
else {
params.add(new NameValuePair(name, value));
}
return this;
}
/**
* Add map of parameters to query string.
* @param values Map with parameter names and values. Values will be converted to strings.
* If a value is an array or {@link Iterable} the value items will be added as separate parameters.
* @return this
*/
public @NotNull QueryStringBuilder params(@NotNull Map<String, Object> values) {
for (Map.Entry<String, Object> entry : values.entrySet()) {
param(entry.getKey(), entry.getValue());
}
return this;
}
/**
* Build query string.
* @return Query string or null if query string contains no parameters at all.
*/
public @Nullable String build() {
StringBuilder queryString = new StringBuilder();
for (NameValuePair param : params) {
if (queryString.length() > 0) {
queryString.append(PARAM_SEPARATOR);
}
queryString.append(Escape.urlEncode(param.getName()))
.append(VALUE_SEPARATOR)
.append(Escape.urlEncode(param.getValue()));
}
if (queryString.length() > 0) {
return queryString.toString();
}
else {
return null;
}
}
private static boolean isArray(Object value) {
return value != null && value.getClass().isArray();
}
private static class NameValuePair {
private final String name;
private final String value;
NameValuePair(String name, Object value) {
this.name = name;
if (value != null) {
this.value = value.toString();
}
else {
this.value = "";
}
}
public String getName() {
return this.name;
}
public String getValue() {
return this.value;
}
}
}