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 6ae3d81e0..748d84d09 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 @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; +import com.fasterxml.jackson.databind.jsontype.TypeDeserializer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.CollectionFactory; @@ -411,6 +412,14 @@ public class PersistentEntityJackson2Module extends SimpleModule { throw ctxt.weirdStringException(source, URI.class, String.format(UNEXPECTED_VALUE, property)); } } + + /** + * Deserialize by ignoring typeDeserializer, as URI will either resolve to null or concrete instance + */ + @Override + public Object deserializeWithType(JsonParser jp, DeserializationContext ctxt, TypeDeserializer typeDeserializer) throws IOException { + return deserialize(jp, ctxt); + } } @SuppressWarnings("serial") diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/PersistentEntityJackson2ModuleUnitTests.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/PersistentEntityJackson2ModuleUnitTests.java index 2f5d8239e..9097ee4a3 100644 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/PersistentEntityJackson2ModuleUnitTests.java +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/json/PersistentEntityJackson2ModuleUnitTests.java @@ -19,15 +19,22 @@ import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import static org.mockito.Mockito.*; +import java.io.IOException; +import java.net.URI; import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonTypeInfo; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.data.mapping.PersistentEntity; +import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.context.PersistentEntities; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; +import org.springframework.data.rest.core.UriToEntityConverter; import org.springframework.data.rest.core.config.EnumTranslationConfiguration; import org.springframework.data.rest.core.config.MetadataConfiguration; import org.springframework.data.rest.core.config.ProjectionDefinitionConfiguration; @@ -38,6 +45,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import com.jayway.jsonpath.JsonPath; +import org.springframework.hateoas.UriTemplate; /** * Unit tests for {@link PersistentEntityJackson2Module}. @@ -48,6 +56,8 @@ import com.jayway.jsonpath.JsonPath; public class PersistentEntityJackson2ModuleUnitTests { @Mock AssociationLinks associationLinks; + @Mock PersistentEntities repositories; + @Mock UriToEntityConverter converter; ObjectMapper mapper; @@ -65,6 +75,9 @@ public class PersistentEntityJackson2ModuleUnitTests { persistentEntities, associationLinks, new RepositoryRestConfiguration(new ProjectionDefinitionConfiguration(), new MetadataConfiguration(), mock(EnumTranslationConfiguration.class)))); + module.setDeserializerModifier(new PersistentEntityJackson2Module. + AssociationUriResolvingDeserializerModifier(repositories, converter, associationLinks)); + this.mapper = new ObjectMapper(); this.mapper.registerModule(module); } @@ -95,6 +108,46 @@ public class PersistentEntityJackson2ModuleUnitTests { assertThat(JsonPath.read(result, "$.number"), is((Object) 5)); } + /** + * @see DATAREST-662 + */ + @Test + public void isAbleToResolveSubclassedProperty() throws IOException { + PersistentEntity petOwnerPersistentEntity = mock(PersistentEntity.class); + PersistentProperty petProperty = mock(PersistentProperty.class); + when(petProperty.isCollectionLike()).thenReturn(false); + when(petProperty.getActualType()).thenReturn(Pet.class); + when(petOwnerPersistentEntity.getPersistentProperty("pet")).thenReturn(petProperty); + when(repositories.getPersistentEntity(PetOwner.class)).thenReturn(petOwnerPersistentEntity); + when(associationLinks.isLinkableAssociation(petProperty)).thenReturn(true); + when(converter.convert(new UriTemplate("/pets/1").expand(), TypeDescriptor.valueOf(URI.class), + TypeDescriptor.valueOf(Pet.class))).thenReturn(new Cat()); + + PetOwner petOwner = mapper.readValue("{\"pet\":\"/pets/1\"}", PetOwner.class); + + assertNotNull(petOwner); + assertNotNull(petOwner.getPet()); + } + + static class PetOwner { + + private Pet pet; + + public Pet getPet() { + return pet; + } + + } + + @JsonTypeInfo(include = JsonTypeInfo.As.PROPERTY, use = JsonTypeInfo.Id.MINIMAL_CLASS) + static class Pet { + + } + + static class Cat extends Pet { + + } + static class Sample { public @JsonProperty("foo") String name; }