Skip to content

Commit

Permalink
#968 - Polishing.
Browse files Browse the repository at this point in the history
Original pull request: #1269.
  • Loading branch information
odrotbohm committed May 7, 2020
1 parent 08c5f56 commit 5d1136e
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/
package org.springframework.hateoas.mediatype;

import com.fasterxml.jackson.annotation.JsonUnwrapped;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;

Expand Down Expand Up @@ -56,6 +55,7 @@
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonProperty.Access;
import com.fasterxml.jackson.annotation.JsonUnwrapped;

/**
* @author Greg Turnquist
Expand Down Expand Up @@ -86,27 +86,7 @@ static List<Class<?>> getTypesToUnwrap() {
}

public static Map<String, Object> extractPropertyValues(@Nullable Object object) {
return extractPropertyValues(object, false);
}

public static Map<String, Object> extractPropertyValues(@Nullable Object object, boolean unwrapEligibleProperties) {

if (object == null) {
return Collections.emptyMap();
}

if (EntityModel.class.isInstance(object)) {
return extractPropertyValues(EntityModel.class.cast(object).getContent());
}

BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(object);

return getExposedProperties(object.getClass()).stream() //
.map(PropertyMetadata::getName)
.map(name -> unwrapEligibleProperties ? unwrapPropertyIfNeeded(name, wrapper) :
Collections.singletonMap(name, wrapper.getPropertyValue(name)))
.flatMap(it -> it.entrySet().stream())
.collect(HashMap::new, (map, it) -> map.put(it.getKey(), it.getValue()), HashMap::putAll);
return extractPropertyValues(object, true);
}

public static <T> T createObjectFromProperties(Class<T> clazz, Map<String, Object> properties) {
Expand All @@ -116,13 +96,14 @@ public static <T> T createObjectFromProperties(Class<T> clazz, Map<String, Objec
properties.forEach((key, value) -> {
Optional.ofNullable(BeanUtils.getPropertyDescriptor(clazz, key)) //
.ifPresent(property -> {

try {

Method writeMethod = property.getWriteMethod();
ReflectionUtils.makeAccessible(writeMethod);
writeMethod.invoke(obj, value);
} catch (IllegalAccessException | InvocationTargetException e) {

} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
});
Expand Down Expand Up @@ -162,16 +143,13 @@ private static Map<String, Object> unwrapPropertyIfNeeded(String propertyName, B
Field descriptorField = ReflectionUtils.findField(wrapper.getWrappedClass(), propertyName);
Method readMethod = wrapper.getPropertyDescriptor(propertyName).getReadMethod();

MergedAnnotation<JsonUnwrapped> unwrappedAnnotation =
Stream.of(descriptorField, readMethod)
.filter(Objects::nonNull)
.map(MergedAnnotations::from)
.flatMap(mergedAnnotations -> mergedAnnotations.stream(JsonUnwrapped.class))
.filter(it -> it.getBoolean("enabled"))
.findFirst()
.orElse(null);
MergedAnnotation<JsonUnwrapped> unwrappedAnnotation = Stream.of(descriptorField, readMethod)
.filter(Objects::nonNull).map(MergedAnnotations::from)
.flatMap(mergedAnnotations -> mergedAnnotations.stream(JsonUnwrapped.class))
.filter(it -> it.getBoolean("enabled")).findFirst().orElse(null);

Object propertyValue = wrapper.getPropertyValue(propertyName);

if (unwrappedAnnotation == null) {
return Collections.singletonMap(propertyName, propertyValue);
}
Expand All @@ -180,11 +158,34 @@ private static Map<String, Object> unwrapPropertyIfNeeded(String propertyName, B
String suffix = unwrappedAnnotation.getString("suffix");

Map<String, Object> properties = new HashMap<>();
extractPropertyValues(propertyValue, true)

extractPropertyValues(propertyValue, true) //
.forEach((name, value) -> properties.put(prefix + name + suffix, value));

return properties;
}

private static Map<String, Object> extractPropertyValues(@Nullable Object object, boolean unwrapEligibleProperties) {

if (object == null) {
return Collections.emptyMap();
}

if (EntityModel.class.isInstance(object)) {
return extractPropertyValues(EntityModel.class.cast(object).getContent());
}

BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(object);

return getExposedProperties(object.getClass()).stream() //
.map(PropertyMetadata::getName) //
.map(name -> unwrapEligibleProperties //
? unwrapPropertyIfNeeded(name, wrapper) //
: Collections.singletonMap(name, wrapper.getPropertyValue(name))) //
.flatMap(it -> it.entrySet().stream()) //
.collect(HashMap::new, (map, it) -> map.put(it.getKey(), it.getValue()), HashMap::putAll);
}

private static ResolvableType unwrapDomainType(ResolvableType type) {

if (!type.hasGenerics()) {
Expand All @@ -203,7 +204,7 @@ private static ResolvableType unwrapDomainType(ResolvableType type) {
* Replaces the given {@link ResolvableType} with the one produced by the given {@link Supplier} if the former is
* assignable from one of the types to be unwrapped.
*
* @param type must not be {@literal null}.
* @param type must not be {@literal null}.
* @param mapper must not be {@literal null}.
* @return
* @see #TYPES_TO_UNWRAP
Expand All @@ -222,8 +223,8 @@ private static Stream<PropertyMetadata> lookupExposedProperties(@Nullable Class<
return type == null //
? Stream.empty() //
: getPropertyDescriptors(type) //
.map(it -> new AnnotatedProperty(new Property(type, it.getReadMethod(), it.getWriteMethod())))
.map(it -> JSR_303_PRESENT ? new Jsr303AwarePropertyMetadata(it) : new DefaultPropertyMetadata(it));
.map(it -> new AnnotatedProperty(new Property(type, it.getReadMethod(), it.getWriteMethod())))
.map(it -> JSR_303_PRESENT ? new Jsr303AwarePropertyMetadata(it) : new DefaultPropertyMetadata(it));
}

/**
Expand Down Expand Up @@ -393,7 +394,7 @@ public boolean hasWriteMethod() {
/**
* Returns the {@link MergedAnnotation} of the given type.
*
* @param <T> the annotation type.
* @param <T> the annotation type.
* @param type must not be {@literal null}.
* @return the {@link MergedAnnotation} if available or {@link MergedAnnotation#missing()} if not.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ private HalFormsDocument() {
*/
public static HalFormsDocument<?> forRepresentationModel(RepresentationModel<?> model) {

Map<String, Object> attributes = PropertyUtils.extractPropertyValues(model, true);
Map<String, Object> attributes = PropertyUtils.extractPropertyValues(model);
attributes.remove("links");

return new HalFormsDocument<>().withAttributes(attributes);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

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

import com.fasterxml.jackson.annotation.JsonUnwrapped;
import lombok.Getter;
import net.minidev.json.JSONArray;

Expand Down Expand Up @@ -68,6 +67,7 @@
import org.springframework.lang.Nullable;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.jayway.jsonpath.JsonPath;
Expand Down Expand Up @@ -517,15 +517,14 @@ void considersJsr303AnnotationsForTemplates() throws Exception {
assertValueForPath(model, "$._templates.default.properties[0].required", true);
}

/**
* @see #968
*/
@Test
@Test // #968
void considerJsonUnwrapped() throws Exception {

UnwrappedExample unwrappedExample = new UnwrappedExample();

unwrappedExample.element = new UnwrappedExampleElement();
unwrappedExample.element.firstname = "john";

assertValueForPath(unwrappedExample, "$.firstname", "john");
}

Expand Down Expand Up @@ -634,17 +633,17 @@ public String getFirstname() {
return firstname;
}
}

public static class UnwrappedExample extends RepresentationModel<UnwrappedExample> {

private UnwrappedExampleElement element;

@JsonUnwrapped
public UnwrappedExampleElement getElement(){
public UnwrappedExampleElement getElement() {
return element;
}
}

public static class UnwrappedExampleElement {
private @Getter String firstname;
}
Expand Down

0 comments on commit 5d1136e

Please sign in to comment.