|
1 | 1 | /*
|
2 |
| - * Copyright 2012-2018 the original author or authors. |
| 2 | + * Copyright 2012-2019 the original author or authors. |
3 | 3 | *
|
4 | 4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
5 | 5 | * you may not use this file except in compliance with the License.
|
|
18 | 18 |
|
19 | 19 | import java.lang.reflect.Modifier;
|
20 | 20 | import java.util.Map;
|
| 21 | +import java.util.function.BiConsumer; |
21 | 22 |
|
22 | 23 | import javax.annotation.PostConstruct;
|
23 | 24 |
|
24 | 25 | import com.fasterxml.jackson.databind.JsonDeserializer;
|
25 | 26 | import com.fasterxml.jackson.databind.JsonSerializer;
|
| 27 | +import com.fasterxml.jackson.databind.KeyDeserializer; |
26 | 28 | import com.fasterxml.jackson.databind.Module;
|
27 | 29 | import com.fasterxml.jackson.databind.module.SimpleModule;
|
28 | 30 |
|
| 31 | +import org.springframework.beans.BeanUtils; |
29 | 32 | import org.springframework.beans.BeansException;
|
30 | 33 | import org.springframework.beans.factory.BeanFactory;
|
31 | 34 | import org.springframework.beans.factory.BeanFactoryAware;
|
32 | 35 | import org.springframework.beans.factory.HierarchicalBeanFactory;
|
33 | 36 | import org.springframework.beans.factory.ListableBeanFactory;
|
| 37 | +import org.springframework.boot.jackson.JsonComponent.Scope; |
34 | 38 | import org.springframework.core.ResolvableType;
|
| 39 | +import org.springframework.core.annotation.MergedAnnotation; |
| 40 | +import org.springframework.core.annotation.MergedAnnotations; |
| 41 | +import org.springframework.core.annotation.MergedAnnotations.SearchStrategy; |
| 42 | +import org.springframework.util.Assert; |
| 43 | +import org.springframework.util.ObjectUtils; |
35 | 44 |
|
36 | 45 | /**
|
37 | 46 | * Spring Bean and Jackson {@link Module} to register {@link JsonComponent} annotated
|
38 | 47 | * beans.
|
39 | 48 | *
|
40 | 49 | * @author Phillip Webb
|
| 50 | + * @author Paul Aly |
41 | 51 | * @since 1.4.0
|
42 | 52 | * @see JsonComponent
|
43 | 53 | */
|
@@ -72,38 +82,74 @@ private void addJsonBeans(ListableBeanFactory beanFactory) {
|
72 | 82 | }
|
73 | 83 |
|
74 | 84 | private void addJsonBean(Object bean) {
|
| 85 | + MergedAnnotation<JsonComponent> annotation = MergedAnnotations |
| 86 | + .from(bean.getClass(), SearchStrategy.EXHAUSTIVE) |
| 87 | + .get(JsonComponent.class); |
| 88 | + Class<?>[] types = annotation.getClassArray("type"); |
| 89 | + Scope scope = annotation.getEnum("scope", JsonComponent.Scope.class); |
| 90 | + addJsonBean(bean, types, scope); |
| 91 | + } |
| 92 | + |
| 93 | + private void addJsonBean(Object bean, Class<?>[] types, Scope scope) { |
75 | 94 | if (bean instanceof JsonSerializer) {
|
76 |
| - addSerializerWithDeducedType((JsonSerializer<?>) bean); |
| 95 | + addJsonSerializerBean((JsonSerializer<?>) bean, scope, types); |
| 96 | + } |
| 97 | + else if (bean instanceof JsonDeserializer) { |
| 98 | + addJsonDeserializerBean((JsonDeserializer<?>) bean, types); |
77 | 99 | }
|
78 |
| - if (bean instanceof JsonDeserializer) { |
79 |
| - addDeserializerWithDeducedType((JsonDeserializer<?>) bean); |
| 100 | + else if (bean instanceof KeyDeserializer) { |
| 101 | + addKeyDeserializerBean((KeyDeserializer) bean, types); |
80 | 102 | }
|
81 | 103 | for (Class<?> innerClass : bean.getClass().getDeclaredClasses()) {
|
82 |
| - if (!Modifier.isAbstract(innerClass.getModifiers()) |
83 |
| - && (JsonSerializer.class.isAssignableFrom(innerClass) |
84 |
| - || JsonDeserializer.class.isAssignableFrom(innerClass))) { |
85 |
| - try { |
86 |
| - addJsonBean(innerClass.newInstance()); |
87 |
| - } |
88 |
| - catch (Exception ex) { |
89 |
| - throw new IllegalStateException(ex); |
90 |
| - } |
| 104 | + if (isSuitableInnerClass(innerClass)) { |
| 105 | + Object innerInstance = BeanUtils.instantiateClass(innerClass); |
| 106 | + addJsonBean(innerInstance, types, scope); |
91 | 107 | }
|
92 | 108 | }
|
93 | 109 | }
|
94 | 110 |
|
95 |
| - @SuppressWarnings({ "unchecked" }) |
96 |
| - private <T> void addSerializerWithDeducedType(JsonSerializer<T> serializer) { |
97 |
| - ResolvableType type = ResolvableType.forClass(JsonSerializer.class, |
98 |
| - serializer.getClass()); |
99 |
| - addSerializer((Class<T>) type.resolveGeneric(), serializer); |
| 111 | + private boolean isSuitableInnerClass(Class<?> innerClass) { |
| 112 | + return !Modifier.isAbstract(innerClass.getModifiers()) |
| 113 | + && (JsonSerializer.class.isAssignableFrom(innerClass) |
| 114 | + || JsonDeserializer.class.isAssignableFrom(innerClass) |
| 115 | + || KeyDeserializer.class.isAssignableFrom(innerClass)); |
| 116 | + } |
| 117 | + |
| 118 | + @SuppressWarnings("unchecked") |
| 119 | + private <T> void addJsonSerializerBean(JsonSerializer<T> serializer, |
| 120 | + JsonComponent.Scope scope, Class<?>[] types) { |
| 121 | + Class<T> baseType = (Class<T>) ResolvableType |
| 122 | + .forClass(JsonSerializer.class, serializer.getClass()).resolveGeneric(); |
| 123 | + addBeanToModule(serializer, baseType, types, |
| 124 | + (scope == Scope.VALUES) ? this::addSerializer : this::addKeySerializer); |
| 125 | + |
| 126 | + } |
| 127 | + |
| 128 | + @SuppressWarnings("unchecked") |
| 129 | + private <T> void addJsonDeserializerBean(JsonDeserializer<T> deserializer, |
| 130 | + Class<?>[] types) { |
| 131 | + Class<T> baseType = (Class<T>) ResolvableType |
| 132 | + .forClass(JsonDeserializer.class, deserializer.getClass()) |
| 133 | + .resolveGeneric(); |
| 134 | + addBeanToModule(deserializer, baseType, types, this::addDeserializer); |
| 135 | + } |
| 136 | + |
| 137 | + private void addKeyDeserializerBean(KeyDeserializer deserializer, Class<?>[] types) { |
| 138 | + Assert.notEmpty(types, "Type must be specified for KeyDeserializer"); |
| 139 | + addBeanToModule(deserializer, Object.class, types, this::addKeyDeserializer); |
100 | 140 | }
|
101 | 141 |
|
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); |
| 142 | + @SuppressWarnings("unchecked") |
| 143 | + private <E, T> void addBeanToModule(E element, Class<T> baseType, Class<?>[] types, |
| 144 | + BiConsumer<Class<T>, E> consumer) { |
| 145 | + if (ObjectUtils.isEmpty(types)) { |
| 146 | + consumer.accept(baseType, element); |
| 147 | + return; |
| 148 | + } |
| 149 | + for (Class<?> type : types) { |
| 150 | + Assert.isAssignable(baseType, type); |
| 151 | + consumer.accept((Class<T>) type, element); |
| 152 | + } |
107 | 153 | }
|
108 | 154 |
|
109 | 155 | }
|
0 commit comments