001/* 002 * Copyright 2002-2020 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.servlet.mvc.method; 018 019import java.util.List; 020import java.util.Set; 021 022import javax.servlet.http.HttpServletRequest; 023 024import org.springframework.http.HttpMethod; 025import org.springframework.lang.Nullable; 026import org.springframework.util.ObjectUtils; 027import org.springframework.util.PathMatcher; 028import org.springframework.util.StringUtils; 029import org.springframework.web.accept.ContentNegotiationManager; 030import org.springframework.web.bind.annotation.RequestMethod; 031import org.springframework.web.servlet.mvc.condition.ConsumesRequestCondition; 032import org.springframework.web.servlet.mvc.condition.HeadersRequestCondition; 033import org.springframework.web.servlet.mvc.condition.ParamsRequestCondition; 034import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition; 035import org.springframework.web.servlet.mvc.condition.ProducesRequestCondition; 036import org.springframework.web.servlet.mvc.condition.RequestCondition; 037import org.springframework.web.servlet.mvc.condition.RequestConditionHolder; 038import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition; 039import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; 040import org.springframework.web.util.UrlPathHelper; 041 042/** 043 * Request mapping information. Encapsulates the following request mapping conditions: 044 * <ol> 045 * <li>{@link PatternsRequestCondition} 046 * <li>{@link RequestMethodsRequestCondition} 047 * <li>{@link ParamsRequestCondition} 048 * <li>{@link HeadersRequestCondition} 049 * <li>{@link ConsumesRequestCondition} 050 * <li>{@link ProducesRequestCondition} 051 * <li>{@code RequestCondition} (optional, custom request condition) 052 * </ol> 053 * 054 * @author Arjen Poutsma 055 * @author Rossen Stoyanchev 056 * @since 3.1 057 */ 058public final class RequestMappingInfo implements RequestCondition<RequestMappingInfo> { 059 060 private static final PatternsRequestCondition EMPTY_PATTERNS = new PatternsRequestCondition(); 061 062 private static final RequestMethodsRequestCondition EMPTY_REQUEST_METHODS = new RequestMethodsRequestCondition(); 063 064 private static final ParamsRequestCondition EMPTY_PARAMS = new ParamsRequestCondition(); 065 066 private static final HeadersRequestCondition EMPTY_HEADERS = new HeadersRequestCondition(); 067 068 private static final ConsumesRequestCondition EMPTY_CONSUMES = new ConsumesRequestCondition(); 069 070 private static final ProducesRequestCondition EMPTY_PRODUCES = new ProducesRequestCondition(); 071 072 private static final RequestConditionHolder EMPTY_CUSTOM = new RequestConditionHolder(null); 073 074 075 @Nullable 076 private final String name; 077 078 private final PatternsRequestCondition patternsCondition; 079 080 private final RequestMethodsRequestCondition methodsCondition; 081 082 private final ParamsRequestCondition paramsCondition; 083 084 private final HeadersRequestCondition headersCondition; 085 086 private final ConsumesRequestCondition consumesCondition; 087 088 private final ProducesRequestCondition producesCondition; 089 090 private final RequestConditionHolder customConditionHolder; 091 092 private final int hashCode; 093 094 095 public RequestMappingInfo(@Nullable String name, @Nullable PatternsRequestCondition patterns, 096 @Nullable RequestMethodsRequestCondition methods, @Nullable ParamsRequestCondition params, 097 @Nullable HeadersRequestCondition headers, @Nullable ConsumesRequestCondition consumes, 098 @Nullable ProducesRequestCondition produces, @Nullable RequestCondition<?> custom) { 099 100 this.name = (StringUtils.hasText(name) ? name : null); 101 this.patternsCondition = (patterns != null ? patterns : EMPTY_PATTERNS); 102 this.methodsCondition = (methods != null ? methods : EMPTY_REQUEST_METHODS); 103 this.paramsCondition = (params != null ? params : EMPTY_PARAMS); 104 this.headersCondition = (headers != null ? headers : EMPTY_HEADERS); 105 this.consumesCondition = (consumes != null ? consumes : EMPTY_CONSUMES); 106 this.producesCondition = (produces != null ? produces : EMPTY_PRODUCES); 107 this.customConditionHolder = (custom != null ? new RequestConditionHolder(custom) : EMPTY_CUSTOM); 108 109 this.hashCode = calculateHashCode( 110 this.patternsCondition, this.methodsCondition, this.paramsCondition, this.headersCondition, 111 this.consumesCondition, this.producesCondition, this.customConditionHolder); 112 } 113 114 /** 115 * Creates a new instance with the given request conditions. 116 */ 117 public RequestMappingInfo(@Nullable PatternsRequestCondition patterns, 118 @Nullable RequestMethodsRequestCondition methods, @Nullable ParamsRequestCondition params, 119 @Nullable HeadersRequestCondition headers, @Nullable ConsumesRequestCondition consumes, 120 @Nullable ProducesRequestCondition produces, @Nullable RequestCondition<?> custom) { 121 122 this(null, patterns, methods, params, headers, consumes, produces, custom); 123 } 124 125 /** 126 * Re-create a RequestMappingInfo with the given custom request condition. 127 */ 128 public RequestMappingInfo(RequestMappingInfo info, @Nullable RequestCondition<?> customRequestCondition) { 129 this(info.name, info.patternsCondition, info.methodsCondition, info.paramsCondition, info.headersCondition, 130 info.consumesCondition, info.producesCondition, customRequestCondition); 131 } 132 133 /** 134 * Return the name for this mapping, or {@code null}. 135 */ 136 @Nullable 137 public String getName() { 138 return this.name; 139 } 140 141 /** 142 * Return the URL patterns of this {@link RequestMappingInfo}; 143 * or instance with 0 patterns (never {@code null}). 144 */ 145 public PatternsRequestCondition getPatternsCondition() { 146 return this.patternsCondition; 147 } 148 149 /** 150 * Return the HTTP request methods of this {@link RequestMappingInfo}; 151 * or instance with 0 request methods (never {@code null}). 152 */ 153 public RequestMethodsRequestCondition getMethodsCondition() { 154 return this.methodsCondition; 155 } 156 157 /** 158 * Return the "parameters" condition of this {@link RequestMappingInfo}; 159 * or instance with 0 parameter expressions (never {@code null}). 160 */ 161 public ParamsRequestCondition getParamsCondition() { 162 return this.paramsCondition; 163 } 164 165 /** 166 * Return the "headers" condition of this {@link RequestMappingInfo}; 167 * or instance with 0 header expressions (never {@code null}). 168 */ 169 public HeadersRequestCondition getHeadersCondition() { 170 return this.headersCondition; 171 } 172 173 /** 174 * Return the "consumes" condition of this {@link RequestMappingInfo}; 175 * or instance with 0 consumes expressions (never {@code null}). 176 */ 177 public ConsumesRequestCondition getConsumesCondition() { 178 return this.consumesCondition; 179 } 180 181 /** 182 * Return the "produces" condition of this {@link RequestMappingInfo}; 183 * or instance with 0 produces expressions (never {@code null}). 184 */ 185 public ProducesRequestCondition getProducesCondition() { 186 return this.producesCondition; 187 } 188 189 /** 190 * Return the "custom" condition of this {@link RequestMappingInfo}, or {@code null}. 191 */ 192 @Nullable 193 public RequestCondition<?> getCustomCondition() { 194 return this.customConditionHolder.getCondition(); 195 } 196 197 198 /** 199 * Combine "this" request mapping info (i.e. the current instance) with another request mapping info instance. 200 * <p>Example: combine type- and method-level request mappings. 201 * @return a new request mapping info instance; never {@code null} 202 */ 203 @Override 204 public RequestMappingInfo combine(RequestMappingInfo other) { 205 String name = combineNames(other); 206 PatternsRequestCondition patterns = this.patternsCondition.combine(other.patternsCondition); 207 RequestMethodsRequestCondition methods = this.methodsCondition.combine(other.methodsCondition); 208 ParamsRequestCondition params = this.paramsCondition.combine(other.paramsCondition); 209 HeadersRequestCondition headers = this.headersCondition.combine(other.headersCondition); 210 ConsumesRequestCondition consumes = this.consumesCondition.combine(other.consumesCondition); 211 ProducesRequestCondition produces = this.producesCondition.combine(other.producesCondition); 212 RequestConditionHolder custom = this.customConditionHolder.combine(other.customConditionHolder); 213 214 return new RequestMappingInfo(name, patterns, 215 methods, params, headers, consumes, produces, custom.getCondition()); 216 } 217 218 @Nullable 219 private String combineNames(RequestMappingInfo other) { 220 if (this.name != null && other.name != null) { 221 String separator = RequestMappingInfoHandlerMethodMappingNamingStrategy.SEPARATOR; 222 return this.name + separator + other.name; 223 } 224 else if (this.name != null) { 225 return this.name; 226 } 227 else { 228 return other.name; 229 } 230 } 231 232 /** 233 * Checks if all conditions in this request mapping info match the provided request and returns 234 * a potentially new request mapping info with conditions tailored to the current request. 235 * <p>For example the returned instance may contain the subset of URL patterns that match to 236 * the current request, sorted with best matching patterns on top. 237 * @return a new instance in case all conditions match; or {@code null} otherwise 238 */ 239 @Override 240 @Nullable 241 public RequestMappingInfo getMatchingCondition(HttpServletRequest request) { 242 RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request); 243 if (methods == null) { 244 return null; 245 } 246 ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request); 247 if (params == null) { 248 return null; 249 } 250 HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request); 251 if (headers == null) { 252 return null; 253 } 254 ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request); 255 if (consumes == null) { 256 return null; 257 } 258 ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request); 259 if (produces == null) { 260 return null; 261 } 262 PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request); 263 if (patterns == null) { 264 return null; 265 } 266 RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request); 267 if (custom == null) { 268 return null; 269 } 270 271 return new RequestMappingInfo(this.name, patterns, 272 methods, params, headers, consumes, produces, custom.getCondition()); 273 } 274 275 /** 276 * Compares "this" info (i.e. the current instance) with another info in the context of a request. 277 * <p>Note: It is assumed both instances have been obtained via 278 * {@link #getMatchingCondition(HttpServletRequest)} to ensure they have conditions with 279 * content relevant to current request. 280 */ 281 @Override 282 public int compareTo(RequestMappingInfo other, HttpServletRequest request) { 283 int result; 284 // Automatic vs explicit HTTP HEAD mapping 285 if (HttpMethod.HEAD.matches(request.getMethod())) { 286 result = this.methodsCondition.compareTo(other.getMethodsCondition(), request); 287 if (result != 0) { 288 return result; 289 } 290 } 291 result = this.patternsCondition.compareTo(other.getPatternsCondition(), request); 292 if (result != 0) { 293 return result; 294 } 295 result = this.paramsCondition.compareTo(other.getParamsCondition(), request); 296 if (result != 0) { 297 return result; 298 } 299 result = this.headersCondition.compareTo(other.getHeadersCondition(), request); 300 if (result != 0) { 301 return result; 302 } 303 result = this.consumesCondition.compareTo(other.getConsumesCondition(), request); 304 if (result != 0) { 305 return result; 306 } 307 result = this.producesCondition.compareTo(other.getProducesCondition(), request); 308 if (result != 0) { 309 return result; 310 } 311 // Implicit (no method) vs explicit HTTP method mappings 312 result = this.methodsCondition.compareTo(other.getMethodsCondition(), request); 313 if (result != 0) { 314 return result; 315 } 316 result = this.customConditionHolder.compareTo(other.customConditionHolder, request); 317 if (result != 0) { 318 return result; 319 } 320 return 0; 321 } 322 323 @Override 324 public boolean equals(@Nullable Object other) { 325 if (this == other) { 326 return true; 327 } 328 if (!(other instanceof RequestMappingInfo)) { 329 return false; 330 } 331 RequestMappingInfo otherInfo = (RequestMappingInfo) other; 332 return (this.patternsCondition.equals(otherInfo.patternsCondition) && 333 this.methodsCondition.equals(otherInfo.methodsCondition) && 334 this.paramsCondition.equals(otherInfo.paramsCondition) && 335 this.headersCondition.equals(otherInfo.headersCondition) && 336 this.consumesCondition.equals(otherInfo.consumesCondition) && 337 this.producesCondition.equals(otherInfo.producesCondition) && 338 this.customConditionHolder.equals(otherInfo.customConditionHolder)); 339 } 340 341 @Override 342 public int hashCode() { 343 return this.hashCode; 344 } 345 346 private static int calculateHashCode( 347 PatternsRequestCondition patterns, RequestMethodsRequestCondition methods, 348 ParamsRequestCondition params, HeadersRequestCondition headers, 349 ConsumesRequestCondition consumes, ProducesRequestCondition produces, 350 RequestConditionHolder custom) { 351 352 return patterns.hashCode() * 31 + methods.hashCode() + params.hashCode() + 353 headers.hashCode() + consumes.hashCode() + produces.hashCode() + custom.hashCode(); 354 } 355 356 @Override 357 public String toString() { 358 StringBuilder builder = new StringBuilder("{"); 359 if (!this.methodsCondition.isEmpty()) { 360 Set<RequestMethod> httpMethods = this.methodsCondition.getMethods(); 361 builder.append(httpMethods.size() == 1 ? httpMethods.iterator().next() : httpMethods); 362 } 363 if (!this.patternsCondition.isEmpty()) { 364 Set<String> patterns = this.patternsCondition.getPatterns(); 365 builder.append(" ").append(patterns.size() == 1 ? patterns.iterator().next() : patterns); 366 } 367 if (!this.paramsCondition.isEmpty()) { 368 builder.append(", params ").append(this.paramsCondition); 369 } 370 if (!this.headersCondition.isEmpty()) { 371 builder.append(", headers ").append(this.headersCondition); 372 } 373 if (!this.consumesCondition.isEmpty()) { 374 builder.append(", consumes ").append(this.consumesCondition); 375 } 376 if (!this.producesCondition.isEmpty()) { 377 builder.append(", produces ").append(this.producesCondition); 378 } 379 if (!this.customConditionHolder.isEmpty()) { 380 builder.append(", and ").append(this.customConditionHolder); 381 } 382 builder.append('}'); 383 return builder.toString(); 384 } 385 386 387 /** 388 * Create a new {@code RequestMappingInfo.Builder} with the given paths. 389 * @param paths the paths to use 390 * @since 4.2 391 */ 392 public static Builder paths(String... paths) { 393 return new DefaultBuilder(paths); 394 } 395 396 397 /** 398 * Defines a builder for creating a RequestMappingInfo. 399 * @since 4.2 400 */ 401 public interface Builder { 402 403 /** 404 * Set the path patterns. 405 */ 406 Builder paths(String... paths); 407 408 /** 409 * Set the request method conditions. 410 */ 411 Builder methods(RequestMethod... methods); 412 413 /** 414 * Set the request param conditions. 415 */ 416 Builder params(String... params); 417 418 /** 419 * Set the header conditions. 420 * <p>By default this is not set. 421 */ 422 Builder headers(String... headers); 423 424 /** 425 * Set the consumes conditions. 426 */ 427 Builder consumes(String... consumes); 428 429 /** 430 * Set the produces conditions. 431 */ 432 Builder produces(String... produces); 433 434 /** 435 * Set the mapping name. 436 */ 437 Builder mappingName(String name); 438 439 /** 440 * Set a custom condition to use. 441 */ 442 Builder customCondition(RequestCondition<?> condition); 443 444 /** 445 * Provide additional configuration needed for request mapping purposes. 446 */ 447 Builder options(BuilderConfiguration options); 448 449 /** 450 * Build the RequestMappingInfo. 451 */ 452 RequestMappingInfo build(); 453 } 454 455 456 private static class DefaultBuilder implements Builder { 457 458 private String[] paths; 459 460 private RequestMethod[] methods = new RequestMethod[0]; 461 462 private String[] params = new String[0]; 463 464 private String[] headers = new String[0]; 465 466 private String[] consumes = new String[0]; 467 468 private String[] produces = new String[0]; 469 470 private boolean hasContentType; 471 472 private boolean hasAccept; 473 474 @Nullable 475 private String mappingName; 476 477 @Nullable 478 private RequestCondition<?> customCondition; 479 480 private BuilderConfiguration options = new BuilderConfiguration(); 481 482 public DefaultBuilder(String... paths) { 483 this.paths = paths; 484 } 485 486 @Override 487 public Builder paths(String... paths) { 488 this.paths = paths; 489 return this; 490 } 491 492 @Override 493 public DefaultBuilder methods(RequestMethod... methods) { 494 this.methods = methods; 495 return this; 496 } 497 498 @Override 499 public DefaultBuilder params(String... params) { 500 this.params = params; 501 return this; 502 } 503 504 @Override 505 public DefaultBuilder headers(String... headers) { 506 for (String header : headers) { 507 this.hasContentType = this.hasContentType || 508 header.contains("Content-Type") || header.contains("content-type"); 509 this.hasAccept = this.hasAccept || 510 header.contains("Accept") || header.contains("accept"); 511 } 512 this.headers = headers; 513 return this; 514 } 515 516 @Override 517 public DefaultBuilder consumes(String... consumes) { 518 this.consumes = consumes; 519 return this; 520 } 521 522 @Override 523 public DefaultBuilder produces(String... produces) { 524 this.produces = produces; 525 return this; 526 } 527 528 @Override 529 public DefaultBuilder mappingName(String name) { 530 this.mappingName = name; 531 return this; 532 } 533 534 @Override 535 public DefaultBuilder customCondition(RequestCondition<?> condition) { 536 this.customCondition = condition; 537 return this; 538 } 539 540 @Override 541 public Builder options(BuilderConfiguration options) { 542 this.options = options; 543 return this; 544 } 545 546 @Override 547 @SuppressWarnings("deprecation") 548 public RequestMappingInfo build() { 549 550 PatternsRequestCondition patternsCondition = ObjectUtils.isEmpty(this.paths) ? null : 551 new PatternsRequestCondition( 552 this.paths, this.options.getUrlPathHelper(), this.options.getPathMatcher(), 553 this.options.useSuffixPatternMatch(), this.options.useTrailingSlashMatch(), 554 this.options.getFileExtensions()); 555 556 ContentNegotiationManager manager = this.options.getContentNegotiationManager(); 557 558 return new RequestMappingInfo(this.mappingName, patternsCondition, 559 ObjectUtils.isEmpty(this.methods) ? 560 null : new RequestMethodsRequestCondition(this.methods), 561 ObjectUtils.isEmpty(this.params) ? 562 null : new ParamsRequestCondition(this.params), 563 ObjectUtils.isEmpty(this.headers) ? 564 null : new HeadersRequestCondition(this.headers), 565 ObjectUtils.isEmpty(this.consumes) && !this.hasContentType ? 566 null : new ConsumesRequestCondition(this.consumes, this.headers), 567 ObjectUtils.isEmpty(this.produces) && !this.hasAccept ? 568 null : new ProducesRequestCondition(this.produces, this.headers, manager), 569 this.customCondition); 570 } 571 } 572 573 574 /** 575 * Container for configuration options used for request mapping purposes. 576 * Such configuration is required to create RequestMappingInfo instances but 577 * is typically used across all RequestMappingInfo instances. 578 * @since 4.2 579 * @see Builder#options 580 */ 581 public static class BuilderConfiguration { 582 583 @Nullable 584 private UrlPathHelper urlPathHelper; 585 586 @Nullable 587 private PathMatcher pathMatcher; 588 589 private boolean trailingSlashMatch = true; 590 591 private boolean suffixPatternMatch = true; 592 593 private boolean registeredSuffixPatternMatch = false; 594 595 @Nullable 596 private ContentNegotiationManager contentNegotiationManager; 597 598 /** 599 * Set a custom UrlPathHelper to use for the PatternsRequestCondition. 600 * <p>By default this is not set. 601 * @since 4.2.8 602 */ 603 public void setUrlPathHelper(@Nullable UrlPathHelper urlPathHelper) { 604 this.urlPathHelper = urlPathHelper; 605 } 606 607 /** 608 * Return a custom UrlPathHelper to use for the PatternsRequestCondition, if any. 609 */ 610 @Nullable 611 public UrlPathHelper getUrlPathHelper() { 612 return this.urlPathHelper; 613 } 614 615 /** 616 * Set a custom PathMatcher to use for the PatternsRequestCondition. 617 * <p>By default this is not set. 618 */ 619 public void setPathMatcher(@Nullable PathMatcher pathMatcher) { 620 this.pathMatcher = pathMatcher; 621 } 622 623 /** 624 * Return a custom PathMatcher to use for the PatternsRequestCondition, if any. 625 */ 626 @Nullable 627 public PathMatcher getPathMatcher() { 628 return this.pathMatcher; 629 } 630 631 /** 632 * Set whether to apply trailing slash matching in PatternsRequestCondition. 633 * <p>By default this is set to 'true'. 634 */ 635 public void setTrailingSlashMatch(boolean trailingSlashMatch) { 636 this.trailingSlashMatch = trailingSlashMatch; 637 } 638 639 /** 640 * Return whether to apply trailing slash matching in PatternsRequestCondition. 641 */ 642 public boolean useTrailingSlashMatch() { 643 return this.trailingSlashMatch; 644 } 645 646 /** 647 * Set whether to apply suffix pattern matching in PatternsRequestCondition. 648 * <p>By default this is set to 'true'. 649 * @see #setRegisteredSuffixPatternMatch(boolean) 650 * @deprecated as of 5.2.4. See class-level note in 651 * {@link RequestMappingHandlerMapping} on the deprecation of path 652 * extension config options. 653 */ 654 @Deprecated 655 public void setSuffixPatternMatch(boolean suffixPatternMatch) { 656 this.suffixPatternMatch = suffixPatternMatch; 657 } 658 659 /** 660 * Return whether to apply suffix pattern matching in PatternsRequestCondition. 661 * @deprecated as of 5.2.4. See class-level note in 662 * {@link RequestMappingHandlerMapping} on the deprecation of path 663 * extension config options. 664 */ 665 @Deprecated 666 public boolean useSuffixPatternMatch() { 667 return this.suffixPatternMatch; 668 } 669 670 /** 671 * Set whether suffix pattern matching should be restricted to registered 672 * file extensions only. Setting this property also sets 673 * {@code suffixPatternMatch=true} and requires that a 674 * {@link #setContentNegotiationManager} is also configured in order to 675 * obtain the registered file extensions. 676 * @deprecated as of 5.2.4. See class-level note in 677 * {@link RequestMappingHandlerMapping} on the deprecation of path 678 * extension config options; note also that in 5.3 the default for this 679 * property switches from {@code false} to {@code true}. 680 */ 681 @Deprecated 682 public void setRegisteredSuffixPatternMatch(boolean registeredSuffixPatternMatch) { 683 this.registeredSuffixPatternMatch = registeredSuffixPatternMatch; 684 this.suffixPatternMatch = (registeredSuffixPatternMatch || this.suffixPatternMatch); 685 } 686 687 /** 688 * Return whether suffix pattern matching should be restricted to registered 689 * file extensions only. 690 * @deprecated as of 5.2.4. See class-level note in 691 * {@link RequestMappingHandlerMapping} on the deprecation of path 692 * extension config options. 693 */ 694 @Deprecated 695 public boolean useRegisteredSuffixPatternMatch() { 696 return this.registeredSuffixPatternMatch; 697 } 698 699 /** 700 * Return the file extensions to use for suffix pattern matching. If 701 * {@code registeredSuffixPatternMatch=true}, the extensions are obtained 702 * from the configured {@code contentNegotiationManager}. 703 * @deprecated as of 5.2.4. See class-level note in 704 * {@link RequestMappingHandlerMapping} on the deprecation of path 705 * extension config options. 706 */ 707 @Nullable 708 @Deprecated 709 public List<String> getFileExtensions() { 710 if (useRegisteredSuffixPatternMatch() && this.contentNegotiationManager != null) { 711 return this.contentNegotiationManager.getAllFileExtensions(); 712 } 713 return null; 714 } 715 716 /** 717 * Set the ContentNegotiationManager to use for the ProducesRequestCondition. 718 * <p>By default this is not set. 719 */ 720 public void setContentNegotiationManager(ContentNegotiationManager contentNegotiationManager) { 721 this.contentNegotiationManager = contentNegotiationManager; 722 } 723 724 /** 725 * Return the ContentNegotiationManager to use for the ProducesRequestCondition, 726 * if any. 727 */ 728 @Nullable 729 public ContentNegotiationManager getContentNegotiationManager() { 730 return this.contentNegotiationManager; 731 } 732 } 733 734}