15
15
*/
16
16
package org .springframework .hateoas .mediatype ;
17
17
18
- import com .fasterxml .jackson .annotation .JsonUnwrapped ;
19
18
import lombok .AccessLevel ;
20
19
import lombok .RequiredArgsConstructor ;
21
20
56
55
import com .fasterxml .jackson .annotation .JsonIgnoreProperties ;
57
56
import com .fasterxml .jackson .annotation .JsonProperty ;
58
57
import com .fasterxml .jackson .annotation .JsonProperty .Access ;
58
+ import com .fasterxml .jackson .annotation .JsonUnwrapped ;
59
59
60
60
/**
61
61
* @author Greg Turnquist
@@ -86,27 +86,7 @@ static List<Class<?>> getTypesToUnwrap() {
86
86
}
87
87
88
88
public static Map <String , Object > extractPropertyValues (@ Nullable Object object ) {
89
- return extractPropertyValues (object , false );
90
- }
91
-
92
- public static Map <String , Object > extractPropertyValues (@ Nullable Object object , boolean unwrapEligibleProperties ) {
93
-
94
- if (object == null ) {
95
- return Collections .emptyMap ();
96
- }
97
-
98
- if (EntityModel .class .isInstance (object )) {
99
- return extractPropertyValues (EntityModel .class .cast (object ).getContent ());
100
- }
101
-
102
- BeanWrapper wrapper = PropertyAccessorFactory .forBeanPropertyAccess (object );
103
-
104
- return getExposedProperties (object .getClass ()).stream () //
105
- .map (PropertyMetadata ::getName )
106
- .map (name -> unwrapEligibleProperties ? unwrapPropertyIfNeeded (name , wrapper ) :
107
- Collections .singletonMap (name , wrapper .getPropertyValue (name )))
108
- .flatMap (it -> it .entrySet ().stream ())
109
- .collect (HashMap ::new , (map , it ) -> map .put (it .getKey (), it .getValue ()), HashMap ::putAll );
89
+ return extractPropertyValues (object , true );
110
90
}
111
91
112
92
public static <T > T createObjectFromProperties (Class <T > clazz , Map <String , Object > properties ) {
@@ -116,13 +96,14 @@ public static <T> T createObjectFromProperties(Class<T> clazz, Map<String, Objec
116
96
properties .forEach ((key , value ) -> {
117
97
Optional .ofNullable (BeanUtils .getPropertyDescriptor (clazz , key )) //
118
98
.ifPresent (property -> {
99
+
119
100
try {
120
101
121
102
Method writeMethod = property .getWriteMethod ();
122
103
ReflectionUtils .makeAccessible (writeMethod );
123
104
writeMethod .invoke (obj , value );
124
- } catch (IllegalAccessException | InvocationTargetException e ) {
125
105
106
+ } catch (IllegalAccessException | InvocationTargetException e ) {
126
107
throw new RuntimeException (e );
127
108
}
128
109
});
@@ -162,16 +143,13 @@ private static Map<String, Object> unwrapPropertyIfNeeded(String propertyName, B
162
143
Field descriptorField = ReflectionUtils .findField (wrapper .getWrappedClass (), propertyName );
163
144
Method readMethod = wrapper .getPropertyDescriptor (propertyName ).getReadMethod ();
164
145
165
- MergedAnnotation <JsonUnwrapped > unwrappedAnnotation =
166
- Stream .of (descriptorField , readMethod )
167
- .filter (Objects ::nonNull )
168
- .map (MergedAnnotations ::from )
169
- .flatMap (mergedAnnotations -> mergedAnnotations .stream (JsonUnwrapped .class ))
170
- .filter (it -> it .getBoolean ("enabled" ))
171
- .findFirst ()
172
- .orElse (null );
146
+ MergedAnnotation <JsonUnwrapped > unwrappedAnnotation = Stream .of (descriptorField , readMethod )
147
+ .filter (Objects ::nonNull ).map (MergedAnnotations ::from )
148
+ .flatMap (mergedAnnotations -> mergedAnnotations .stream (JsonUnwrapped .class ))
149
+ .filter (it -> it .getBoolean ("enabled" )).findFirst ().orElse (null );
173
150
174
151
Object propertyValue = wrapper .getPropertyValue (propertyName );
152
+
175
153
if (unwrappedAnnotation == null ) {
176
154
return Collections .singletonMap (propertyName , propertyValue );
177
155
}
@@ -180,11 +158,34 @@ private static Map<String, Object> unwrapPropertyIfNeeded(String propertyName, B
180
158
String suffix = unwrappedAnnotation .getString ("suffix" );
181
159
182
160
Map <String , Object > properties = new HashMap <>();
183
- extractPropertyValues (propertyValue , true )
161
+
162
+ extractPropertyValues (propertyValue , true ) //
184
163
.forEach ((name , value ) -> properties .put (prefix + name + suffix , value ));
164
+
185
165
return properties ;
186
166
}
187
167
168
+ private static Map <String , Object > extractPropertyValues (@ Nullable Object object , boolean unwrapEligibleProperties ) {
169
+
170
+ if (object == null ) {
171
+ return Collections .emptyMap ();
172
+ }
173
+
174
+ if (EntityModel .class .isInstance (object )) {
175
+ return extractPropertyValues (EntityModel .class .cast (object ).getContent ());
176
+ }
177
+
178
+ BeanWrapper wrapper = PropertyAccessorFactory .forBeanPropertyAccess (object );
179
+
180
+ return getExposedProperties (object .getClass ()).stream () //
181
+ .map (PropertyMetadata ::getName ) //
182
+ .map (name -> unwrapEligibleProperties //
183
+ ? unwrapPropertyIfNeeded (name , wrapper ) //
184
+ : Collections .singletonMap (name , wrapper .getPropertyValue (name ))) //
185
+ .flatMap (it -> it .entrySet ().stream ()) //
186
+ .collect (HashMap ::new , (map , it ) -> map .put (it .getKey (), it .getValue ()), HashMap ::putAll );
187
+ }
188
+
188
189
private static ResolvableType unwrapDomainType (ResolvableType type ) {
189
190
190
191
if (!type .hasGenerics ()) {
@@ -203,7 +204,7 @@ private static ResolvableType unwrapDomainType(ResolvableType type) {
203
204
* Replaces the given {@link ResolvableType} with the one produced by the given {@link Supplier} if the former is
204
205
* assignable from one of the types to be unwrapped.
205
206
*
206
- * @param type must not be {@literal null}.
207
+ * @param type must not be {@literal null}.
207
208
* @param mapper must not be {@literal null}.
208
209
* @return
209
210
* @see #TYPES_TO_UNWRAP
@@ -222,8 +223,8 @@ private static Stream<PropertyMetadata> lookupExposedProperties(@Nullable Class<
222
223
return type == null //
223
224
? Stream .empty () //
224
225
: getPropertyDescriptors (type ) //
225
- .map (it -> new AnnotatedProperty (new Property (type , it .getReadMethod (), it .getWriteMethod ())))
226
- .map (it -> JSR_303_PRESENT ? new Jsr303AwarePropertyMetadata (it ) : new DefaultPropertyMetadata (it ));
226
+ .map (it -> new AnnotatedProperty (new Property (type , it .getReadMethod (), it .getWriteMethod ())))
227
+ .map (it -> JSR_303_PRESENT ? new Jsr303AwarePropertyMetadata (it ) : new DefaultPropertyMetadata (it ));
227
228
}
228
229
229
230
/**
@@ -393,7 +394,7 @@ public boolean hasWriteMethod() {
393
394
/**
394
395
* Returns the {@link MergedAnnotation} of the given type.
395
396
*
396
- * @param <T> the annotation type.
397
+ * @param <T> the annotation type.
397
398
* @param type must not be {@literal null}.
398
399
* @return the {@link MergedAnnotation} if available or {@link MergedAnnotation#missing()} if not.
399
400
*/
0 commit comments