From c36267a4476effca701ccf5e2cdbbe773c323453 Mon Sep 17 00:00:00 2001 From: Alex Leigh Date: Wed, 14 Sep 2016 18:29:53 -0700 Subject: [PATCH] DATAREST-872 - PersistentEntityJackson2Module now serializes JsonTypeInfo correctly. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NestedEntitySerializer now overrides serializeWithType(…) so that @JsonTypeInfo is rendered properly. Related pull request: #221. --- .../data/rest/webmvc/jpa/Dinner.java | 45 +++++++++++++ .../data/rest/webmvc/jpa/Guest.java | 66 +++++++++++++++++++ .../data/rest/webmvc/jpa/GuestRepository.java | 24 +++++++ .../data/rest/webmvc/jpa/Meal.java | 51 ++++++++++++++ .../data/rest/webmvc/jpa/Room.java | 51 ++++++++++++++ .../data/rest/webmvc/jpa/Suite.java | 45 +++++++++++++ .../PersistentEntitySerializationTests.java | 37 ++++++++--- .../json/PersistentEntityJackson2Module.java | 8 +++ 8 files changed, 318 insertions(+), 9 deletions(-) create mode 100644 spring-data-rest-tests/spring-data-rest-tests-jpa/src/main/java/org/springframework/data/rest/webmvc/jpa/Dinner.java create mode 100644 spring-data-rest-tests/spring-data-rest-tests-jpa/src/main/java/org/springframework/data/rest/webmvc/jpa/Guest.java create mode 100644 spring-data-rest-tests/spring-data-rest-tests-jpa/src/main/java/org/springframework/data/rest/webmvc/jpa/GuestRepository.java create mode 100644 spring-data-rest-tests/spring-data-rest-tests-jpa/src/main/java/org/springframework/data/rest/webmvc/jpa/Meal.java create mode 100644 spring-data-rest-tests/spring-data-rest-tests-jpa/src/main/java/org/springframework/data/rest/webmvc/jpa/Room.java create mode 100644 spring-data-rest-tests/spring-data-rest-tests-jpa/src/main/java/org/springframework/data/rest/webmvc/jpa/Suite.java diff --git a/spring-data-rest-tests/spring-data-rest-tests-jpa/src/main/java/org/springframework/data/rest/webmvc/jpa/Dinner.java b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/main/java/org/springframework/data/rest/webmvc/jpa/Dinner.java new file mode 100644 index 000000000..f98349743 --- /dev/null +++ b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/main/java/org/springframework/data/rest/webmvc/jpa/Dinner.java @@ -0,0 +1,45 @@ +/* + * Copyright 2012-2016 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.rest.webmvc.jpa; + +import javax.persistence.DiscriminatorValue; +import javax.persistence.Entity; + +/** + * @author Alex Leigh + * @see DATAREST-872 + */ +@Entity +@DiscriminatorValue("D") +public class Dinner extends Meal { + + public static final String TYPE = "dinner"; + + private String dinnerCode; + + @Override + public String getType() { + return TYPE; + } + + public String getDinnerCode() { + return dinnerCode; + } + + public void setDinnerCode(String dinnerCode) { + this.dinnerCode = dinnerCode; + } +} diff --git a/spring-data-rest-tests/spring-data-rest-tests-jpa/src/main/java/org/springframework/data/rest/webmvc/jpa/Guest.java b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/main/java/org/springframework/data/rest/webmvc/jpa/Guest.java new file mode 100644 index 000000000..43e50b28d --- /dev/null +++ b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/main/java/org/springframework/data/rest/webmvc/jpa/Guest.java @@ -0,0 +1,66 @@ +/* + * Copyright 2015-2016 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.rest.webmvc.jpa; + +import javax.persistence.*; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Alex Leigh + * @see DATAREST-872 + */ +@Entity +public class Guest { + + @Id + @GeneratedValue + private Long id; + + @OneToOne(cascade = CascadeType.ALL) + private Room room; + + @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) + private List meals = new ArrayList(); + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Room getRoom() { + return room; + } + + public void setRoom(Room room) { + this.room = room; + } + + public List getMeals() { + return meals; + } + + public void setMeals(List meals) { + this.meals = meals; + } + + public void addMeal(Meal meal) { + meals.add(meal); + } +} diff --git a/spring-data-rest-tests/spring-data-rest-tests-jpa/src/main/java/org/springframework/data/rest/webmvc/jpa/GuestRepository.java b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/main/java/org/springframework/data/rest/webmvc/jpa/GuestRepository.java new file mode 100644 index 000000000..948c08cab --- /dev/null +++ b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/main/java/org/springframework/data/rest/webmvc/jpa/GuestRepository.java @@ -0,0 +1,24 @@ +/* + * Copyright 2015-2016 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.rest.webmvc.jpa; + +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * @author Alex Leigh + * @see DATAREST-872 + */ +public interface GuestRepository extends JpaRepository {} diff --git a/spring-data-rest-tests/spring-data-rest-tests-jpa/src/main/java/org/springframework/data/rest/webmvc/jpa/Meal.java b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/main/java/org/springframework/data/rest/webmvc/jpa/Meal.java new file mode 100644 index 000000000..927f02f09 --- /dev/null +++ b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/main/java/org/springframework/data/rest/webmvc/jpa/Meal.java @@ -0,0 +1,51 @@ +/* + * Copyright 2012-2016 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.rest.webmvc.jpa; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Inheritance; + +/** + * @author Alex Leigh + * @see DATAREST-872 + */ +@Entity +@Inheritance +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type") +@JsonSubTypes({ + @JsonSubTypes.Type(value = Dinner.class, name = Dinner.TYPE) +}) +public abstract class Meal { + + @Id + @GeneratedValue + private Long id; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public abstract String getType(); +} diff --git a/spring-data-rest-tests/spring-data-rest-tests-jpa/src/main/java/org/springframework/data/rest/webmvc/jpa/Room.java b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/main/java/org/springframework/data/rest/webmvc/jpa/Room.java new file mode 100644 index 000000000..aec971a45 --- /dev/null +++ b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/main/java/org/springframework/data/rest/webmvc/jpa/Room.java @@ -0,0 +1,51 @@ +/* + * Copyright 2012-2016 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.rest.webmvc.jpa; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Inheritance; + +/** + * @author Alex Leigh + * @see DATAREST-872 + */ +@Entity +@Inheritance +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type") +@JsonSubTypes({ + @JsonSubTypes.Type(value = Suite.class, name = Suite.TYPE) +}) +public abstract class Room { + + @Id + @GeneratedValue + private Long id; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public abstract String getType(); +} diff --git a/spring-data-rest-tests/spring-data-rest-tests-jpa/src/main/java/org/springframework/data/rest/webmvc/jpa/Suite.java b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/main/java/org/springframework/data/rest/webmvc/jpa/Suite.java new file mode 100644 index 000000000..a376bbf9f --- /dev/null +++ b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/main/java/org/springframework/data/rest/webmvc/jpa/Suite.java @@ -0,0 +1,45 @@ +/* + * Copyright 2012-2016 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.rest.webmvc.jpa; + +import javax.persistence.DiscriminatorValue; +import javax.persistence.Entity; + +/** + * @author Alex Leigh + * @see DATAREST-872 + */ +@Entity +@DiscriminatorValue("S") +public class Suite extends Room { + + public static final String TYPE = "suite"; + + private String suiteCode; + + @Override + public String getType() { + return TYPE; + } + + public String getSuiteCode() { + return suiteCode; + } + + public void setSuiteCode(String suiteCode) { + this.suiteCode = suiteCode; + } +} diff --git a/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/json/PersistentEntitySerializationTests.java b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/json/PersistentEntitySerializationTests.java index ae2b911fd..6c5683c46 100644 --- a/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/json/PersistentEntitySerializationTests.java +++ b/spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/json/PersistentEntitySerializationTests.java @@ -36,15 +36,7 @@ import org.springframework.data.projection.ProjectionFactory; import org.springframework.data.projection.SpelAwareProxyProjectionFactory; import org.springframework.data.repository.support.Repositories; import org.springframework.data.rest.webmvc.PersistentEntityResource; -import org.springframework.data.rest.webmvc.jpa.CreditCard; -import org.springframework.data.rest.webmvc.jpa.JpaRepositoryConfig; -import org.springframework.data.rest.webmvc.jpa.LineItem; -import org.springframework.data.rest.webmvc.jpa.Order; -import org.springframework.data.rest.webmvc.jpa.OrderRepository; -import org.springframework.data.rest.webmvc.jpa.Person; -import org.springframework.data.rest.webmvc.jpa.PersonRepository; -import org.springframework.data.rest.webmvc.jpa.PersonSummary; -import org.springframework.data.rest.webmvc.jpa.UserExcerpt; +import org.springframework.data.rest.webmvc.jpa.*; import org.springframework.data.rest.webmvc.util.TestUtils; import org.springframework.hateoas.Link; import org.springframework.hateoas.LinkDiscoverer; @@ -301,4 +293,31 @@ public class PersistentEntitySerializationTests { assertThat(JsonPath.read(mapper.writeValueAsString(creditCard), "$.ccn"), is("1234123412341234")); } + + /** + * @see DATAREST-872 + */ + @Test + public void serializesInheritance() throws Exception { + + Suite suite = new Suite(); + suite.setSuiteCode("Suite 42"); + + Dinner dinner = new Dinner(); + dinner.setDinnerCode("STD_DINNER"); + + Guest guest = new Guest(); + guest.setRoom(suite); + guest.addMeal(dinner); + + PersistentEntityResource resource = PersistentEntityResource. + build(guest, repositories.getPersistentEntity(Guest.class)). + withLink(new Link("/guests/1")). + build(); + + String result = mapper.writeValueAsString(resource); + + assertThat(JsonPath.read(result, "$.room.type"), equalTo("suite")); + assertThat(JsonPath.read(result, "$.meals[0].type"), equalTo("dinner")); + } } 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 917a2d5a3..d7da28fc1 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 @@ -79,6 +79,7 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer; import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition; import com.fasterxml.jackson.databind.jsontype.TypeDeserializer; +import com.fasterxml.jackson.databind.jsontype.TypeSerializer; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.BeanPropertyWriter; import com.fasterxml.jackson.databind.ser.BeanSerializerBuilder; @@ -369,6 +370,13 @@ public class PersistentEntityJackson2Module extends SimpleModule { } } + @Override + public void serializeWithType(Object value, JsonGenerator gen, SerializerProvider provider, + TypeSerializer typeSerializer) throws IOException { + + serialize(value, gen, provider); + } + private Resource toResource(Object value) { PersistentEntity entity = entities.getPersistentEntity(value.getClass());