#784 - Polishing.

* Formatting.
* Extracted conversion methods.
* Tested and fixed NPE with empty pojo.
* Tested and fixed NPE with empty page meta data.
This commit is contained in:
Jens Schauder
2019-01-14 10:54:14 +01:00
committed by Greg Turnquist
parent 8da3a851ce
commit b7a1c06f79
11 changed files with 465 additions and 186 deletions

View File

@@ -55,7 +55,9 @@ public class ResourceSupport implements Identifiable<Link> {
* @param link
*/
public void add(Link link) {
Assert.notNull(link, "Link must not be null!");
this.links.add(link);
}
@@ -65,7 +67,9 @@ public class ResourceSupport implements Identifiable<Link> {
* @param links
*/
public void add(Iterable<Link> links) {
Assert.notNull(links, "Given links must not be null!");
links.forEach(this::add);
}
@@ -75,7 +79,9 @@ public class ResourceSupport implements Identifiable<Link> {
* @param links must not be {@literal null}.
*/
public void add(Link... links) {
Assert.notNull(links, "Given links must not be null!");
add(Arrays.asList(links));
}

View File

@@ -87,10 +87,9 @@ public class PropertyUtils {
.collect(Collectors.toList());
}
@SuppressWarnings("unchecked")
public static <T> T createObjectFromProperties(Class<T> clazz, Map<String, Object> properties) {
Object obj = BeanUtils.instantiateClass(clazz);
T obj = BeanUtils.instantiateClass(clazz);
properties.forEach((key, value) -> {
Optional<PropertyDescriptor> possibleProperty = Optional.ofNullable(BeanUtils.getPropertyDescriptor(clazz, key));
@@ -105,7 +104,7 @@ public class PropertyUtils {
});
});
return (T) obj;
return obj;
}
/**

View File

@@ -26,6 +26,7 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.PagedResources;
@@ -59,12 +60,13 @@ import com.fasterxml.jackson.databind.type.TypeFactory;
* Jackson {@link SimpleModule} for {@literal UBER+JSON} serializers and deserializers.
*
* @author Greg Turnquist
* @author Jens Schauder
* @since 1.0
*/
public class Jackson2UberModule extends SimpleModule {
public Jackson2UberModule() {
super("uber-module", new Version(1, 0, 0, null, "org.springframework.hateoas", "spring-hateoas"));
setMixInAnnotation(ResourceSupport.class, ResourceSupportMixin.class);
@@ -81,7 +83,8 @@ public class Jackson2UberModule extends SimpleModule {
/**
* Custom {@link JsonSerializer} to render {@link ResourceSupport} into {@literal UBER+JSON}.
*/
static class UberResourceSupportSerializer extends ContainerSerializer<ResourceSupport> implements ContextualSerializer {
static class UberResourceSupportSerializer extends ContainerSerializer<ResourceSupport>
implements ContextualSerializer {
private final BeanProperty property;
@@ -98,14 +101,14 @@ public class Jackson2UberModule extends SimpleModule {
@Override
public void serialize(ResourceSupport value, JsonGenerator gen, SerializerProvider provider) throws IOException {
UberDocument doc = new UberDocument()
.withUber(new Uber()
.withVersion("1.0")
.withData(extractLinksAndContent(value)));
UberDocument doc = new UberDocument() //
.withUber(new Uber() //
.withVersion("1.0") //
.withData(extractLinksAndContent(value)));
provider
.findValueSerializer(UberDocument.class, property)
.serialize(doc, gen, provider);
provider //
.findValueSerializer(UberDocument.class, property) //
.serialize(doc, gen, provider);
}
@Override
@@ -129,7 +132,8 @@ public class Jackson2UberModule extends SimpleModule {
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property)
throws JsonMappingException {
return new UberResourceSupportSerializer(property);
}
}
@@ -155,13 +159,13 @@ public class Jackson2UberModule extends SimpleModule {
public void serialize(Resource<?> value, JsonGenerator gen, SerializerProvider provider) throws IOException {
UberDocument doc = new UberDocument()
.withUber(new Uber()
.withVersion("1.0")
.withData(extractLinksAndContent(value)));
.withUber(new Uber()
.withVersion("1.0")
.withData(extractLinksAndContent(value)));
provider
.findValueSerializer(UberDocument.class, property)
.serialize(doc, gen, provider);
provider //
.findValueSerializer(UberDocument.class, property) //
.serialize(doc, gen, provider);
}
@Override
@@ -185,7 +189,8 @@ public class Jackson2UberModule extends SimpleModule {
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property)
throws JsonMappingException {
return new UberResourceSerializer(property);
}
}
@@ -210,14 +215,14 @@ public class Jackson2UberModule extends SimpleModule {
@Override
public void serialize(Resources<?> value, JsonGenerator gen, SerializerProvider provider) throws IOException {
UberDocument doc = new UberDocument()
.withUber(new Uber()
.withVersion("1.0")
.withData(extractLinksAndContent(value)));
UberDocument doc = new UberDocument() //
.withUber(new Uber() //
.withVersion("1.0") //
.withData(extractLinksAndContent(value)));
provider
.findValueSerializer(UberDocument.class, property)
.serialize(doc, gen, provider);
provider //
.findValueSerializer(UberDocument.class, property) //
.serialize(doc, gen, provider);
}
@Override
@@ -241,7 +246,8 @@ public class Jackson2UberModule extends SimpleModule {
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property)
throws JsonMappingException {
return new UberResourcesSerializer(property);
}
}
@@ -249,7 +255,8 @@ public class Jackson2UberModule extends SimpleModule {
/**
* Custom {@link JsonSerializer} to render {@link PagedResources} into {@literal UBER+JSON}.
*/
static class UberPagedResourcesSerializer extends ContainerSerializer<PagedResources<?>> implements ContextualSerializer {
static class UberPagedResourcesSerializer extends ContainerSerializer<PagedResources<?>>
implements ContextualSerializer {
private BeanProperty property;
@@ -266,14 +273,14 @@ public class Jackson2UberModule extends SimpleModule {
@Override
public void serialize(PagedResources<?> value, JsonGenerator gen, SerializerProvider provider) throws IOException {
UberDocument doc = new UberDocument()
.withUber(new Uber()
.withVersion("1.0")
.withData(extractLinksAndContent(value)));
UberDocument doc = new UberDocument() //
.withUber(new Uber() //
.withVersion("1.0") //
.withData(extractLinksAndContent(value)));
provider
.findValueSerializer(UberDocument.class, property)
.serialize(doc, gen, provider);
provider //
.findValueSerializer(UberDocument.class, property) //
.serialize(doc, gen, provider);
}
@Override
@@ -297,7 +304,8 @@ public class Jackson2UberModule extends SimpleModule {
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property)
throws JsonMappingException {
return new UberPagedResourcesSerializer(property);
}
}
@@ -320,7 +328,8 @@ public class Jackson2UberModule extends SimpleModule {
/**
* Custom {@link StdDeserializer} to deserialize {@link ResourceSupport}.
*/
static class UberResourceSupportDeserializer extends ContainerDeserializerBase<ResourceSupport> implements ContextualDeserializer {
static class UberResourceSupportDeserializer extends ContainerDeserializerBase<ResourceSupport>
implements ContextualDeserializer {
private JavaType contentType;
@@ -333,33 +342,44 @@ public class Jackson2UberModule extends SimpleModule {
UberResourceSupportDeserializer() {
this(TypeFactory.defaultInstance().constructSimpleType(UberDocument.class, new JavaType[0]));
}
@Override
public ResourceSupport deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
UberDocument doc = p.getCodec().readValue(p, UberDocument.class);
List<Link> links = doc.getUber().getLinks();
return doc.getUber().getData().stream()
.filter(uberData -> !StringUtils.isEmpty(uberData.getName()))
.findFirst()
.map(uberData -> {
return doc.getUber().getData().stream() //
.filter(uberData -> !StringUtils.isEmpty(uberData.getName())) //
.findFirst() //
.map(uberData -> convertToResourceSupport(uberData, links)) //
.orElseGet(() -> {
Map<String, Object> properties = uberData.getData().stream()
ResourceSupport resourceSupport = new ResourceSupport();
resourceSupport.add(links);
return resourceSupport;
});
}
@NotNull
private ResourceSupport convertToResourceSupport(UberData uberData, List<Link> links) {
List<UberData> data = uberData.getData();
Map<String, Object> properties;
if (data == null) {
properties = new HashMap<>();
} else {
properties = data.stream() //
.collect(Collectors.toMap(UberData::getName, UberData::getValue));
}
ResourceSupport resourceSupport = (ResourceSupport) PropertyUtils
.createObjectFromProperties(this.getContentType().getRawClass(), properties);
ResourceSupport obj = (ResourceSupport) PropertyUtils.createObjectFromProperties(this.getContentType().getRawClass(), properties);
resourceSupport.add(links);
obj.add(doc.getUber().getLinks());
return obj;
})
.orElseGet(() -> {
ResourceSupport resourceSupport = new ResourceSupport();
resourceSupport.add(doc.getUber().getLinks());
return resourceSupport;
});
return resourceSupport;
}
@Override
@@ -368,7 +388,8 @@ public class Jackson2UberModule extends SimpleModule {
}
@Override
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException {
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property)
throws JsonMappingException {
if (property != null) {
JavaType vc = property.getType().getContentType();
@@ -379,7 +400,7 @@ public class Jackson2UberModule extends SimpleModule {
}
/**
* Accesor for deserializer use for deserializing content values.
* Accessor for deserializer use for deserializing content values.
*/
@Override
public JsonDeserializer<Object> getContentDeserializer() {
@@ -390,7 +411,8 @@ public class Jackson2UberModule extends SimpleModule {
/**
* Custom {@link StdDeserializer} to deserialize {@link Resource}.
*/
static class UberResourceDeserializer extends ContainerDeserializerBase<Resource<?>> implements ContextualDeserializer {
static class UberResourceDeserializer extends ContainerDeserializerBase<Resource<?>>
implements ContextualDeserializer {
private JavaType contentType;
@@ -408,30 +430,35 @@ public class Jackson2UberModule extends SimpleModule {
public Resource<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
UberDocument doc = p.getCodec().readValue(p, UberDocument.class);
List<Link> links = doc.getUber().getLinks();
return doc.getUber().getData().stream()
.filter(uberData -> !StringUtils.isEmpty(uberData.getName()))
.findFirst()
.map(uberData -> {
return doc.getUber().getData().stream().filter(uberData -> !StringUtils.isEmpty(uberData.getName())).findFirst()
.map(uberData -> convertUberDataToResource(uberData, links)).orElseThrow(
() -> new IllegalStateException("No data entry containing a 'value' was found in this document!"));
}
List<Link> links = doc.getUber().getLinks();
@NotNull
private Resource<Object> convertUberDataToResource(UberData uberData, List<Link> links) {
// Primitive type
if (uberData.getData().size() == 1 && uberData.getData().get(0).getName() == null) {
Object scalarValue = uberData.getData().get(0).getValue();
return new Resource<>(scalarValue, links);
}
// Primitive type
List<UberData> data = uberData.getData();
if (data != null && data.size() == 1 && data.get(0).getName() == null) {
Object scalarValue = data.get(0).getValue();
return new Resource<>(scalarValue, links);
}
Map<String, Object> properties = uberData.getData().stream()
.collect(Collectors.toMap(UberData::getName, UberData::getValue));
Map<String, Object> properties;
if (data == null) {
properties = new HashMap<>();
} else {
properties = data.stream().collect(Collectors.toMap(UberData::getName, UberData::getValue));
}
JavaType rootType = JacksonHelper.findRootType(this.contentType);
Object value = PropertyUtils.createObjectFromProperties(rootType.getRawClass(), properties);
return new Resource<>(value, links);
})
.orElseThrow(() -> new IllegalStateException("No data entry containing a 'value' was found in this document!"));
JavaType rootType = JacksonHelper.findRootType(this.contentType);
Object value = PropertyUtils.createObjectFromProperties(rootType.getRawClass(), properties);
return new Resource<>(value, links);
}
@Override
@@ -440,7 +467,8 @@ public class Jackson2UberModule extends SimpleModule {
}
@Override
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException {
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property)
throws JsonMappingException {
if (property != null) {
JavaType vc = property.getType().getContentType();
@@ -462,7 +490,8 @@ public class Jackson2UberModule extends SimpleModule {
/**
* Custom {@link StdDeserializer} to deserialize {@link Resources}.
*/
static class UberResourcesDeserializer extends ContainerDeserializerBase<Resources<?>> implements ContextualDeserializer {
static class UberResourcesDeserializer extends ContainerDeserializerBase<Resources<?>>
implements ContextualDeserializer {
private JavaType contentType;
@@ -487,8 +516,7 @@ public class Jackson2UberModule extends SimpleModule {
}
/**
* Accessor for declared type of contained value elements; either exact
* type, or one of its supertypes.
* Accessor for declared type of contained value elements; either exact type, or one of its supertypes.
*/
@Override
public JavaType getContentType() {
@@ -496,7 +524,8 @@ public class Jackson2UberModule extends SimpleModule {
}
@Override
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException {
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property)
throws JsonMappingException {
if (property != null) {
JavaType vc = property.getType().getContentType();
@@ -518,7 +547,8 @@ public class Jackson2UberModule extends SimpleModule {
/**
* Custom {@link StdDeserializer} to deserialize {@link PagedResources}.
*/
static class UberPagedResourcesDeserializer extends ContainerDeserializerBase<PagedResources<?>> implements ContextualDeserializer {
static class UberPagedResourcesDeserializer extends ContainerDeserializerBase<PagedResources<?>>
implements ContextualDeserializer {
private JavaType contentType;
@@ -541,13 +571,12 @@ public class Jackson2UberModule extends SimpleModule {
Resources<?> resources = extractResources(doc, rootType, this.contentType);
PageMetadata pageMetadata = extractPagingMetadata(doc);
return new PagedResources<>(resources.getContent(), pageMetadata, resources.getLinks());
}
/**
* Accessor for declared type of contained value elements; either exact
* type, or one of its supertypes.
* Accessor for declared type of contained value elements; either exact type, or one of its supertypes.
*/
@Override
public JavaType getContentType() {
@@ -555,7 +584,8 @@ public class Jackson2UberModule extends SimpleModule {
}
@Override
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException {
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property)
throws JsonMappingException {
if (property != null) {
JavaType vc = property.getType().getContentType();
@@ -572,6 +602,7 @@ public class Jackson2UberModule extends SimpleModule {
public JsonDeserializer<Object> getContentDeserializer() {
return null;
}
}
/**
@@ -597,21 +628,33 @@ public class Jackson2UberModule extends SimpleModule {
List<Link> resourceLinks = new ArrayList<>();
Resource<?> resource = null;
for (UberData item : uberData.getData()) {
List<UberData> data = uberData.getData();
if (data == null) {
throw new RuntimeException("No content!");
}
for (UberData item : data) {
if (item.getRel() != null) {
item.getRel().forEach(rel -> resourceLinks.add(new Link(item.getUrl(), rel)));
} else {
// Primitive type
if (item.getData().size() == 1 && item.getData().get(0).getName() == null) {
List<UberData> itemData = item.getData();
if (itemData != null && itemData.size() == 1 && itemData.get(0).getName() == null) {
Object scalarValue = item.getData().get(0).getValue();
Object scalarValue = itemData.get(0).getValue();
resource = new Resource<>(scalarValue, uberData.getLinks());
} else {
Map<String, Object> properties = item.getData().stream()
.collect(Collectors.toMap(UberData::getName, UberData::getValue));
Map<String, Object> properties;
if (itemData == null) {
properties = new HashMap<>();
} else {
properties = itemData.stream() //
.collect(Collectors.toMap(UberData::getName, UberData::getValue));
}
Object obj = PropertyUtils.createObjectFromProperties(rootType.getRawClass(), properties);
resource = new Resource<>(obj, uberData.getLinks());
}
@@ -619,6 +662,7 @@ public class Jackson2UberModule extends SimpleModule {
}
if (resource != null) {
resource.add(resourceLinks);
content.add(resource);
} else {
@@ -637,10 +681,8 @@ public class Jackson2UberModule extends SimpleModule {
* ...or return a Resources<T>
*/
List<Object> resourceLessContent = content.stream()
.map(item -> (Resource<?>) item)
.map(Resource::getContent)
.collect(Collectors.toList());
List<Object> resourceLessContent = content.stream().map(item -> (Resource<?>) item).map(Resource::getContent)
.collect(Collectors.toList());
return new Resources<>(resourceLessContent, doc.getUber().getLinks());
}
@@ -649,35 +691,46 @@ public class Jackson2UberModule extends SimpleModule {
private static PageMetadata extractPagingMetadata(UberDocument doc) {
return doc.getUber().getData().stream()
.filter(uberData -> uberData.getName() != null && uberData.getName().equals("page"))
.findFirst()
.map(uberData -> {
int size = 0;
int number = 0;
int totalElements = 0;
int totalPages = 0;
.filter(uberData -> uberData.getName() != null && uberData.getName().equals("page")).findFirst()
.map(Jackson2UberModule::convertUberDataToPageMetaData).orElse(null);
}
for (UberData data : uberData.getData()) {
if (data.getName().equals("size")) {
@NotNull
private static PageMetadata convertUberDataToPageMetaData(UberData uberData) {
int size = 0;
int number = 0;
int totalElements = 0;
int totalPages = 0;
List<UberData> content = uberData.getData();
if (content != null) {
for (UberData data : content) {
String name = data.getName();
switch (name) {
case "size":
size = (int) data.getValue();
}
break;
if (data.getName().equals("number")) {
case "number":
number = (int) data.getValue();
}
break;
if (data.getName().equals("totalElements")) {
case "totalElements":
totalElements = (int) data.getValue();
}
break;
if (data.getName().equals("totalPages")) {
case "totalPages":
totalPages = (int) data.getValue();
}
}
return new PageMetadata(size, number, totalElements, totalPages);
})
.orElse(null);
default:
}
}
}
return new PageMetadata(size, number, totalElements, totalPages);
}
/**
@@ -708,12 +761,14 @@ public class Jackson2UberModule extends SimpleModule {
}
@Override
public JsonDeserializer<?> deserializerInstance(DeserializationConfig config, Annotated annotated, Class<?> deserClass) {
public JsonDeserializer<?> deserializerInstance(DeserializationConfig config, Annotated annotated,
Class<?> deserClass) {
return (JsonDeserializer<?>) findInstance(deserClass);
}
@Override
public KeyDeserializer keyDeserializerInstance(DeserializationConfig config, Annotated annotated, Class<?> keyDeserClass) {
public KeyDeserializer keyDeserializerInstance(DeserializationConfig config, Annotated annotated,
Class<?> keyDeserClass) {
return (KeyDeserializer) findInstance(keyDeserClass);
}
@@ -723,7 +778,8 @@ public class Jackson2UberModule extends SimpleModule {
}
@Override
public TypeResolverBuilder<?> typeResolverBuilderInstance(MapperConfig<?> config, Annotated annotated, Class<?> builderClass) {
public TypeResolverBuilder<?> typeResolverBuilderInstance(MapperConfig<?> config, Annotated annotated,
Class<?> builderClass) {
return (TypeResolverBuilder<?>) findInstance(builderClass);
}
@@ -738,4 +794,4 @@ public class Jackson2UberModule extends SimpleModule {
return result != null ? result : BeanUtils.instantiateClass(type);
}
}
}
}

View File

@@ -252,7 +252,7 @@ class UberData {
.withName("totalPages")
.withValue(resources.getMetadata().getTotalPages()))));
}
return collectionOfResources;
}
@@ -326,7 +326,7 @@ class UberData {
return extractLinksAndContent(new Resource<>(item));
}
/**
* Turn a {@list List} of {@link Link}s into a {@link Map}, where you can see ALL the rels of a given
* link.
@@ -359,7 +359,7 @@ class UberData {
.flatMap(link -> link.getAffordances().stream())
.map(affordance -> (UberAffordanceModel) affordance.getAffordanceModel(MediaTypes.UBER_JSON))
.map(model -> {
if (model.getHttpMethod().equals(HttpMethod.GET)) {
String suffix = model.getQueryProperties().stream()
@@ -372,7 +372,7 @@ class UberData {
return new UberData()
.withName(model.getName())
.withRel(Arrays.asList(model.getName()))
.withRel(Collections.singletonList(model.getName()))
.withUrl(model.getLink().expand().getHref() + suffix)
.withAction(model.getAction());
@@ -380,7 +380,7 @@ class UberData {
return new UberData()
.withName(model.getName())
.withRel(Arrays.asList(model.getName()))
.withRel(Collections.singletonList(model.getName()))
.withUrl(model.getLink().expand().getHref())
.withModel(model.getInputProperties().stream()
.map(UberData::getName)
@@ -431,8 +431,8 @@ class UberData {
private static List<UberData> extractProperties(Object obj) {
if (PRIMITIVE_TYPES.contains(obj.getClass())) {
return Arrays.asList(new UberData()
.withValue(obj));
return Collections.singletonList(new UberData()
.withValue(obj));
}
return PropertyUtils.findProperties(obj).entrySet().stream()

View File

@@ -65,12 +65,6 @@ class UberDocument {
return (UberDocument) object;
}
if (object instanceof Iterable) {
} else if (object instanceof Map) {
}
throw new IllegalArgumentException("Don't know how to handle type : " + object.getClass());
}
}

View File

@@ -25,6 +25,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.jetbrains.annotations.NotNull;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.io.ClassPathResource;
@@ -43,13 +44,15 @@ import com.fasterxml.jackson.databind.SerializationFeature;
/**
* @author Greg Turnquist
* @author Jens Schauder
*/
public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingIntegrationTest {
static final Links PAGINATION_LINKS = new Links(
new Link("localhost", Link.REL_SELF),
new Link("foo", Link.REL_NEXT),
new Link("bar", Link.REL_PREVIOUS));
static final Links PAGINATION_LINKS = new Links( //
new Link("localhost", Link.REL_SELF), //
new Link("foo", Link.REL_NEXT), //
new Link("bar", Link.REL_PREVIOUS)//
);
@Before
public void setUpModule() {
@@ -68,7 +71,8 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
ResourceSupport resourceSupport = new ResourceSupport();
resourceSupport.add(new Link("localhost").withSelfRel());
assertThat(write(resourceSupport)).isEqualTo(MappingUtils.read(new ClassPathResource("resource-support.json", getClass())));
assertThat(write(resourceSupport))
.isEqualTo(MappingUtils.read(new ClassPathResource("resource-support.json", getClass())));
}
/**
@@ -79,8 +83,10 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
ResourceSupport expected = new ResourceSupport();
expected.add(new Link("localhost"));
assertThat(read(MappingUtils.read(new ClassPathResource("resource-support.json", getClass())), ResourceSupport.class))
.isEqualTo(expected);
assertThat(
read(MappingUtils.read(new ClassPathResource("resource-support.json", getClass())), ResourceSupport.class))
.isEqualTo(expected);
}
/**
@@ -93,7 +99,8 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
resourceSupport.add(new Link("localhost"));
resourceSupport.add(new Link("localhost2").withRel("orders"));
assertThat(write(resourceSupport)).isEqualTo(MappingUtils.read(new ClassPathResource("resource-support-2.json", getClass())));
assertThat(write(resourceSupport))
.isEqualTo(MappingUtils.read(new ClassPathResource("resource-support-2.json", getClass())));
}
/**
@@ -106,8 +113,9 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
expected.add(new Link("localhost"));
expected.add(new Link("localhost2").withRel("orders"));
assertThat(read(MappingUtils.read(new ClassPathResource("resource-support-2.json", getClass())), ResourceSupport.class))
.isEqualTo(expected);
assertThat(
read(MappingUtils.read(new ClassPathResource("resource-support-2.json", getClass())), ResourceSupport.class))
.isEqualTo(expected);
}
/**
@@ -162,7 +170,7 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
String resourcesJson = MappingUtils.read(new ClassPathResource("resources.json", getClass()));
JavaType resourcesType = mapper.getTypeFactory().constructParametricType(Resources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, String.class));
mapper.getTypeFactory().constructParametricType(Resource.class, String.class));
Resources<Resource<String>> result = mapper.readValue(resourcesJson, resourcesType);
@@ -176,6 +184,7 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
public void renderSimpleResource() throws Exception {
Resource<String> data = new Resource<>("first", new Link("localhost"));
assertThat(write(data)).isEqualTo(MappingUtils.read(new ClassPathResource("resource.json", getClass())));
}
@@ -186,6 +195,7 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
public void renderResourceWithCustomRel() throws Exception {
Resource<String> data2 = new Resource<>("second", new Link("localhost").withRel("custom"));
assertThat(write(data2)).isEqualTo(MappingUtils.read(new ClassPathResource("resource2.json", getClass())));
}
@@ -195,10 +205,9 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
@Test
public void renderResourceWithMultipleLinks() throws Exception {
Resource<String> data3 = new Resource<>("third",
new Link("localhost"),
new Link("second").withRel("second"),
new Link("third").withRel("third"));
Resource<String> data3 = new Resource<>("third", new Link("localhost"), new Link("second").withRel("second"),
new Link("third").withRel("third"));
assertThat(write(data3)).isEqualTo(MappingUtils.read(new ClassPathResource("resource3.json", getClass())));
}
@@ -208,11 +217,10 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
@Test
public void renderResourceWithMultipleRels() throws Exception {
Resource<String> data4 = new Resource<>("third",
new Link("localhost"),
new Link("localhost").withRel("http://example.org/rels/todo"),
new Link("second").withRel("second"),
new Link("third").withRel("third"));
Resource<String> data4 = new Resource<>("third", new Link("localhost"),
new Link("localhost").withRel("http://example.org/rels/todo"), new Link("second").withRel("second"),
new Link("third").withRel("third"));
assertThat(write(data4)).isEqualTo(MappingUtils.read(new ClassPathResource("resource4.json", getClass())));
}
@@ -226,32 +234,28 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
Resource expected = new Resource<>("first", new Link("localhost"));
Resource<String> actual = mapper.readValue(MappingUtils.read(new ClassPathResource("resource.json", getClass())),
resourceStringType);
resourceStringType);
assertThat(actual).isEqualTo(expected);
Resource<String> expected2 = new Resource<>("second", new Link("localhost").withRel("custom"));
Resource<String> actual2 = mapper.readValue(MappingUtils.read(new ClassPathResource("resource2.json", getClass())),
resourceStringType);
resourceStringType);
assertThat(actual2).isEqualTo(expected2);
Resource<String> expected3 = new Resource<>("third",
new Link("localhost"),
new Link("second").withRel("second"),
new Link("third").withRel("third"));
Resource<String> expected3 = new Resource<>("third", new Link("localhost"), new Link("second").withRel("second"),
new Link("third").withRel("third"));
Resource<String> actual3 = mapper.readValue(MappingUtils.read(new ClassPathResource("resource3.json", getClass())),
resourceStringType);
resourceStringType);
assertThat(actual3).isEqualTo(expected3);
Resource<String> expected4 = new Resource<>("third",
new Link("localhost"),
new Link("localhost").withRel("http://example.org/rels/todo"),
new Link("second").withRel("second"),
new Link("third").withRel("third"));
Resource<String> expected4 = new Resource<>("third", new Link("localhost"),
new Link("localhost").withRel("http://example.org/rels/todo"), new Link("second").withRel("second"),
new Link("third").withRel("third"));
Resource<String> actual4 = mapper.readValue(MappingUtils.read(new ClassPathResource("resource4.json", getClass())),
resourceStringType);
resourceStringType);
assertThat(actual4).isEqualTo(expected4);
}
@@ -270,7 +274,8 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
resources.add(new Link("localhost"));
resources.add(new Link("/page/2").withRel("next"));
assertThat(write(resources)).isEqualTo(MappingUtils.read(new ClassPathResource("resources-with-resource-objects.json", getClass())));
assertThat(write(resources))
.isEqualTo(MappingUtils.read(new ClassPathResource("resources-with-resource-objects.json", getClass())));
}
/**
@@ -287,13 +292,60 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
expected.add(new Link("localhost"));
expected.add(new Link("/page/2").withRel("next"));
Resources<Resource<String>> actual = mapper.readValue(MappingUtils.read(new ClassPathResource("resources-with-resource-objects.json", getClass())),
mapper.getTypeFactory().constructParametricType(Resources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, String.class)));
Resources<Resource<String>> actual = mapper.readValue(
MappingUtils.read(new ClassPathResource("resources-with-resource-objects.json", getClass())),
mapper.getTypeFactory().constructParametricType(Resources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, String.class)));
assertThat(actual).isEqualTo(expected);
}
/**
* @see #784
*/
@Test
public void deserializeEmptyValue() throws Exception {
List<Resource<String>> data = new ArrayList<Resource<String>>();
data.add(new Resource<>("", new Link("localhost"), new Link("orders").withRel("orders")));
data.add(new Resource<>("second", new Link("remotehost"), new Link("order").withRel("orders")));
Resources expected = new Resources<>(data);
expected.add(new Link("localhost"));
expected.add(new Link("/page/2").withRel("next"));
Resources<Resource<String>> actual = mapper.readValue(
MappingUtils.read(new ClassPathResource("resources-with-resource-objects-and-empty-value.json", getClass())),
mapper.getTypeFactory().constructParametricType(Resources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, String.class)));
assertThat(actual).isEqualTo(expected);
}
/**
* @see #784
*/
@Test
public void deserializeEmptyResources() throws Exception {
List<Resource<String>> data = new ArrayList<Resource<String>>();
data.add(new Resource<>("first", new Link("localhost"), new Link("orders").withRel("orders")));
data.add(new Resource<>("second", new Link("remotehost"), new Link("order").withRel("orders")));
Resources expected = new Resources<>(data);
expected.add(new Link("localhost"));
expected.add(new Link("/page/2").withRel("next"));
assertThatThrownBy(() -> mapper.readValue( //
MappingUtils.read(new ClassPathResource("resources-with-empty-resource-objects.json", getClass())), //
mapper.getTypeFactory() //
.constructParametricType( //
Resources.class, //
mapper.getTypeFactory().constructParametricType(Resource.class, String.class) //
) //
)).isInstanceOf(RuntimeException.class);
}
/**
* @see #784
*/
@@ -308,8 +360,9 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
expected.add(new Link("localhost"));
expected.add(new Link("/page/2").withRel("next"));
Resources<String> actual = mapper.readValue(MappingUtils.read(new ClassPathResource("resources-with-resource-objects.json", getClass())),
mapper.getTypeFactory().constructParametricType(Resources.class, String.class));
Resources<String> actual = mapper.readValue(
MappingUtils.read(new ClassPathResource("resources-with-resource-objects.json", getClass())),
mapper.getTypeFactory().constructParametricType(Resources.class, String.class));
assertThat(actual).isEqualTo(expected);
}
@@ -337,8 +390,25 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
Employee employee = new Employee("Frodo", "ring bearer");
Resource<Employee> expected = new Resource<>(employee, new Link("/employees/1").withSelfRel());
Resource<Employee> actual = mapper.readValue(MappingUtils.read(new ClassPathResource("resource-with-simple-pojo.json", getClass())),
mapper.getTypeFactory().constructParametricType(Resource.class, Employee.class));
Resource<Employee> actual = mapper.readValue(
MappingUtils.read(new ClassPathResource("resource-with-simple-pojo.json", getClass())),
mapper.getTypeFactory().constructParametricType(Resource.class, Employee.class));
assertThat(actual).isEqualTo(expected);
}
/**
* @see #784
*/
@Test
public void deserializeWrappedEmptyPojo() throws IOException {
Employee employee = new Employee();
Resource<Employee> expected = new Resource<>(employee, new Link("/employees/1").withSelfRel());
Resource<Employee> actual = mapper.readValue(
MappingUtils.read(new ClassPathResource("resource-with-empty-pojo.json", getClass())),
mapper.getTypeFactory().constructParametricType(Resource.class, Employee.class));
assertThat(actual).isEqualTo(expected);
}
@@ -369,8 +439,24 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
expected.add(new Link("/employees").withRel("employees"));
EmployeeResource actual = mapper.readValue(
MappingUtils.read(new ClassPathResource("resource-support-pojo.json", getClass())),
EmployeeResource.class);
MappingUtils.read(new ClassPathResource("resource-support-pojo.json", getClass())), EmployeeResource.class);
assertThat(actual).isEqualTo(expected);
}
/**
* @see #784
*/
@Test
public void deserializeEmptyConcreteResourceSupport() throws Exception {
EmployeeResource expected = new EmployeeResource(null, null);
expected.add(new Link("/employees/1").withSelfRel());
expected.add(new Link("/employees").withRel("employees"));
EmployeeResource actual = mapper.readValue(
MappingUtils.read(new ClassPathResource("resource-support-pojo-empty.json", getClass())),
EmployeeResource.class);
assertThat(actual).isEqualTo(expected);
}
@@ -391,24 +477,42 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
@Test
public void deserializesPagedResource() throws Exception {
PagedResources<Resource<Employee>> result = mapper.readValue(MappingUtils.read(new ClassPathResource("paged-resources.json", getClass())),
mapper.getTypeFactory().constructParametricType(PagedResources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, Employee.class)));
PagedResources<Resource<Employee>> result = mapper.readValue(
MappingUtils.read(new ClassPathResource("paged-resources.json", getClass())),
mapper.getTypeFactory().constructParametricType(PagedResources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, Employee.class)));
assertThat(result).isEqualTo(setupAnnotatedPagedResources());
}
/**
* @see #784
*/
@Test
public void deserializesPagedResourceWithEmptyPageInformation() throws Exception {
PagedResources<Resource<Employee>> result = mapper.readValue(
MappingUtils.read(new ClassPathResource("paged-resources-empty-page.json", getClass())),
mapper.getTypeFactory().constructParametricType(PagedResources.class,
mapper.getTypeFactory().constructParametricType(Resource.class, Employee.class)));
assertThat(result).isEqualTo(setupAnnotatedPagedResources(0,0));
}
private static Resources<Resource<Employee>> setupAnnotatedPagedResources() {
return setupAnnotatedPagedResources(2, 4);
}
@NotNull
private static Resources<Resource<Employee>> setupAnnotatedPagedResources(int size, int totalElements) {
List<Resource<Employee>> content = new ArrayList<>();
Employee employee = new Employee("Frodo", "ring bearer");
Resource<Employee> employeeResource = new Resource<>(employee, new Link("/employees/1").withSelfRel());
content.add(employeeResource);
return new PagedResources<>(
content,
new PagedResources.PageMetadata(2, 0, 4),
PAGINATION_LINKS);
return new PagedResources<>(content, new PagedResources.PageMetadata(size, 0, totalElements), PAGINATION_LINKS);
}
@Data
@@ -429,4 +533,4 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte
private String role;
}
}
}

View File

@@ -0,0 +1,32 @@
{
"uber" : {
"version" : "1.0",
"data" : [ {
"rel" : [ "self" ],
"url" : "localhost"
}, {
"rel" : [ "next" ],
"url" : "foo"
}, {
"rel" : [ "prev" ],
"url" : "bar"
}, {
"data" : [ {
"rel" : [ "self" ],
"url" : "/employees/1"
}, {
"name" : "employee",
"data" : [ {
"name" : "role",
"value" : "ring bearer"
}, {
"name" : "name",
"value" : "Frodo"
} ]
} ]
}, {
"name" : "page",
"data" : []
} ]
}
}

View File

@@ -0,0 +1,14 @@
{
"uber" : {
"version" : "1.0",
"data" : [ {
"rel" : [ "self" ],
"url" : "/employees/1"
}, {
"rel" : [ "employees" ],
"url" : "/employees"
}, {
"name" : "employeeResource",
"data" : [] } ]
}
}

View File

@@ -0,0 +1,12 @@
{
"uber" : {
"version" : "1.0",
"data" : [ {
"rel" : [ "self" ],
"url" : "/employees/1"
}, {
"name" : "employee",
"data" : [ ]
} ]
}
}

View File

@@ -0,0 +1,26 @@
{
"uber" : {
"version" : "1.0",
"data" : [ {
"rel" : [ "self" ],
"url" : "localhost"
}, {
"rel" : [ "next" ],
"url" : "/page/2"
}, {
"data" : [ {
"rel" : [ "self" ],
"url" : "localhost"
}, {
"rel" : [ "orders" ],
"url" : "orders"
}, {
"name" : "string",
"data" : [ {
"value" : "first"
} ]
} ]
}, {
"data" : [] } ]
}
}

View File

@@ -0,0 +1,36 @@
{
"uber" : {
"version" : "1.0",
"data" : [ {
"rel" : [ "self" ],
"url" : "localhost"
}, {
"rel" : [ "next" ],
"url" : "/page/2"
}, {
"data" : [ {
"rel" : [ "self" ],
"url" : "localhost"
}, {
"rel" : [ "orders" ],
"url" : "orders"
}, {
"name" : "string",
"data" : []
} ]
}, {
"data" : [ {
"rel" : [ "self" ],
"url" : "remotehost"
}, {
"rel" : [ "orders" ],
"url" : "order"
}, {
"name" : "string",
"data" : [ {
"value" : "second"
} ]
} ]
} ]
}
}