/* * Copyright 2016 Netflix, Inc. * * 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 okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; import org.junit.Rule; import org.junit.Test; import org.springframework.beans.factory.BeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import static feign.assertj.MockWebServerAssertions.assertThat; public class ContractWithRuntimeInjectionTest { static class CaseExpander implements Param.Expander { private final boolean lowercase; CaseExpander() { this(false); } CaseExpander(boolean lowercase) { this.lowercase = lowercase; } @Override public String expand(Object value) { return lowercase ? value.toString().toLowerCase() : value.toString(); } } @Rule public final MockWebServer server = new MockWebServer(); interface TestExpander { @RequestLine("GET /path?query={query}") Response get(@Param(value = "query", expander = CaseExpander.class) String query); } @Test public void baseCaseExpanderNewInstance() throws InterruptedException { server.enqueue(new MockResponse()); String baseUrl = server.url("/default").toString(); Feign.builder().target(TestExpander.class, baseUrl).get("FOO"); assertThat(server.takeRequest()).hasPath("/default/path?query=FOO"); } @Configuration static class FeignConfiguration { @Bean CaseExpander lowercaseExpander() { return new CaseExpander(true); } @Bean Contract contract(BeanFactory beanFactory) { return new ContractWithRuntimeInjection(beanFactory); } } static class ContractWithRuntimeInjection extends Contract.Default { final BeanFactory beanFactory; ContractWithRuntimeInjection(BeanFactory beanFactory) { this.beanFactory = beanFactory; } /** * Injects {@link MethodMetadata#indexToExpander(Map)} via {@link BeanFactory#getBean(Class)}. */ @Override public List<MethodMetadata> parseAndValidatateMetadata(Class<?> targetType) { List<MethodMetadata> result = super.parseAndValidatateMetadata(targetType); for (MethodMetadata md : result) { Map<Integer, Param.Expander> indexToExpander = new LinkedHashMap<Integer, Param.Expander>(); for (Map.Entry<Integer, Class<? extends Param.Expander>> entry : md.indexToExpanderClass().entrySet()) { indexToExpander.put(entry.getKey(), beanFactory.getBean(entry.getValue())); } md.indexToExpander(indexToExpander); } return result; } } @Test public void contractWithRuntimeInjection() throws InterruptedException { server.enqueue(new MockResponse()); String baseUrl = server.url("/default").toString(); ApplicationContext context = new AnnotationConfigApplicationContext(FeignConfiguration.class); Feign.builder() .contract(context.getBean(Contract.class)) .target(TestExpander.class, baseUrl).get("FOO"); assertThat(server.takeRequest()).hasPath("/default/path?query=foo"); } }