20
20
import java .io .UncheckedIOException ;
21
21
22
22
import org .springframework .beans .factory .BeanClassLoaderAware ;
23
+ import org .springframework .core .ResolvableType ;
23
24
import org .springframework .integration .mapping .support .JsonHeaders ;
24
- import org .springframework .integration .support .AbstractIntegrationMessageBuilder ;
25
25
import org .springframework .integration .support .json .JsonObjectMapper ;
26
26
import org .springframework .integration .support .json .JsonObjectMapperProvider ;
27
27
import org .springframework .integration .transformer .AbstractTransformer ;
28
+ import org .springframework .lang .Nullable ;
28
29
import org .springframework .messaging .Message ;
30
+ import org .springframework .messaging .MessageHeaders ;
31
+ import org .springframework .util .Assert ;
32
+ import org .springframework .util .ClassUtils ;
29
33
30
34
/**
31
35
* Transformer implementation that converts a JSON string payload into an instance of the
42
46
*
43
47
* @author Mark Fisher
44
48
* @author Artem Bilan
49
+ *
45
50
* @see JsonObjectMapper
46
51
* @see org.springframework.integration.support.json.JsonObjectMapperProvider
52
+ *
47
53
* @since 2.0
48
54
*/
49
55
public class JsonToObjectTransformer extends AbstractTransformer implements BeanClassLoaderAware {
50
56
51
- private final Class <?> targetClass ;
57
+ private final ResolvableType targetType ;
52
58
53
59
private final JsonObjectMapper <?, ?> jsonObjectMapper ;
54
60
61
+ private ClassLoader classLoader ;
62
+
55
63
public JsonToObjectTransformer () {
56
64
this ((Class <?>) null );
57
65
}
58
66
59
- public JsonToObjectTransformer (Class <?> targetClass ) {
60
- this (targetClass , null );
67
+ public JsonToObjectTransformer (@ Nullable Class <?> targetClass ) {
68
+ this (ResolvableType .forClass (targetClass ));
69
+ }
70
+
71
+ /**
72
+ * Construct an instance based on the provided {@link ResolvableType}.
73
+ * @param targetType the {@link ResolvableType} to use.
74
+ * @since 5.2
75
+ */
76
+ public JsonToObjectTransformer (ResolvableType targetType ) {
77
+ this (targetType , null );
78
+ }
79
+
80
+ public JsonToObjectTransformer (@ Nullable JsonObjectMapper <?, ?> jsonObjectMapper ) {
81
+ this ((Class <?>) null , jsonObjectMapper );
61
82
}
62
83
63
- public JsonToObjectTransformer (JsonObjectMapper <?, ?> jsonObjectMapper ) {
64
- this (null , jsonObjectMapper );
84
+ public JsonToObjectTransformer (@ Nullable Class <?> targetClass , @ Nullable JsonObjectMapper <?, ?> jsonObjectMapper ) {
85
+ this (ResolvableType . forClass ( targetClass ) , jsonObjectMapper );
65
86
}
66
87
67
- public JsonToObjectTransformer (Class <?> targetClass , JsonObjectMapper <?, ?> jsonObjectMapper ) {
68
- this .targetClass = targetClass ;
88
+ /**
89
+ * Construct an instance based on the provided {@link ResolvableType} and {@link JsonObjectMapper}.
90
+ * @param targetType the {@link ResolvableType} to use.
91
+ * @param jsonObjectMapper the {@link JsonObjectMapper} to use.
92
+ * @since 5.2
93
+ */
94
+ public JsonToObjectTransformer (ResolvableType targetType , @ Nullable JsonObjectMapper <?, ?> jsonObjectMapper ) {
95
+ Assert .notNull (targetType , "'targetType' must not be null" );
96
+ this .targetType = targetType ;
69
97
this .jsonObjectMapper = (jsonObjectMapper != null ) ? jsonObjectMapper : JsonObjectMapperProvider .newInstance ();
70
98
}
71
99
72
100
@ Override
73
101
public void setBeanClassLoader (ClassLoader classLoader ) {
102
+ this .classLoader = classLoader ;
74
103
if (this .jsonObjectMapper instanceof BeanClassLoaderAware ) {
75
104
((BeanClassLoaderAware ) this .jsonObjectMapper ).setBeanClassLoader (classLoader );
76
105
}
@@ -83,21 +112,72 @@ public String getComponentType() {
83
112
84
113
@ Override
85
114
protected Object doTransform (Message <?> message ) {
115
+ MessageHeaders headers = message .getHeaders ();
116
+ boolean removeHeaders = false ;
117
+ ResolvableType valueType = obtainResolvableTypeFromHeadersIfAny (headers );
118
+
119
+ if (valueType != null ) {
120
+ removeHeaders = true ;
121
+ }
122
+ else {
123
+ valueType = this .targetType ;
124
+ }
125
+
126
+ Object result ;
86
127
try {
87
- if (this .targetClass != null ) {
88
- return this .jsonObjectMapper .fromJson (message .getPayload (), this .targetClass );
89
- }
90
- else {
91
- Object result = this .jsonObjectMapper .fromJson (message .getPayload (), message .getHeaders ());
92
- AbstractIntegrationMessageBuilder <Object > messageBuilder = this .getMessageBuilderFactory ().withPayload (result )
93
- .copyHeaders (message .getHeaders ())
94
- .removeHeaders (JsonHeaders .HEADERS .toArray (new String [3 ]));
95
- return messageBuilder .build ();
96
- }
128
+ result = this .jsonObjectMapper .fromJson (message .getPayload (), valueType );
129
+
97
130
}
98
131
catch (IOException e ) {
99
132
throw new UncheckedIOException (e );
100
133
}
134
+
135
+ if (removeHeaders ) {
136
+ return getMessageBuilderFactory ()
137
+ .withPayload (result )
138
+ .copyHeaders (headers )
139
+ .removeHeaders (JsonHeaders .HEADERS .toArray (new String [3 ]))
140
+ .build ();
141
+ }
142
+ else {
143
+ return result ;
144
+ }
145
+ }
146
+
147
+
148
+ private ResolvableType obtainResolvableTypeFromHeadersIfAny (MessageHeaders headers ) {
149
+ ResolvableType valueType = null ;
150
+ if (headers .containsKey (JsonHeaders .TYPE_ID ) || headers .containsKey (JsonHeaders .RESOLVABLE_TYPE )) {
151
+ valueType = headers .get (JsonHeaders .RESOLVABLE_TYPE , ResolvableType .class );
152
+ if (valueType == null ) {
153
+ Class <?> targetClass = getClassForValue (headers .get (JsonHeaders .TYPE_ID ));
154
+ Class <?> contentClass = null ;
155
+ Class <?> keyClass = null ;
156
+ if (headers .containsKey (JsonHeaders .CONTENT_TYPE_ID )) {
157
+ contentClass = getClassForValue (headers .get (JsonHeaders .CONTENT_TYPE_ID ));
158
+ }
159
+ if (headers .containsKey (JsonHeaders .KEY_TYPE_ID )) {
160
+ keyClass = getClassForValue (headers .get (JsonHeaders .KEY_TYPE_ID ));
161
+ }
162
+
163
+ valueType = JsonObjectMapper .buildResolvableType (targetClass , contentClass , keyClass );
164
+ }
165
+ }
166
+ return valueType ;
167
+ }
168
+
169
+ private Class <?> getClassForValue (Object classValue ) {
170
+ if (classValue instanceof Class <?>) {
171
+ return (Class <?>) classValue ;
172
+ }
173
+ else {
174
+ try {
175
+ return ClassUtils .forName (classValue .toString (), this .classLoader );
176
+ }
177
+ catch (ClassNotFoundException | LinkageError e ) {
178
+ throw new IllegalStateException (e );
179
+ }
180
+ }
101
181
}
102
182
103
183
}
0 commit comments