See More

/* * Copyright © 2012 The Feign Authors ([email protected]) * * 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. */ package feign; import static feign.Util.checkState; import static feign.Util.emptyToNull; import feign.Request.HttpMethod; import java.lang.reflect.Parameter; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; public class DefaultContract extends DeclarativeContract { static final Pattern REQUEST_LINE_PATTERN = Pattern.compile("^([A-Z]+)[ ]*(.*)$"); public DefaultContract() { super.registerClassAnnotation( Headers.class, (header, data) -> { final String[] headersOnType = header.value(); checkState( headersOnType.length > 0, "Headers annotation was empty on type %s.", data.configKey()); final Map> headers = toMap(headersOnType); headers.putAll(data.template().headers()); data.template().headers(null); // to clear data.template().headers(headers); }); super.registerMethodAnnotation( RequestLine.class, (ann, data) -> { final String requestLine = ann.value(); checkState( emptyToNull(requestLine) != null, "RequestLine annotation was empty on method %s.", data.configKey()); final Matcher requestLineMatcher = REQUEST_LINE_PATTERN.matcher(requestLine); if (!requestLineMatcher.find()) { throw new IllegalStateException( String.format( "RequestLine annotation didn't start with an HTTP verb on method %s", data.configKey())); } else { data.template().method(HttpMethod.valueOf(requestLineMatcher.group(1))); data.template().uri(requestLineMatcher.group(2)); } data.template().decodeSlash(ann.decodeSlash()); data.template().collectionFormat(ann.collectionFormat()); }); super.registerMethodAnnotation( Body.class, (ann, data) -> { final String body = ann.value(); checkState( emptyToNull(body) != null, "Body annotation was empty on method %s.", data.configKey()); if (body.indexOf('{') == -1) { data.template().body(body); } else { data.template().bodyTemplate(body); } }); super.registerMethodAnnotation( Headers.class, (header, data) -> { final String[] headersOnMethod = header.value(); checkState( headersOnMethod.length > 0, "Headers annotation was empty on method %s.", data.configKey()); data.template().headers(toMap(headersOnMethod)); }); super.registerParameterAnnotation( Param.class, (paramAnnotation, data, paramIndex) -> { final String annotationName = paramAnnotation.value(); final Parameter parameter = data.method().getParameters()[paramIndex]; final String name; if (emptyToNull(annotationName) == null && parameter.isNamePresent()) { name = parameter.getName(); } else { name = annotationName; } checkState( emptyToNull(name) != null, "Param annotation was empty on param %s.\nHint: %s", paramIndex, "Prefer using @Param(value=\"name\"), or compile your code with the -parameters flag.\n" + "If the value is missing, Feign attempts to retrieve the parameter name from bytecode, " + "which only works if the class was compiled with the -parameters flag."); nameParam(data, name, paramIndex); final Class extends Param.Expander> expander = paramAnnotation.expander(); if (expander != Param.ToStringExpander.class) { data.indexToExpanderClass().put(paramIndex, expander); } if (!data.template().hasRequestVariable(name)) { data.formParams().add(name); } }); super.registerParameterAnnotation( QueryMap.class, (queryMap, data, paramIndex) -> { checkState( data.queryMapIndex() == null, "QueryMap annotation was present on multiple parameters."); data.queryMapIndex(paramIndex); data.queryMapEncoder(queryMap.mapEncoder().instance()); }); super.registerParameterAnnotation( HeaderMap.class, (queryMap, data, paramIndex) -> { checkState( data.headerMapIndex() == null, "HeaderMap annotation was present on multiple parameters."); data.headerMapIndex(paramIndex); }); } private static Map> toMap(String[] input) { final Map> result = new LinkedHashMap>(input.length); for (final String header : input) { final int colon = header.indexOf(':'); final String name = header.substring(0, colon); if (!result.containsKey(name)) { result.put(name, new ArrayList(1)); } result.get(name).add(header.substring(colon + 1).trim()); } return result; } }