001/*
002 * Copyright 2012-2018 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.jackson;
018
019import java.lang.reflect.Modifier;
020import java.util.Map;
021
022import javax.annotation.PostConstruct;
023
024import com.fasterxml.jackson.databind.JsonDeserializer;
025import com.fasterxml.jackson.databind.JsonSerializer;
026import com.fasterxml.jackson.databind.Module;
027import com.fasterxml.jackson.databind.module.SimpleModule;
028
029import org.springframework.beans.BeansException;
030import org.springframework.beans.factory.BeanFactory;
031import org.springframework.beans.factory.BeanFactoryAware;
032import org.springframework.beans.factory.HierarchicalBeanFactory;
033import org.springframework.beans.factory.ListableBeanFactory;
034import org.springframework.core.ResolvableType;
035
036/**
037 * Spring Bean and Jackson {@link Module} to register {@link JsonComponent} annotated
038 * beans.
039 *
040 * @author Phillip Webb
041 * @since 1.4.0
042 * @see JsonComponent
043 */
044public class JsonComponentModule extends SimpleModule implements BeanFactoryAware {
045
046        private BeanFactory beanFactory;
047
048        @Override
049        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
050                this.beanFactory = beanFactory;
051        }
052
053        @PostConstruct
054        public void registerJsonComponents() {
055                BeanFactory beanFactory = this.beanFactory;
056                while (beanFactory != null) {
057                        if (beanFactory instanceof ListableBeanFactory) {
058                                addJsonBeans((ListableBeanFactory) beanFactory);
059                        }
060                        beanFactory = (beanFactory instanceof HierarchicalBeanFactory)
061                                        ? ((HierarchicalBeanFactory) beanFactory).getParentBeanFactory()
062                                        : null;
063                }
064        }
065
066        private void addJsonBeans(ListableBeanFactory beanFactory) {
067                Map<String, Object> beans = beanFactory
068                                .getBeansWithAnnotation(JsonComponent.class);
069                for (Object bean : beans.values()) {
070                        addJsonBean(bean);
071                }
072        }
073
074        private void addJsonBean(Object bean) {
075                if (bean instanceof JsonSerializer) {
076                        addSerializerWithDeducedType((JsonSerializer<?>) bean);
077                }
078                if (bean instanceof JsonDeserializer) {
079                        addDeserializerWithDeducedType((JsonDeserializer<?>) bean);
080                }
081                for (Class<?> innerClass : bean.getClass().getDeclaredClasses()) {
082                        if (!Modifier.isAbstract(innerClass.getModifiers())
083                                        && (JsonSerializer.class.isAssignableFrom(innerClass)
084                                                        || JsonDeserializer.class.isAssignableFrom(innerClass))) {
085                                try {
086                                        addJsonBean(innerClass.newInstance());
087                                }
088                                catch (Exception ex) {
089                                        throw new IllegalStateException(ex);
090                                }
091                        }
092                }
093        }
094
095        @SuppressWarnings({ "unchecked" })
096        private <T> void addSerializerWithDeducedType(JsonSerializer<T> serializer) {
097                ResolvableType type = ResolvableType.forClass(JsonSerializer.class,
098                                serializer.getClass());
099                addSerializer((Class<T>) type.resolveGeneric(), serializer);
100        }
101
102        @SuppressWarnings({ "unchecked" })
103        private <T> void addDeserializerWithDeducedType(JsonDeserializer<T> deserializer) {
104                ResolvableType type = ResolvableType.forClass(JsonDeserializer.class,
105                                deserializer.getClass());
106                addDeserializer((Class<T>) type.resolveGeneric(), deserializer);
107        }
108
109}