1515 */
1616package org .springframework .hateoas .mediatype ;
1717
18- import com .fasterxml .jackson .annotation .JsonUnwrapped ;
1918import lombok .AccessLevel ;
2019import lombok .RequiredArgsConstructor ;
2120
5655import com .fasterxml .jackson .annotation .JsonIgnoreProperties ;
5756import com .fasterxml .jackson .annotation .JsonProperty ;
5857import com .fasterxml .jackson .annotation .JsonProperty .Access ;
58+ import com .fasterxml .jackson .annotation .JsonUnwrapped ;
5959
6060/**
6161 * @author Greg Turnquist
@@ -86,27 +86,7 @@ static List<Class<?>> getTypesToUnwrap() {
8686 }
8787
8888 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 );
11090 }
11191
11292 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
11696 properties .forEach ((key , value ) -> {
11797 Optional .ofNullable (BeanUtils .getPropertyDescriptor (clazz , key )) //
11898 .ifPresent (property -> {
99+
119100 try {
120101
121102 Method writeMethod = property .getWriteMethod ();
122103 ReflectionUtils .makeAccessible (writeMethod );
123104 writeMethod .invoke (obj , value );
124- } catch (IllegalAccessException | InvocationTargetException e ) {
125105
106+ } catch (IllegalAccessException | InvocationTargetException e ) {
126107 throw new RuntimeException (e );
127108 }
128109 });
@@ -162,16 +143,13 @@ private static Map<String, Object> unwrapPropertyIfNeeded(String propertyName, B
162143 Field descriptorField = ReflectionUtils .findField (wrapper .getWrappedClass (), propertyName );
163144 Method readMethod = wrapper .getPropertyDescriptor (propertyName ).getReadMethod ();
164145
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 );
173150
174151 Object propertyValue = wrapper .getPropertyValue (propertyName );
152+
175153 if (unwrappedAnnotation == null ) {
176154 return Collections .singletonMap (propertyName , propertyValue );
177155 }
@@ -180,11 +158,34 @@ private static Map<String, Object> unwrapPropertyIfNeeded(String propertyName, B
180158 String suffix = unwrappedAnnotation .getString ("suffix" );
181159
182160 Map <String , Object > properties = new HashMap <>();
183- extractPropertyValues (propertyValue , true )
161+
162+ extractPropertyValues (propertyValue , true ) //
184163 .forEach ((name , value ) -> properties .put (prefix + name + suffix , value ));
164+
185165 return properties ;
186166 }
187167
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+
188189 private static ResolvableType unwrapDomainType (ResolvableType type ) {
189190
190191 if (!type .hasGenerics ()) {
@@ -203,7 +204,7 @@ private static ResolvableType unwrapDomainType(ResolvableType type) {
203204 * Replaces the given {@link ResolvableType} with the one produced by the given {@link Supplier} if the former is
204205 * assignable from one of the types to be unwrapped.
205206 *
206- * @param type must not be {@literal null}.
207+ * @param type must not be {@literal null}.
207208 * @param mapper must not be {@literal null}.
208209 * @return
209210 * @see #TYPES_TO_UNWRAP
@@ -222,8 +223,8 @@ private static Stream<PropertyMetadata> lookupExposedProperties(@Nullable Class<
222223 return type == null //
223224 ? Stream .empty () //
224225 : 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 ));
227228 }
228229
229230 /**
@@ -393,7 +394,7 @@ public boolean hasWriteMethod() {
393394 /**
394395 * Returns the {@link MergedAnnotation} of the given type.
395396 *
396- * @param <T> the annotation type.
397+ * @param <T> the annotation type.
397398 * @param type must not be {@literal null}.
398399 * @return the {@link MergedAnnotation} if available or {@link MergedAnnotation#missing()} if not.
399400 */
0 commit comments