001/* 002 * Copyright 2012-2016 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 com.fasterxml.jackson.databind.ObjectMapper; 020 021import org.springframework.beans.BeansException; 022import org.springframework.beans.factory.BeanFactory; 023import org.springframework.beans.factory.BeanFactoryAware; 024import org.springframework.beans.factory.NoSuchBeanDefinitionException; 025import org.springframework.beans.factory.config.BeanPostProcessor; 026import org.springframework.boot.autoconfigure.AutoConfigureAfter; 027import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 028import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 029import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 030import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; 031import org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration; 032import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; 033import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration; 034import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration; 035import org.springframework.boot.context.properties.EnableConfigurationProperties; 036import org.springframework.context.annotation.Bean; 037import org.springframework.context.annotation.Configuration; 038import org.springframework.context.annotation.Import; 039import org.springframework.hateoas.EntityLinks; 040import org.springframework.hateoas.LinkDiscoverers; 041import org.springframework.hateoas.Resource; 042import org.springframework.hateoas.config.EnableEntityLinks; 043import org.springframework.hateoas.config.EnableHypermediaSupport; 044import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType; 045import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; 046import org.springframework.plugin.core.Plugin; 047import org.springframework.web.bind.annotation.RequestMapping; 048 049/** 050 * {@link EnableAutoConfiguration Auto-configuration} for Spring HATEOAS's 051 * {@link EnableHypermediaSupport}. 052 * 053 * @author Roy Clarkson 054 * @author Oliver Gierke 055 * @author Andy Wilkinson 056 * @since 1.1.0 057 */ 058@Configuration 059@ConditionalOnClass({ Resource.class, RequestMapping.class, Plugin.class }) 060@ConditionalOnWebApplication 061@AutoConfigureAfter({ WebMvcAutoConfiguration.class, JacksonAutoConfiguration.class, 062 HttpMessageConvertersAutoConfiguration.class, 063 RepositoryRestMvcAutoConfiguration.class }) 064@EnableConfigurationProperties(HateoasProperties.class) 065@Import(HypermediaHttpMessageConverterConfiguration.class) 066public class HypermediaAutoConfiguration { 067 068 @Configuration 069 @ConditionalOnMissingBean(LinkDiscoverers.class) 070 @ConditionalOnClass(ObjectMapper.class) 071 @EnableHypermediaSupport(type = HypermediaType.HAL) 072 protected static class HypermediaConfiguration { 073 074 @Bean 075 public static HalObjectMapperConfigurer halObjectMapperConfigurer() { 076 return new HalObjectMapperConfigurer(); 077 } 078 079 } 080 081 @Configuration 082 @ConditionalOnMissingBean(EntityLinks.class) 083 @EnableEntityLinks 084 protected static class EntityLinksConfiguration { 085 086 } 087 088 /** 089 * {@link BeanPostProcessor} to apply any {@link Jackson2ObjectMapperBuilder} 090 * configuration to the HAL {@link ObjectMapper}. 091 */ 092 private static class HalObjectMapperConfigurer 093 implements BeanPostProcessor, BeanFactoryAware { 094 095 private BeanFactory beanFactory; 096 097 @Override 098 public Object postProcessBeforeInitialization(Object bean, String beanName) 099 throws BeansException { 100 if (bean instanceof ObjectMapper && "_halObjectMapper".equals(beanName)) { 101 postProcessHalObjectMapper((ObjectMapper) bean); 102 } 103 return bean; 104 } 105 106 private void postProcessHalObjectMapper(ObjectMapper objectMapper) { 107 try { 108 Jackson2ObjectMapperBuilder builder = this.beanFactory 109 .getBean(Jackson2ObjectMapperBuilder.class); 110 builder.configure(objectMapper); 111 } 112 catch (NoSuchBeanDefinitionException ex) { 113 // No Jackson configuration required 114 } 115 } 116 117 @Override 118 public Object postProcessAfterInitialization(Object bean, String beanName) 119 throws BeansException { 120 return bean; 121 } 122 123 @Override 124 public void setBeanFactory(BeanFactory beanFactory) throws BeansException { 125 this.beanFactory = beanFactory; 126 } 127 128 } 129 130}