Fix potential NullPointerException in ProjectionSerializer.
Fixes GH-1947.
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.rest.core.mapping;
|
||||
|
||||
import org.springframework.data.util.Streamable;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
@@ -28,6 +29,7 @@ public interface ResourceMappings extends Streamable<ResourceMetadata> {
|
||||
* @param type must not be {@literal null}.
|
||||
* @return the {@link ResourceMetadata} if available or {@literal null} otherwise.
|
||||
*/
|
||||
@Nullable
|
||||
ResourceMetadata getMetadataFor(Class<?> type);
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,15 +34,11 @@ import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.projection.TargetAware;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
import org.springframework.data.repository.support.RepositoryInvoker;
|
||||
import org.springframework.data.repository.support.RepositoryInvokerFactory;
|
||||
import org.springframework.data.rest.core.UriToEntityConverter;
|
||||
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMappings;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMetadata;
|
||||
import org.springframework.data.rest.core.support.EntityLookup;
|
||||
import org.springframework.data.rest.core.support.SelfLinkProvider;
|
||||
import org.springframework.data.rest.webmvc.EmbeddedResourcesAssembler;
|
||||
import org.springframework.data.rest.webmvc.PersistentEntityResource;
|
||||
import org.springframework.data.rest.webmvc.mapping.Associations;
|
||||
@@ -649,7 +645,7 @@ public class PersistentEntityJackson2Module extends SimpleModule {
|
||||
* @param invoker must not be {@literal null}.
|
||||
* @param unwrapping
|
||||
*/
|
||||
private ProjectionSerializer(LinkCollector collector, Associations mappings,
|
||||
ProjectionSerializer(LinkCollector collector, Associations mappings,
|
||||
RepresentationModelProcessorInvoker invoker, boolean unwrapping) {
|
||||
|
||||
super(TargetAware.class);
|
||||
@@ -694,11 +690,11 @@ public class PersistentEntityJackson2Module extends SimpleModule {
|
||||
* @param value must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private ProjectionResource toModel(TargetAware value) {
|
||||
ProjectionResource toModel(TargetAware value) {
|
||||
|
||||
Object target = value.getTarget();
|
||||
ResourceMetadata metadata = associations.getMetadataFor(value.getTargetClass());
|
||||
Links links = metadata.isExported() ? collector.getLinksFor(target) : Links.NONE;
|
||||
Links links = metadata != null && metadata.isExported() ? collector.getLinksFor(target) : Links.NONE;
|
||||
|
||||
EntityModel<TargetAware> resource = invoker.invokeProcessorsFor(EntityModel.of(value, links));
|
||||
|
||||
@@ -708,7 +704,6 @@ public class PersistentEntityJackson2Module extends SimpleModule {
|
||||
|
||||
static class ProjectionResource extends EntityModel<ProjectionResourceContent> {
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
ProjectionResource(TargetAware projection, Iterable<Link> links) {
|
||||
super(new ProjectionResourceContent(projection, projection.getClass().getInterfaces()[0]), links);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.TemplateVariable;
|
||||
import org.springframework.hateoas.TemplateVariables;
|
||||
import org.springframework.hateoas.UriTemplate;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -94,6 +95,7 @@ public class Associations {
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
public ResourceMetadata getMetadataFor(Class<?> type) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null");
|
||||
|
||||
@@ -39,6 +39,7 @@ import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.data.keyvalue.core.mapping.context.KeyValueMappingContext;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.projection.TargetAware;
|
||||
import org.springframework.data.repository.support.RepositoryInvoker;
|
||||
import org.springframework.data.repository.support.RepositoryInvokerFactory;
|
||||
import org.springframework.data.rest.core.UriToEntityConverter;
|
||||
@@ -52,8 +53,10 @@ import org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module.
|
||||
import org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module.LookupObjectSerializer;
|
||||
import org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module.NestedEntitySerializer;
|
||||
import org.springframework.data.rest.webmvc.mapping.Associations;
|
||||
import org.springframework.data.rest.webmvc.mapping.DefaultLinkCollector;
|
||||
import org.springframework.data.rest.webmvc.support.ExcerptProjector;
|
||||
import org.springframework.hateoas.EntityModel;
|
||||
import org.springframework.hateoas.RepresentationModel;
|
||||
import org.springframework.hateoas.UriTemplate;
|
||||
import org.springframework.hateoas.server.EntityLinks;
|
||||
import org.springframework.hateoas.server.mvc.RepresentationModelProcessorInvoker;
|
||||
@@ -263,6 +266,19 @@ class PersistentEntityJackson2ModuleUnitTests {
|
||||
assertThatNoException().isThrownBy(() -> mapper.writeValueAsString(model));
|
||||
}
|
||||
|
||||
@Test // GH-1947
|
||||
void projectionsHandleMissingMetadata() {
|
||||
|
||||
var collector = new DefaultLinkCollector(persistentEntities, selfLinks, associations);
|
||||
var invoker = mock(RepresentationModelProcessorInvoker.class);
|
||||
when(invoker.invokeProcessorsFor(any(RepresentationModel.class)))
|
||||
.then(invocation -> invocation.getArgument(0));
|
||||
|
||||
var serializer = new PersistentEntityJackson2Module.ProjectionSerializer(collector, associations, invoker, false);
|
||||
|
||||
assertThatNoException().isThrownBy(() -> serializer.toModel(mock(SampleProjection.class)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@@ -365,4 +381,6 @@ class PersistentEntityJackson2ModuleUnitTests {
|
||||
gen.writeEndObject();
|
||||
}
|
||||
}
|
||||
|
||||
interface SampleProjection extends TargetAware {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user