values) {
if (values != null) {
return header(name, toArray(values, String.class));
}
return header(name, (String[]) null);
}
/**
* Replaces all existing headers with the newly supplied headers.
relationship to
* JAXRS 2.0
Like {@code Invocation.Builder.headers(MultivaluedMap)}, except the
* values can be templatized.
ex.
*
* template.headers(mapOf("X-Application-Version", asList("{version}")));
*
*
* @param headers if null, remove all headers. else value to replace all headers with.
* @see #headers()
*/
public RequestTemplate headers(Map> headers) {
if (headers == null || headers.isEmpty()) {
this.headers.clear();
} else {
this.headers.putAll(headers);
}
return this;
}
/**
* Returns an immutable copy of the current headers.
*
* @see Request#headers()
*/
public Map> headers() {
return Collections.unmodifiableMap(headers);
}
/**
* replaces the {@link feign.Util#CONTENT_LENGTH} header.
Usually populated by an {@link
* feign.codec.Encoder}.
*
* @see Request#body()
*/
public RequestTemplate body(byte[] bodyData, Charset charset) {
this.bodyTemplate = null;
this.charset = charset;
this.body = bodyData;
int bodyLength = bodyData != null ? bodyData.length : 0;
header(CONTENT_LENGTH, String.valueOf(bodyLength));
return this;
}
/**
* replaces the {@link feign.Util#CONTENT_LENGTH} header.
Usually populated by an {@link
* feign.codec.Encoder}.
*
* @see Request#body()
*/
public RequestTemplate body(String bodyText) {
byte[] bodyData = bodyText != null ? bodyText.getBytes(UTF_8) : null;
return body(bodyData, UTF_8);
}
/**
* The character set with which the body is encoded, or null if unknown or not applicable. When
* this is present, you can use {@code new String(req.body(), req.charset())} to access the body
* as a String.
*/
public Charset charset() {
return charset;
}
/**
* @see Request#body()
*/
public byte[] body() {
return body;
}
/**
* populated by {@link Body}
*
* @see Request#body()
*/
public RequestTemplate bodyTemplate(String bodyTemplate) {
this.bodyTemplate = bodyTemplate;
this.charset = null;
this.body = null;
return this;
}
/**
* @see Request#body()
* @see #expand(String, Map)
*/
public String bodyTemplate() {
return bodyTemplate;
}
/**
* if there are any query params in the URL, this will extract them out.
*/
private StringBuilder pullAnyQueriesOutOfUrl(StringBuilder url) {
// parse out queries
int queryIndex = url.indexOf("?");
if (queryIndex != -1) {
String queryLine = url.substring(queryIndex + 1);
Map> firstQueries = parseAndDecodeQueries(queryLine);
if (!queries.isEmpty()) {
firstQueries.putAll(queries);
queries.clear();
}
//Since we decode all queries, we want to use the
//query()-method to re-add them to ensure that all
//logic (such as url-encoding) are executed, giving
//a valid queryLine()
for (String key : firstQueries.keySet()) {
Collection values = firstQueries.get(key);
if (allValuesAreNull(values)) {
//Queries where all values are null will
//be ignored by the query(key, value)-method
//So we manually avoid this case here, to ensure that
//we still fulfill the contract (ex. parameters without values)
queries.put(urlEncode(key), values);
} else {
query(key, values);
}
}
return new StringBuilder(url.substring(0, queryIndex));
}
return url;
}
private boolean allValuesAreNull(Collection values) {
if (values == null || values.isEmpty()) {
return true;
}
for (String val : values) {
if (val != null) {
return false;
}
}
return true;
}
@Override
public String toString() {
return request().toString();
}
/**
* Replaces query values which are templated with corresponding values from the {@code unencoded}
* map. Any unresolved queries are removed.
*/
public void replaceQueryValues(Map unencoded) {
Iterator>> iterator = queries.entrySet().iterator();
while (iterator.hasNext()) {
Entry> entry = iterator.next();
if (entry.getValue() == null) {
continue;
}
Collection values = new ArrayList();
for (String value : entry.getValue()) {
if (value.indexOf('{') == 0 && value.indexOf('}') == value.length() - 1) {
Object variableValue = unencoded.get(value.substring(1, value.length() - 1));
// only add non-null expressions
if (variableValue == null) {
continue;
}
if (variableValue instanceof Iterable) {
for (Object val : Iterable.class.cast(variableValue)) {
values.add(urlEncode(String.valueOf(val)));
}
} else {
values.add(urlEncode(String.valueOf(variableValue)));
}
} else {
values.add(value);
}
}
if (values.isEmpty()) {
iterator.remove();
} else {
entry.setValue(values);
}
}
}
public String queryLine() {
if (queries.isEmpty()) {
return "";
}
StringBuilder queryBuilder = new StringBuilder();
for (String field : queries.keySet()) {
for (String value : valuesOrEmpty(queries, field)) {
queryBuilder.append('&');
queryBuilder.append(field);
if (value != null) {
queryBuilder.append('=');
if (!value.isEmpty()) {
queryBuilder.append(value);
}
}
}
}
queryBuilder.deleteCharAt(0);
return queryBuilder.insert(0, '?').toString();
}
interface Factory {
/**
* create a request template using args passed to a method invocation.
*/
RequestTemplate create(Object[] argv);
}
}