From 171ab2583eafb52d2e0443e6ed5192c7dcbcc734 Mon Sep 17 00:00:00 2001 From: Greg Turnquist Date: Fri, 14 Feb 2014 09:49:38 -0600 Subject: [PATCH] DATAREST-117 - Added support to detect @JsonIgnore and @JsonIgnoreProperties. Wrote test cases to verify it handles class level and attribute level annotations to ignore properties when rendering PersistentEntityResources. Original pull request: #135. --- .../json/PersistentEntityJackson2Module.java | 32 +++++++++++++++++ .../webmvc/AbstractWebIntegrationTests.java | 11 +++++- .../data/rest/webmvc/jpa/JpaWebTests.java | 27 ++++++++++++-- .../data/rest/webmvc/jpa/Person.java | 36 +++++++++++++++++-- 4 files changed, 101 insertions(+), 5 deletions(-) diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/PersistentEntityJackson2Module.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/PersistentEntityJackson2Module.java index 93528b113..48ecd921c 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/PersistentEntityJackson2Module.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/PersistentEntityJackson2Module.java @@ -16,6 +16,8 @@ package org.springframework.data.rest.webmvc.json; import java.io.IOException; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; @@ -44,6 +46,7 @@ import org.springframework.util.Assert; import com.fasterxml.jackson.annotation.JsonAnyGetter; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.core.JsonGenerationException; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.Version; @@ -133,6 +136,17 @@ public class PersistentEntityJackson2Module extends SimpleModule { final Map model = new LinkedHashMap(); + String[] fieldsToIgnore = new String[]{}; + + for (Annotation annotation : entity.getType().getAnnotations()) { + if (annotation.annotationType().equals(JsonIgnoreProperties.class)) { + JsonIgnoreProperties ann = (JsonIgnoreProperties)annotation; + fieldsToIgnore = ann.value(); + break; + } + } + final String[] finalFieldsToIgnore = fieldsToIgnore; + try { entity.doWithProperties(new SimplePropertyHandler() { @@ -151,6 +165,24 @@ public class PersistentEntityJackson2Module extends SimpleModule { return; } + final Method getter = property.getGetter(); + if (getter != null) { + final Annotation[] annotations = getter.getAnnotations(); + for (Annotation annotation : annotations) { + if (annotation.annotationType().equals(JsonIgnore.class)) { + if (((JsonIgnore)annotation).value()) { + return; + } + } + } + } + + for (String fieldToIgnore : finalFieldsToIgnore) { + if (property.getName().equals(fieldToIgnore)) { + return; + } + } + // Property is a normal or non-managed property. model.put(property.getName(), wrapper.getProperty(property)); } diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/AbstractWebIntegrationTests.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/AbstractWebIntegrationTests.java index 60a84e998..4741fcc4a 100644 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/AbstractWebIntegrationTests.java +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/AbstractWebIntegrationTests.java @@ -262,7 +262,16 @@ public abstract class AbstractWebIntegrationTests { return (T) jsonPathResult; } - protected String assertJsonPathEquals(String path, MockHttpServletResponse response, String expected) + protected void assertJsonPathDoesntExist(String path, MockHttpServletResponse response) throws Exception { + + try { + JsonPath.read(response.getContentAsString(), path); + fail(path + " should have failed"); + } catch (InvalidPathException e) { + } + } + + protected String assertJsonPathEquals(String path, String expected, MockHttpServletResponse response) throws Exception { String jsonQueryResults = assertHasJsonPathValue(path, response); diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaWebTests.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaWebTests.java index 4472dfc81..97ff8cf7c 100644 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaWebTests.java +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaWebTests.java @@ -176,6 +176,29 @@ public class JpaWebTests extends AbstractWebIntegrationTests { ).andExpect(status().isCreated()); } + /** + * @see DATAREST-117 + */ + @Test + public void createPersonThenVerifyIgnoredAttributesDontExist() throws Exception { + + Link peopleLink = discoverUnique("people"); + ObjectMapper mapper = new ObjectMapper(); + Person frodo = new Person("Frodo", "Baggins"); + frodo.setAge(77); + frodo.setHeight(42); + frodo.setWeight(75); + String frodoString = mapper.writeValueAsString(frodo); + + MockHttpServletResponse response = postAndGet(peopleLink, frodoString, MediaType.APPLICATION_JSON); + + assertJsonPathEquals("$.firstName", "Frodo", response); + assertJsonPathEquals("$.lastName", "Baggins", response); + assertJsonPathDoesntExist("$.age", response); + assertJsonPathDoesntExist("$.height", response); + assertJsonPathDoesntExist("$.weight", response); + } + /** * @see DATAREST-95 */ @@ -354,14 +377,14 @@ public class JpaWebTests extends AbstractWebIntegrationTests { MockHttpServletResponse createdPerson = postAndGet(peopleLink, frodoString, MediaType.APPLICATION_JSON); Link frodoLink = assertHasLinkWithRel("self", createdPerson); - assertJsonPathEquals("$.firstName", createdPerson, "Frodo"); + assertJsonPathEquals("$.firstName", "Frodo", createdPerson); String bilboWithFrodosLinks = createdPerson.getContentAsString().replace("Frodo", "Bilbo"); MockHttpServletResponse overwrittenResponse = putAndGet(frodoLink, bilboWithFrodosLinks, MediaType.APPLICATION_JSON); assertHasLinkWithRel("self", overwrittenResponse); - assertJsonPathEquals("$.firstName", overwrittenResponse, "Bilbo"); + assertJsonPathEquals("$.firstName", "Bilbo", overwrittenResponse); } private List preparePersonResources(Person primary, Person... persons) throws Exception { diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/Person.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/Person.java index 1936d50dd..657624e58 100644 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/Person.java +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/Person.java @@ -14,14 +14,19 @@ import javax.persistence.ManyToOne; import javax.persistence.PrePersist; import javax.validation.constraints.NotNull; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonIgnoreType; import org.springframework.data.rest.core.annotation.Description; +import com.fasterxml.jackson.annotation.JsonIgnore; + /** * An entity that represents a person. - * + * * @author Jon Brisbin */ @Entity +@JsonIgnoreProperties({"height", "weight"}) public class Person { private Long id; @@ -30,6 +35,9 @@ public class Person { @Description("A person's siblings") private List siblings = Collections.emptyList(); private Person father; @Description("Timestamp this person object was created") private Date created; + private int age; + private int height; + private int weight; public Person() {} @@ -102,4 +110,28 @@ public class Person { this.created = Calendar.getInstance().getTime(); } -} + @JsonIgnore + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public int getHeight() { + return height; + } + + public void setHeight(int height) { + this.height = height; + } + + public int getWeight() { + return weight; + } + + public void setWeight(int weight) { + this.weight = weight; + } +} \ No newline at end of file