DATAREST-471 - Populate Last-Modified headers from auditing information.
We now populate the Last-Modified header for requests to the item resource and search resource invocations that return a single item.
This commit is contained in:
@@ -18,16 +18,22 @@ package org.springframework.data.rest.webmvc;
|
||||
import static org.springframework.data.rest.webmvc.ControllerUtils.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.auditing.AuditableBeanWrapper;
|
||||
import org.springframework.data.auditing.AuditableBeanWrapperFactory;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMetadata;
|
||||
import org.springframework.data.rest.webmvc.support.ETag;
|
||||
import org.springframework.data.web.PagedResourcesAssembler;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.Resource;
|
||||
import org.springframework.hateoas.ResourceSupport;
|
||||
import org.springframework.hateoas.Resources;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin
|
||||
@@ -38,16 +44,23 @@ import org.springframework.util.Assert;
|
||||
class AbstractRepositoryRestController {
|
||||
|
||||
private final PagedResourcesAssembler<Object> pagedResourcesAssembler;
|
||||
private final AuditableBeanWrapperFactory auditableBeanWrapperFactory;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AbstractRepositoryRestController} for the given {@link PagedResourcesAssembler}.
|
||||
* Creates a new {@link AbstractRepositoryRestController} for the given {@link PagedResourcesAssembler} and
|
||||
* {@link AuditableBeanWrapperFactory}.
|
||||
*
|
||||
* @param pagedResourcesAssembler must not be {@literal null}.
|
||||
* @param auditableBeanWrapperFactory must not be {@literal null}.
|
||||
*/
|
||||
public AbstractRepositoryRestController(PagedResourcesAssembler<Object> pagedResourcesAssembler) {
|
||||
public AbstractRepositoryRestController(PagedResourcesAssembler<Object> pagedResourcesAssembler,
|
||||
AuditableBeanWrapperFactory auditableBeanWrapperFactory) {
|
||||
|
||||
Assert.notNull(pagedResourcesAssembler, "PagedResourcesAssembler must not be null!");
|
||||
Assert.notNull(auditableBeanWrapperFactory, "AuditableBeanWrapperFactory must not be null!");
|
||||
|
||||
this.pagedResourcesAssembler = pagedResourcesAssembler;
|
||||
this.auditableBeanWrapperFactory = auditableBeanWrapperFactory;
|
||||
}
|
||||
|
||||
protected Link resourceLink(RootResourceInformation resourceLink, Resource resource) {
|
||||
@@ -61,18 +74,35 @@ class AbstractRepositoryRestController {
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
protected Resources resultToResources(Object result, PersistentEntityResourceAssembler assembler, Link baseLink) {
|
||||
protected Resources<?> toResources(Iterable<?> source, PersistentEntityResourceAssembler assembler, Link baseLink) {
|
||||
|
||||
if (result instanceof Page) {
|
||||
Page<Object> page = (Page<Object>) result;
|
||||
if (source instanceof Page) {
|
||||
Page<Object> page = (Page<Object>) source;
|
||||
return entitiesToResources(page, assembler, baseLink);
|
||||
} else if (result instanceof Iterable) {
|
||||
return entitiesToResources((Iterable<Object>) result, assembler);
|
||||
} else if (null == result) {
|
||||
return new Resources(EMPTY_RESOURCE_LIST);
|
||||
} else if (source instanceof Iterable) {
|
||||
return entitiesToResources((Iterable<Object>) source, assembler);
|
||||
} else {
|
||||
Resource<Object> resource = assembler.toFullResource(result);
|
||||
return new Resources(Collections.singletonList(resource));
|
||||
return new Resources(EMPTY_RESOURCE_LIST);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns the given source into a {@link ResourceSupport} if needed and possible. Uses the given
|
||||
* {@link PersistentEntityResourceAssembler} for the actual conversion.
|
||||
*
|
||||
* @param source can be must not be {@literal null}.
|
||||
* @param assembler must not be {@literal null}.
|
||||
* @param baseLink can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected Object toResource(Object source, PersistentEntityResourceAssembler assembler, Link baseLink) {
|
||||
|
||||
if (source instanceof Iterable) {
|
||||
return toResources((Iterable<?>) source, assembler, baseLink);
|
||||
} else if (source == null || ClassUtils.isPrimitiveOrWrapper(source.getClass())) {
|
||||
return source;
|
||||
} else {
|
||||
return assembler.toFullResource(source);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,4 +123,38 @@ class AbstractRepositoryRestController {
|
||||
|
||||
return new Resources<Resource<Object>>(resources);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default headers to be returned for the given {@link PersistentEntityResource}. Will set {@link ETag}
|
||||
* and {@code Last-Modified} headers if applicable.
|
||||
*
|
||||
* @param resource can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected HttpHeaders prepareHeaders(PersistentEntityResource resource) {
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
|
||||
if (resource == null) {
|
||||
return headers;
|
||||
}
|
||||
|
||||
// Add ETag
|
||||
headers = ETag.from(resource).addTo(headers);
|
||||
|
||||
// Add Last-Modified
|
||||
AuditableBeanWrapper wrapper = auditableBeanWrapperFactory.getBeanWrapperFor(resource.getContent());
|
||||
|
||||
if (wrapper == null) {
|
||||
return headers;
|
||||
}
|
||||
|
||||
Calendar lastModifiedDate = wrapper.getLastModifiedDate();
|
||||
|
||||
if (lastModifiedDate != null) {
|
||||
headers.setLastModified(lastModifiedDate.getTimeInMillis());
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.data.rest.webmvc;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.auditing.AuditableBeanWrapperFactory;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMappings;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMetadata;
|
||||
@@ -53,12 +54,13 @@ public class RepositoryController extends AbstractRepositoryRestController {
|
||||
* @param repositories must not be {@literal null}.
|
||||
* @param entityLinks must not be {@literal null}.
|
||||
* @param mappings must not be {@literal null}.
|
||||
* @param auditableBeanWrapperFactory must not be {@literal null}.
|
||||
*/
|
||||
@Autowired
|
||||
public RepositoryController(PagedResourcesAssembler<Object> assembler, Repositories repositories,
|
||||
EntityLinks entityLinks, ResourceMappings mappings) {
|
||||
EntityLinks entityLinks, ResourceMappings mappings, AuditableBeanWrapperFactory auditableBeanWrapperFactory) {
|
||||
|
||||
super(assembler);
|
||||
super(assembler, auditableBeanWrapperFactory);
|
||||
|
||||
Assert.notNull(repositories, "Repositories must not be null!");
|
||||
Assert.notNull(entityLinks, "EntityLinks must not be null!");
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.auditing.AuditableBeanWrapperFactory;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
|
||||
@@ -89,9 +90,10 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem
|
||||
@Autowired
|
||||
public RepositoryEntityController(Repositories repositories, RepositoryRestConfiguration config,
|
||||
RepositoryEntityLinks entityLinks, PagedResourcesAssembler<Object> assembler,
|
||||
@Qualifier("defaultConversionService") ConversionService conversionService) {
|
||||
@Qualifier("defaultConversionService") ConversionService conversionService,
|
||||
AuditableBeanWrapperFactory auditableBeanWrapperFactory) {
|
||||
|
||||
super(assembler);
|
||||
super(assembler, auditableBeanWrapperFactory);
|
||||
|
||||
this.entityLinks = entityLinks;
|
||||
this.config = config;
|
||||
@@ -193,9 +195,9 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem
|
||||
Link baseLink = entityLinks.linkToPagedResource(resourceInformation.getDomainType(), pageable.isDefault() ? null
|
||||
: pageable.getPageable());
|
||||
|
||||
Resources<?> resources = resultToResources(results, assembler, baseLink);
|
||||
resources.add(links);
|
||||
return resources;
|
||||
Resources<?> result = toResources(results, assembler, baseLink);
|
||||
result.add(links);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@@ -268,14 +270,18 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem
|
||||
* @since 2.2
|
||||
*/
|
||||
@RequestMapping(value = BASE_MAPPING + "/{id}", method = RequestMethod.HEAD)
|
||||
public ResponseEntity<?> headForItemResource(RootResourceInformation resourceInformation, @BackendId Serializable id)
|
||||
throws HttpRequestMethodNotSupportedException {
|
||||
public ResponseEntity<?> headForItemResource(RootResourceInformation resourceInformation, @BackendId Serializable id,
|
||||
PersistentEntityResourceAssembler assembler) throws HttpRequestMethodNotSupportedException {
|
||||
|
||||
if (getItemResource(resourceInformation, id) != null) {
|
||||
return new ResponseEntity<Object>(HttpStatus.NO_CONTENT);
|
||||
Object domainObject = getItemResource(resourceInformation, id);
|
||||
|
||||
if (domainObject == null) {
|
||||
throw new ResourceNotFoundException();
|
||||
}
|
||||
|
||||
throw new ResourceNotFoundException();
|
||||
PersistentEntityResource resource = assembler.toResource(domainObject);
|
||||
|
||||
return new ResponseEntity<Object>(prepareHeaders(resource), HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -298,7 +304,7 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem
|
||||
}
|
||||
|
||||
PersistentEntityResource resource = assembler.toFullResource(domainObj);
|
||||
HttpHeaders headers = ETag.from(resource).addTo(new HttpHeaders());
|
||||
HttpHeaders headers = prepareHeaders(resource);
|
||||
|
||||
return new ResponseEntity<Resource<?>>(resource, headers, HttpStatus.OK);
|
||||
}
|
||||
@@ -415,17 +421,14 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem
|
||||
Object obj = invoker.invokeSave(domainObject);
|
||||
publisher.publishEvent(new AfterSaveEvent(domainObject));
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
PersistentEntityResource resource = assembler.toFullResource(obj);
|
||||
HttpHeaders headers = prepareHeaders(resource);
|
||||
|
||||
if (PUT.equals(httpMethod)) {
|
||||
addLocationHeader(headers, assembler, obj);
|
||||
}
|
||||
|
||||
if (config.isReturnBodyOnUpdate()) {
|
||||
|
||||
PersistentEntityResource resource = assembler.toFullResource(obj);
|
||||
headers = ETag.from(resource).addTo(headers);
|
||||
|
||||
return ControllerUtils.toResponseEntity(HttpStatus.OK, headers, resource);
|
||||
} else {
|
||||
return ControllerUtils.toEmptyResponse(HttpStatus.NO_CONTENT, headers);
|
||||
@@ -446,11 +449,10 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem
|
||||
Object savedObject = invoker.invokeSave(domainObject);
|
||||
publisher.publishEvent(new AfterCreateEvent(savedObject));
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
addLocationHeader(headers, assembler, savedObject);
|
||||
|
||||
PersistentEntityResource resource = config.isReturnBodyOnCreate() ? assembler.toFullResource(savedObject) : null;
|
||||
headers = ETag.from(resource).addTo(headers);
|
||||
|
||||
HttpHeaders headers = prepareHeaders(resource);
|
||||
addLocationHeader(headers, assembler, savedObject);
|
||||
|
||||
return ControllerUtils.toResponseEntity(HttpStatus.CREATED, headers, resource);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.core.CollectionFactory;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.auditing.AuditableBeanWrapperFactory;
|
||||
import org.springframework.data.mapping.IdentifierAccessor;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
@@ -85,9 +86,9 @@ class RepositoryPropertyReferenceController extends AbstractRepositoryRestContro
|
||||
@Autowired
|
||||
public RepositoryPropertyReferenceController(Repositories repositories,
|
||||
@Qualifier("defaultConversionService") ConversionService conversionService,
|
||||
PagedResourcesAssembler<Object> assembler) {
|
||||
PagedResourcesAssembler<Object> assembler, AuditableBeanWrapperFactory auditableBeanWrapperFactory) {
|
||||
|
||||
super(assembler);
|
||||
super(assembler, auditableBeanWrapperFactory);
|
||||
|
||||
this.repositories = repositories;
|
||||
this.conversionService = conversionService;
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.auditing.AuditableBeanWrapperFactory;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.repository.support.RepositoryInvoker;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMappings;
|
||||
@@ -44,7 +45,6 @@ import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
@@ -78,9 +78,10 @@ class RepositorySearchController extends AbstractRepositoryRestController {
|
||||
*/
|
||||
@Autowired
|
||||
public RepositorySearchController(PagedResourcesAssembler<Object> assembler, RepositoryEntityLinks entityLinks,
|
||||
ResourceMappings mappings, HateoasSortHandlerMethodArgumentResolver sortResolver) {
|
||||
ResourceMappings mappings, HateoasSortHandlerMethodArgumentResolver sortResolver,
|
||||
AuditableBeanWrapperFactory auditableBeanWrapperFactory) {
|
||||
|
||||
super(assembler);
|
||||
super(assembler, auditableBeanWrapperFactory);
|
||||
|
||||
Assert.notNull(entityLinks, "EntityLinks must not be null!");
|
||||
Assert.notNull(mappings, "ResourceMappings must not be null!");
|
||||
@@ -165,9 +166,9 @@ class RepositorySearchController extends AbstractRepositoryRestController {
|
||||
@PathVariable String search, DefaultedPageable pageable, Sort sort, PersistentEntityResourceAssembler assembler) {
|
||||
|
||||
Method method = checkExecutability(resourceInformation, search);
|
||||
Object resources = executeQueryMethod(resourceInformation.getInvoker(), request, method, pageable, sort, assembler);
|
||||
Object result = executeQueryMethod(resourceInformation.getInvoker(), request, method, pageable, sort, assembler);
|
||||
|
||||
return new ResponseEntity<Object>(resources, HttpStatus.OK);
|
||||
return new ResponseEntity<Object>(toResource(result, assembler, null), HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -187,8 +188,8 @@ class RepositorySearchController extends AbstractRepositoryRestController {
|
||||
PersistentEntityResourceAssembler assembler) {
|
||||
|
||||
Method method = checkExecutability(resourceInformation, search);
|
||||
Object resource = executeQueryMethod(resourceInformation.getInvoker(), request, method, pageable, sort, assembler);
|
||||
|
||||
Object result = executeQueryMethod(resourceInformation.getInvoker(), request, method, pageable, sort, assembler);
|
||||
Object resource = toResource(result, assembler, null);
|
||||
List<Link> links = new ArrayList<Link>();
|
||||
|
||||
if (resource instanceof Resources && ((Resources<?>) resource).getContent() != null) {
|
||||
@@ -275,13 +276,7 @@ class RepositorySearchController extends AbstractRepositoryRestController {
|
||||
DefaultedPageable pageable, Sort sort, PersistentEntityResourceAssembler assembler) {
|
||||
|
||||
Map<String, String[]> parameters = request.getParameterMap();
|
||||
Object result = invoker.invokeQueryMethod(method, parameters, pageable.getPageable(), sort);
|
||||
|
||||
if (ClassUtils.isPrimitiveOrWrapper(method.getReturnType())) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return resultToResources(result, assembler, null);
|
||||
return invoker.invokeQueryMethod(method, parameters, pageable.getPageable(), sort);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,6 +42,8 @@ import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.convert.support.ConfigurableConversionService;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.data.auditing.AuditableBeanWrapperFactory;
|
||||
import org.springframework.data.auditing.MappingAuditableBeanWrapperFactory;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.geo.GeoModule;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
@@ -629,6 +631,11 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
|
||||
return OrderAwarePluginRegistry.create(converters);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuditableBeanWrapperFactory auditableBeanWrapperFactory() {
|
||||
return new MappingAuditableBeanWrapperFactory(persistentEntities());
|
||||
}
|
||||
|
||||
protected List<HandlerMethodArgumentResolver> defaultMethodArgumentResolvers() {
|
||||
|
||||
SpelAwareProxyProjectionFactory projectionFactory = new SpelAwareProxyProjectionFactory();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
* Copyright 2014-2015 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.
|
||||
@@ -121,7 +121,9 @@ public class RepositoryEntityControllerIntegrationTests extends AbstractControll
|
||||
|
||||
Address address = repository.save(new Address());
|
||||
|
||||
ResponseEntity<?> entity = controller.headForItemResource(getResourceInformation(Address.class), address.id);
|
||||
ResponseEntity<?> entity = controller.headForItemResource(getResourceInformation(Address.class), address.id,
|
||||
assembler);
|
||||
|
||||
assertThat(entity.getStatusCode(), is(HttpStatus.NO_CONTENT));
|
||||
}
|
||||
|
||||
@@ -130,7 +132,7 @@ public class RepositoryEntityControllerIntegrationTests extends AbstractControll
|
||||
*/
|
||||
@Test(expected = ResourceNotFoundException.class)
|
||||
public void doesNotExposeHeadForItemResourceIfNotExisting() throws Exception {
|
||||
controller.headForItemResource(getResourceInformation(CreditCard.class), 1L);
|
||||
controller.headForItemResource(getResourceInformation(CreditCard.class), 1L, assembler);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
* Copyright 2012-2015 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.
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.rest.webmvc.mongodb;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
|
||||
import org.springframework.data.mongodb.config.EnableMongoAuditing;
|
||||
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
|
||||
|
||||
import com.mongodb.Mongo;
|
||||
@@ -24,9 +25,11 @@ import com.mongodb.MongoClient;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Configuration
|
||||
@EnableMongoRepositories
|
||||
@EnableMongoAuditing
|
||||
public class MongoDbRepositoryConfig extends AbstractMongoConfiguration {
|
||||
|
||||
/*
|
||||
|
||||
@@ -186,4 +186,18 @@ public class MongoWebTests extends CommonWebTests {
|
||||
.contentType(MediaType.APPLICATION_JSON).header("If-Match", concurrencyTag)).andExpect(
|
||||
status().isPreconditionFailed());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-471
|
||||
*/
|
||||
@Test
|
||||
public void auditableResourceHasLastModifiedHeaderSet() throws Exception {
|
||||
|
||||
Profile profile = repository.findAll().iterator().next();
|
||||
|
||||
String header = mvc.perform(get("/profiles/{id}", profile.getId())).//
|
||||
andReturn().getResponse().getHeader("Last-Modified");
|
||||
|
||||
assertThat(header, not(isEmptyOrNullString()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
package org.springframework.data.rest.webmvc.mongodb;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
@@ -12,6 +17,7 @@ public class Profile {
|
||||
@Id private String id;
|
||||
private Long person;
|
||||
private String type;
|
||||
private @LastModifiedDate Date lastModifiedDate;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
@@ -40,4 +46,8 @@ public class Profile {
|
||||
return this;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public Date getLastModifiedDate() {
|
||||
return lastModifiedDate;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user