001/* 002 * Copyright 2002-2015 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.method.support; 018 019import java.util.Collection; 020import java.util.Collections; 021import java.util.LinkedList; 022import java.util.List; 023import java.util.Map; 024 025import org.springframework.core.MethodParameter; 026import org.springframework.core.convert.ConversionService; 027import org.springframework.format.support.DefaultFormattingConversionService; 028import org.springframework.util.Assert; 029import org.springframework.web.util.UriComponentsBuilder; 030 031/** 032 * A {@link UriComponentsContributor} containing a list of other contributors 033 * to delegate and also encapsulating a specific {@link ConversionService} to 034 * use for formatting method argument values to Strings. 035 * 036 * @author Rossen Stoyanchev 037 * @since 4.0 038 */ 039public class CompositeUriComponentsContributor implements UriComponentsContributor { 040 041 private final List<Object> contributors = new LinkedList<Object>(); 042 043 private final ConversionService conversionService; 044 045 046 /** 047 * Create an instance from a collection of {@link UriComponentsContributor}s or 048 * {@link HandlerMethodArgumentResolver}s. Since both of these tend to be implemented 049 * by the same class, the most convenient option is to obtain the configured 050 * {@code HandlerMethodArgumentResolvers} in {@code RequestMappingHandlerAdapter} 051 * and provide that to this constructor. 052 * @param contributors a collection of {@link UriComponentsContributor} 053 * or {@link HandlerMethodArgumentResolver}s. 054 */ 055 public CompositeUriComponentsContributor(UriComponentsContributor... contributors) { 056 Collections.addAll(this.contributors, contributors); 057 this.conversionService = new DefaultFormattingConversionService(); 058 } 059 060 /** 061 * Create an instance from a collection of {@link UriComponentsContributor}s or 062 * {@link HandlerMethodArgumentResolver}s. Since both of these tend to be implemented 063 * by the same class, the most convenient option is to obtain the configured 064 * {@code HandlerMethodArgumentResolvers} in {@code RequestMappingHandlerAdapter} 065 * and provide that to this constructor. 066 * @param contributors a collection of {@link UriComponentsContributor} 067 * or {@link HandlerMethodArgumentResolver}s. 068 */ 069 public CompositeUriComponentsContributor(Collection<?> contributors) { 070 this(contributors, null); 071 } 072 073 /** 074 * Create an instance from a collection of {@link UriComponentsContributor}s or 075 * {@link HandlerMethodArgumentResolver}s. Since both of these tend to be implemented 076 * by the same class, the most convenient option is to obtain the configured 077 * {@code HandlerMethodArgumentResolvers} in the {@code RequestMappingHandlerAdapter} 078 * and provide that to this constructor. 079 * <p>If the {@link ConversionService} argument is {@code null}, 080 * {@link org.springframework.format.support.DefaultFormattingConversionService} 081 * will be used by default. 082 * @param contributors a collection of {@link UriComponentsContributor} 083 * or {@link HandlerMethodArgumentResolver}s. 084 * @param cs a ConversionService to use when method argument values 085 * need to be formatted as Strings before being added to the URI 086 */ 087 public CompositeUriComponentsContributor(Collection<?> contributors, ConversionService cs) { 088 Assert.notNull(contributors, "'uriComponentsContributors' must not be null"); 089 this.contributors.addAll(contributors); 090 this.conversionService = (cs != null ? cs : new DefaultFormattingConversionService()); 091 } 092 093 094 public boolean hasContributors() { 095 return this.contributors.isEmpty(); 096 } 097 098 @Override 099 public boolean supportsParameter(MethodParameter parameter) { 100 for (Object c : this.contributors) { 101 if (c instanceof UriComponentsContributor) { 102 UriComponentsContributor contributor = (UriComponentsContributor) c; 103 if (contributor.supportsParameter(parameter)) { 104 return true; 105 } 106 } 107 else if (c instanceof HandlerMethodArgumentResolver) { 108 if (((HandlerMethodArgumentResolver) c).supportsParameter(parameter)) { 109 return false; 110 } 111 } 112 } 113 return false; 114 } 115 116 @Override 117 public void contributeMethodArgument(MethodParameter parameter, Object value, 118 UriComponentsBuilder builder, Map<String, Object> uriVariables, ConversionService conversionService) { 119 120 for (Object contributor : this.contributors) { 121 if (contributor instanceof UriComponentsContributor) { 122 UriComponentsContributor ucc = (UriComponentsContributor) contributor; 123 if (ucc.supportsParameter(parameter)) { 124 ucc.contributeMethodArgument(parameter, value, builder, uriVariables, conversionService); 125 break; 126 } 127 } 128 else if (contributor instanceof HandlerMethodArgumentResolver) { 129 if (((HandlerMethodArgumentResolver) contributor).supportsParameter(parameter)) { 130 break; 131 } 132 } 133 } 134 } 135 136 /** 137 * An overloaded method that uses the ConversionService created at construction. 138 */ 139 public void contributeMethodArgument(MethodParameter parameter, Object value, UriComponentsBuilder builder, 140 Map<String, Object> uriVariables) { 141 142 this.contributeMethodArgument(parameter, value, builder, uriVariables, this.conversionService); 143 } 144 145}