diff --git a/src/main/java/org/springframework/hateoas/uber/Jackson2UberModule.java b/src/main/java/org/springframework/hateoas/uber/Jackson2UberModule.java index 523f977d..7f40591b 100644 --- a/src/main/java/org/springframework/hateoas/uber/Jackson2UberModule.java +++ b/src/main/java/org/springframework/hateoas/uber/Jackson2UberModule.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2018 the original author or authors. + * Copyright 2017-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -433,16 +433,16 @@ public class Jackson2UberModule extends SimpleModule { List links = doc.getUber().getLinks(); return doc.getUber().getData().stream().filter(uberData -> !StringUtils.isEmpty(uberData.getName())).findFirst() - .map(uberData -> convertUberDataToResource(uberData, links)).orElseThrow( + .map(uberData -> convertToResource(uberData, links)).orElseThrow( () -> new IllegalStateException("No data entry containing a 'value' was found in this document!")); } @NotNull - private Resource convertUberDataToResource(UberData uberData, List links) { + private Resource convertToResource(UberData uberData, List links) { // Primitive type List data = uberData.getData(); - if (data != null && data.size() == 1 && data.get(0).getName() == null) { + if (isPrimitiveType(data)) { Object scalarValue = data.get(0).getValue(); return new Resource<>(scalarValue, links); } @@ -641,7 +641,7 @@ public class Jackson2UberModule extends SimpleModule { // Primitive type List itemData = item.getData(); - if (itemData != null && itemData.size() == 1 && itemData.get(0).getName() == null) { + if (isPrimitiveType(itemData)) { Object scalarValue = itemData.get(0).getValue(); resource = new Resource<>(scalarValue, uberData.getLinks()); @@ -681,18 +681,26 @@ public class Jackson2UberModule extends SimpleModule { * ...or return a Resources */ - List resourceLessContent = content.stream().map(item -> (Resource) item).map(Resource::getContent) + List resourceLessContent = content.stream() + .map(item -> (Resource) item) + .map(Resource::getContent) .collect(Collectors.toList()); return new Resources<>(resourceLessContent, doc.getUber().getLinks()); } } + private static boolean isPrimitiveType(List data) { + return data != null && data.size() == 1 && data.get(0).getName() == null; + } + private static PageMetadata extractPagingMetadata(UberDocument doc) { return doc.getUber().getData().stream() - .filter(uberData -> uberData.getName() != null && uberData.getName().equals("page")).findFirst() - .map(Jackson2UberModule::convertUberDataToPageMetaData).orElse(null); + .filter(uberData -> uberData.getName() != null && uberData.getName().equals("page")) + .findFirst() + .map(Jackson2UberModule::convertUberDataToPageMetaData) + .orElse(null); } @NotNull @@ -724,6 +732,7 @@ public class Jackson2UberModule extends SimpleModule { case "totalPages": totalPages = (int) data.getValue(); + break; default: } diff --git a/src/main/java/org/springframework/hateoas/uber/PagedResourcesMixin.java b/src/main/java/org/springframework/hateoas/uber/PagedResourcesMixin.java index 8ae58c9b..c2b9d9ee 100644 --- a/src/main/java/org/springframework/hateoas/uber/PagedResourcesMixin.java +++ b/src/main/java/org/springframework/hateoas/uber/PagedResourcesMixin.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2018-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ import org.springframework.hateoas.uber.Jackson2UberModule.UberPagedResourcesDes import com.fasterxml.jackson.databind.annotation.JsonDeserialize; /** - * Jackson 2 mixin to handle {@link PagedResources}. + * Jackson 2 mixin to handle {@link PagedResources} for {@literal UBER+JSON}. * * @author Greg Turnquist * @since 1.0 diff --git a/src/main/java/org/springframework/hateoas/uber/ResourceMixin.java b/src/main/java/org/springframework/hateoas/uber/ResourceMixin.java index 476895b8..8c2e1605 100644 --- a/src/main/java/org/springframework/hateoas/uber/ResourceMixin.java +++ b/src/main/java/org/springframework/hateoas/uber/ResourceMixin.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2018-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ import org.springframework.hateoas.uber.Jackson2UberModule.UberResourceDeseriali import com.fasterxml.jackson.databind.annotation.JsonDeserialize; /** - * Jackson 2 mixin to handle {@link Resource}. + * Jackson 2 mixin to handle {@link Resource} for {@literal UBER+JSON}. * * @author Greg Turnquist * @since 1.0 diff --git a/src/main/java/org/springframework/hateoas/uber/ResourceSupportMixin.java b/src/main/java/org/springframework/hateoas/uber/ResourceSupportMixin.java index 21851e9a..4a378486 100644 --- a/src/main/java/org/springframework/hateoas/uber/ResourceSupportMixin.java +++ b/src/main/java/org/springframework/hateoas/uber/ResourceSupportMixin.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2018-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ import org.springframework.hateoas.uber.Jackson2UberModule.UberResourceSupportDe import com.fasterxml.jackson.databind.annotation.JsonDeserialize; /** - * Jackson 2 mixin to handle {@link ResourceSupport}. + * Jackson 2 mixin to handle {@link ResourceSupport} for {@literal UBER+JSON}. * * @author Greg Turnquist * @since 1.0 diff --git a/src/main/java/org/springframework/hateoas/uber/ResourcesMixin.java b/src/main/java/org/springframework/hateoas/uber/ResourcesMixin.java index a1ab3a2e..53be5cda 100644 --- a/src/main/java/org/springframework/hateoas/uber/ResourcesMixin.java +++ b/src/main/java/org/springframework/hateoas/uber/ResourcesMixin.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2018-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ import org.springframework.hateoas.uber.Jackson2UberModule.UberResourcesDeserial import com.fasterxml.jackson.databind.annotation.JsonDeserialize; /** - * Jackson 2 mixin to handle {@link Resources}. + * Jackson 2 mixin to handle {@link Resources} for {@literal UBER+JSON}. * * @author Greg Turnquist * @since 1.0 diff --git a/src/main/java/org/springframework/hateoas/uber/Uber.java b/src/main/java/org/springframework/hateoas/uber/Uber.java index 77560d61..57971dd6 100644 --- a/src/main/java/org/springframework/hateoas/uber/Uber.java +++ b/src/main/java/org/springframework/hateoas/uber/Uber.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2018-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,7 +31,7 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; /** - * Enclosing collection in an UBER representation. + * Enclosing collection in an {@literal UBER+JSON} representation. * * @author Greg Turnquist * @since 1.0 diff --git a/src/main/java/org/springframework/hateoas/uber/UberAction.java b/src/main/java/org/springframework/hateoas/uber/UberAction.java index dda0e6ff..868a0b10 100644 --- a/src/main/java/org/springframework/hateoas/uber/UberAction.java +++ b/src/main/java/org/springframework/hateoas/uber/UberAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2017 the original author or authors. + * Copyright 2014-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; /** - * Embodies possible actions for an UBER representation, mapped onto {@link HttpMethod}s. + * Embodies possible actions for an {@literal UBER+JSON} representation, mapped onto {@link HttpMethod}s. * * @author Dietrich Schulten * @author Greg Turnquist diff --git a/src/main/java/org/springframework/hateoas/uber/UberAffordanceModel.java b/src/main/java/org/springframework/hateoas/uber/UberAffordanceModel.java index ace0a1d7..6d588222 100644 --- a/src/main/java/org/springframework/hateoas/uber/UberAffordanceModel.java +++ b/src/main/java/org/springframework/hateoas/uber/UberAffordanceModel.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2018-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/main/java/org/springframework/hateoas/uber/UberAffordanceModelFactory.java b/src/main/java/org/springframework/hateoas/uber/UberAffordanceModelFactory.java index ede551be..6467d3e1 100644 --- a/src/main/java/org/springframework/hateoas/uber/UberAffordanceModelFactory.java +++ b/src/main/java/org/springframework/hateoas/uber/UberAffordanceModelFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2018-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/main/java/org/springframework/hateoas/uber/UberData.java b/src/main/java/org/springframework/hateoas/uber/UberData.java index 4126e0ec..07289f95 100644 --- a/src/main/java/org/springframework/hateoas/uber/UberData.java +++ b/src/main/java/org/springframework/hateoas/uber/UberData.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2018-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -45,6 +45,7 @@ import org.springframework.util.StringUtils; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; @@ -57,6 +58,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; @Value @Wither(AccessLevel.PACKAGE) @JsonInclude(Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) class UberData { private String id; @@ -109,28 +111,6 @@ class UberData { return this.action; } - /* - * Don't render if {@literal null}. - */ - public List getRel() { - - if (this.rel == null || this.rel.isEmpty()) { - return null; - } - return this.rel; - } - - /* - * Don't render if {@literal null}. - */ - public List getData() { - - if (this.data == null || this.data.isEmpty()) { - return null; - } - return this.data; - } - /* * Use a {@link Boolean} to support returning {@literal null}, and if it is {@literal null}, don't render. */ @@ -141,10 +121,6 @@ class UberData { .orElse(null); } - public void setTemplated(boolean __) { - // Ignore since "templated" is a virtual property - } - /* * Use a {@link Boolean} to support returning {@literal null}, and if it is {@literal null}, don't render. */ diff --git a/src/main/java/org/springframework/hateoas/uber/UberDocument.java b/src/main/java/org/springframework/hateoas/uber/UberDocument.java index 617c9f9a..2aea867e 100644 --- a/src/main/java/org/springframework/hateoas/uber/UberDocument.java +++ b/src/main/java/org/springframework/hateoas/uber/UberDocument.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2018-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,13 +21,12 @@ import lombok.Value; import lombok.experimental.Wither; import java.util.List; -import java.util.Map; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; /** - * Top-level element in an UBER representation. + * Top-level element in an {@literal UBER+JSON} representation. * * @author Greg Turnquist * @since 1.0 @@ -48,23 +47,4 @@ class UberDocument { UberDocument() { this("1.0", null, null); } - - /** - * Transform an object into a {@link UberDocument}. - * - * @param object - * @return - */ - static UberDocument toUberDocument(final Object object) { - - if (object == null) { - return null; - } - - if (object instanceof UberDocument) { - return (UberDocument) object; - } - - throw new IllegalArgumentException("Don't know how to handle type : " + object.getClass()); - } } \ No newline at end of file diff --git a/src/main/java/org/springframework/hateoas/uber/UberError.java b/src/main/java/org/springframework/hateoas/uber/UberError.java index c092d21d..08154f19 100644 --- a/src/main/java/org/springframework/hateoas/uber/UberError.java +++ b/src/main/java/org/springframework/hateoas/uber/UberError.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2018-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; /** - * UBER representation of an error. + * {@literal UBER+JSON} representation of an error. * * @author Greg Turnquist * @since 1.0 diff --git a/src/main/java/org/springframework/hateoas/uber/UberLinkDiscoverer.java b/src/main/java/org/springframework/hateoas/uber/UberLinkDiscoverer.java index f3bb0d88..ba44e1ce 100644 --- a/src/main/java/org/springframework/hateoas/uber/UberLinkDiscoverer.java +++ b/src/main/java/org/springframework/hateoas/uber/UberLinkDiscoverer.java @@ -29,7 +29,7 @@ import org.springframework.http.MediaType; import com.fasterxml.jackson.databind.ObjectMapper; /** - * Find links by rel in an UBER representation. + * Find links by rel in an {@literal UBER+JSON} representation. * * TODO: Pending https://github.com/json-path/JsonPath/issues/429, replace deserializing solution with JsonPath-based expression "$.uber.data[?(@.rel.indexOf('%s') != -1)].url" * diff --git a/src/test/java/org/springframework/hateoas/uber/Jackson2UberIntegrationTest.java b/src/test/java/org/springframework/hateoas/uber/Jackson2UberIntegrationTest.java index 2c4aba17..b8f12ed6 100644 --- a/src/test/java/org/springframework/hateoas/uber/Jackson2UberIntegrationTest.java +++ b/src/test/java/org/springframework/hateoas/uber/Jackson2UberIntegrationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2017-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ import org.junit.Before; import org.junit.Test; import org.springframework.core.io.ClassPathResource; import org.springframework.hateoas.AbstractJackson2MarshallingIntegrationTest; +import org.springframework.hateoas.IanaLinkRelation; import org.springframework.hateoas.Link; import org.springframework.hateoas.Links; import org.springframework.hateoas.PagedResources; @@ -49,9 +50,9 @@ import com.fasterxml.jackson.databind.SerializationFeature; 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)// + new Link("localhost", IanaLinkRelation.SELF.value()), // + new Link("foo", IanaLinkRelation.NEXT.value()), // + new Link("bar", IanaLinkRelation.PREV.value())// ); @Before @@ -284,7 +285,7 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte @Test public void deserializeResources() throws Exception { - List> data = new ArrayList>(); + List> data = new ArrayList<>(); 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"))); @@ -306,7 +307,7 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte @Test public void deserializeEmptyValue() throws Exception { - List> data = new ArrayList>(); + List> data = new ArrayList<>(); 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"))); @@ -326,9 +327,27 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte * @see #784 */ @Test - public void deserializeEmptyResources() throws Exception { + public void serializeEmptyResources() throws Exception { - List> data = new ArrayList>(); + List> data = new ArrayList<>(); + 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 source = new Resources<>(data); + source.add(new Link("localhost")); + source.add(new Link("/page/2").withRel("next")); + + assertThat(write(source)) + .isEqualTo(MappingUtils.read(new ClassPathResource("resources-with-resource-objects.json", getClass()))); + } + + /** + * @see #784 + */ + @Test + public void deserializeEmptyResources() { + + List> data = new ArrayList<>(); 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"))); @@ -499,6 +518,26 @@ public class Jackson2UberIntegrationTest extends AbstractJackson2MarshallingInte assertThat(result).isEqualTo(setupAnnotatedPagedResources(0,0)); } + /** + * @see #784 + */ + @Test + public void handleTemplatedLinksOnDeserialization() throws IOException { + + ResourceSupport original = new ResourceSupport(); + original.add(new Link("/orders{?id}", "order")); + + String serialized = mapper.writeValueAsString(original); + + String expected = MappingUtils.read(new ClassPathResource("resource-with-templated-link.json", getClass())); + + assertThat(serialized).isEqualTo(expected); + + ResourceSupport deserialized = mapper.readValue(serialized, ResourceSupport.class); + + assertThat(deserialized).isEqualTo(original); + } + private static Resources> setupAnnotatedPagedResources() { return setupAnnotatedPagedResources(2, 4); diff --git a/src/test/resources/org/springframework/hateoas/uber/resource-with-templated-link.json b/src/test/resources/org/springframework/hateoas/uber/resource-with-templated-link.json new file mode 100644 index 00000000..5b5bdce1 --- /dev/null +++ b/src/test/resources/org/springframework/hateoas/uber/resource-with-templated-link.json @@ -0,0 +1,10 @@ +{ + "uber" : { + "version" : "1.0", + "data" : [ { + "rel" : [ "order" ], + "url" : "/orders{?id}", + "templated" : true + } ] + } +} \ No newline at end of file