Skip to content

Commit 5d88b50

Browse files
committed
#1288 - Polishing.
Original ticket: #968. Original pull request: #1269.
1 parent 5f1d5a8 commit 5d88b50

File tree

3 files changed

+47
-47
lines changed

3 files changed

+47
-47
lines changed

src/main/java/org/springframework/hateoas/mediatype/PropertyUtils.java

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616
package org.springframework.hateoas.mediatype;
1717

18-
import com.fasterxml.jackson.annotation.JsonUnwrapped;
1918
import lombok.AccessLevel;
2019
import lombok.RequiredArgsConstructor;
2120

@@ -56,6 +55,7 @@
5655
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
5756
import com.fasterxml.jackson.annotation.JsonProperty;
5857
import 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
*/

src/main/java/org/springframework/hateoas/mediatype/hal/forms/HalFormsDocument.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ private HalFormsDocument() {
108108
*/
109109
public static HalFormsDocument<?> forRepresentationModel(RepresentationModel<?> model) {
110110

111-
Map<String, Object> attributes = PropertyUtils.extractPropertyValues(model, true);
111+
Map<String, Object> attributes = PropertyUtils.extractPropertyValues(model);
112112
attributes.remove("links");
113113

114114
return new HalFormsDocument<>().withAttributes(attributes);

src/test/java/org/springframework/hateoas/mediatype/hal/forms/Jackson2HalFormsIntegrationTest.java

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
import static org.assertj.core.api.Assertions.*;
1919

20-
import com.fasterxml.jackson.annotation.JsonUnwrapped;
2120
import lombok.Getter;
2221
import net.minidev.json.JSONArray;
2322

@@ -67,6 +66,7 @@
6766
import org.springframework.lang.Nullable;
6867

6968
import com.fasterxml.jackson.annotation.JsonInclude.Include;
69+
import com.fasterxml.jackson.annotation.JsonUnwrapped;
7070
import com.fasterxml.jackson.databind.ObjectMapper;
7171
import com.fasterxml.jackson.databind.SerializationFeature;
7272
import com.jayway.jsonpath.JsonPath;
@@ -519,15 +519,14 @@ void considersJsr303AnnotationsForTemplates() throws Exception {
519519
assertValueForPath(model, "$._templates.default.properties[0].required", true);
520520
}
521521

522-
/**
523-
* @see #968
524-
*/
525-
@Test
522+
@Test // #968
526523
void considerJsonUnwrapped() throws Exception {
524+
527525
UnwrappedExample unwrappedExample = new UnwrappedExample();
526+
528527
unwrappedExample.element = new UnwrappedExampleElement();
529528
unwrappedExample.element.firstname = "john";
530-
529+
531530
assertValueForPath(unwrappedExample, "$.firstname", "john");
532531
}
533532

@@ -636,17 +635,17 @@ public String getFirstname() {
636635
return firstname;
637636
}
638637
}
639-
638+
640639
public static class UnwrappedExample extends RepresentationModel<UnwrappedExample> {
641-
640+
642641
private UnwrappedExampleElement element;
643642

644643
@JsonUnwrapped
645-
public UnwrappedExampleElement getElement(){
644+
public UnwrappedExampleElement getElement() {
646645
return element;
647646
}
648647
}
649-
648+
650649
public static class UnwrappedExampleElement {
651650
private @Getter String firstname;
652651
}

0 commit comments

Comments
 (0)