001/* 002 * Copyright 2012-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 * http://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.boot.autoconfigure.hateoas; 018 019import java.util.ArrayList; 020import java.util.Collection; 021import java.util.List; 022 023import javax.annotation.PostConstruct; 024 025import org.springframework.beans.BeansException; 026import org.springframework.beans.factory.BeanFactory; 027import org.springframework.beans.factory.BeanFactoryAware; 028import org.springframework.beans.factory.ListableBeanFactory; 029import org.springframework.beans.factory.config.BeanPostProcessor; 030import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 031import org.springframework.context.annotation.Bean; 032import org.springframework.hateoas.mvc.TypeConstrainedMappingJackson2HttpMessageConverter; 033import org.springframework.http.MediaType; 034import org.springframework.http.converter.AbstractHttpMessageConverter; 035import org.springframework.http.converter.HttpMessageConverter; 036import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; 037 038/** 039 * Configuration for {@link HttpMessageConverter HttpMessageConverters} when hypermedia is 040 * enabled. 041 * 042 * @author Andy Wilkinson 043 */ 044public class HypermediaHttpMessageConverterConfiguration { 045 046 @Bean 047 @ConditionalOnProperty(prefix = "spring.hateoas", name = "use-hal-as-default-json-media-type", matchIfMissing = true) 048 public static HalMessageConverterSupportedMediaTypesCustomizer halMessageConverterSupportedMediaTypeCustomizer() { 049 return new HalMessageConverterSupportedMediaTypesCustomizer(); 050 } 051 052 /** 053 * Updates any {@link TypeConstrainedMappingJackson2HttpMessageConverter}s to support 054 * {@code application/json} in addition to {@code application/hal+json}. Cannot be a 055 * {@link BeanPostProcessor} as processing must be performed after 056 * {@code Jackson2ModuleRegisteringBeanPostProcessor} has registered the converter and 057 * it is unordered. 058 */ 059 private static class HalMessageConverterSupportedMediaTypesCustomizer 060 implements BeanFactoryAware { 061 062 private volatile BeanFactory beanFactory; 063 064 @PostConstruct 065 public void configureHttpMessageConverters() { 066 if (this.beanFactory instanceof ListableBeanFactory) { 067 configureHttpMessageConverters(((ListableBeanFactory) this.beanFactory) 068 .getBeansOfType(RequestMappingHandlerAdapter.class).values()); 069 } 070 } 071 072 private void configureHttpMessageConverters( 073 Collection<RequestMappingHandlerAdapter> handlerAdapters) { 074 for (RequestMappingHandlerAdapter handlerAdapter : handlerAdapters) { 075 for (HttpMessageConverter<?> messageConverter : handlerAdapter 076 .getMessageConverters()) { 077 configureHttpMessageConverter(messageConverter); 078 } 079 } 080 } 081 082 private void configureHttpMessageConverter(HttpMessageConverter<?> converter) { 083 if (converter instanceof TypeConstrainedMappingJackson2HttpMessageConverter) { 084 List<MediaType> supportedMediaTypes = new ArrayList<MediaType>( 085 converter.getSupportedMediaTypes()); 086 if (!supportedMediaTypes.contains(MediaType.APPLICATION_JSON)) { 087 supportedMediaTypes.add(MediaType.APPLICATION_JSON); 088 } 089 ((AbstractHttpMessageConverter<?>) converter) 090 .setSupportedMediaTypes(supportedMediaTypes); 091 } 092 } 093 094 @Override 095 public void setBeanFactory(BeanFactory beanFactory) throws BeansException { 096 this.beanFactory = beanFactory; 097 } 098 099 } 100 101}