001/* 002 * Copyright 2002-2017 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.accept; 018 019import java.util.Collections; 020import java.util.List; 021import java.util.Map; 022 023import org.springframework.http.MediaType; 024import org.springframework.util.StringUtils; 025import org.springframework.web.HttpMediaTypeNotAcceptableException; 026import org.springframework.web.context.request.NativeWebRequest; 027 028/** 029 * Base class for {@code ContentNegotiationStrategy} implementations with the 030 * steps to resolve a request to media types. 031 * 032 * <p>First a key (e.g. "json", "pdf") must be extracted from the request (e.g. 033 * file extension, query param). The key must then be resolved to media type(s) 034 * through the base class {@link MappingMediaTypeFileExtensionResolver} which 035 * stores such mappings. 036 * 037 * <p>The method {@link #handleNoMatch} allow sub-classes to plug in additional 038 * ways of looking up media types (e.g. through the Java Activation framework, 039 * or {@link javax.servlet.ServletContext#getMimeType}. Media types resolved 040 * via base classes are then added to the base class 041 * {@link MappingMediaTypeFileExtensionResolver}, i.e. cached for new lookups. 042 * 043 * @author Rossen Stoyanchev 044 * @since 3.2 045 */ 046public abstract class AbstractMappingContentNegotiationStrategy extends MappingMediaTypeFileExtensionResolver 047 implements ContentNegotiationStrategy { 048 049 /** 050 * Create an instance with the given map of file extensions and media types. 051 */ 052 public AbstractMappingContentNegotiationStrategy(Map<String, MediaType> mediaTypes) { 053 super(mediaTypes); 054 } 055 056 057 @Override 058 public List<MediaType> resolveMediaTypes(NativeWebRequest webRequest) 059 throws HttpMediaTypeNotAcceptableException { 060 061 return resolveMediaTypeKey(webRequest, getMediaTypeKey(webRequest)); 062 } 063 064 /** 065 * An alternative to {@link #resolveMediaTypes(NativeWebRequest)} that accepts 066 * an already extracted key. 067 * @since 3.2.16 068 */ 069 public List<MediaType> resolveMediaTypeKey(NativeWebRequest webRequest, String key) 070 throws HttpMediaTypeNotAcceptableException { 071 072 if (StringUtils.hasText(key)) { 073 MediaType mediaType = lookupMediaType(key); 074 if (mediaType != null) { 075 handleMatch(key, mediaType); 076 return Collections.singletonList(mediaType); 077 } 078 mediaType = handleNoMatch(webRequest, key); 079 if (mediaType != null) { 080 addMapping(key, mediaType); 081 return Collections.singletonList(mediaType); 082 } 083 } 084 return Collections.emptyList(); 085 } 086 087 088 /** 089 * Extract a key from the request to use to look up media types. 090 * @return the lookup key, or {@code null} if none 091 */ 092 protected abstract String getMediaTypeKey(NativeWebRequest request); 093 094 /** 095 * Override to provide handling when a key is successfully resolved via 096 * {@link #lookupMediaType}. 097 */ 098 protected void handleMatch(String key, MediaType mediaType) { 099 } 100 101 /** 102 * Override to provide handling when a key is not resolved via. 103 * {@link #lookupMediaType}. Sub-classes can take further steps to 104 * determine the media type(s). If a MediaType is returned from 105 * this method it will be added to the cache in the base class. 106 */ 107 protected MediaType handleNoMatch(NativeWebRequest request, String key) 108 throws HttpMediaTypeNotAcceptableException { 109 110 return null; 111 } 112 113}