#76 - Adapt to API changes in Spring Data Commons.

This commit is contained in:
Oliver Gierke
2017-03-25 12:39:10 +01:00
parent fc370dbd3a
commit 1383d815e6
5 changed files with 84 additions and 113 deletions

View File

@@ -15,10 +15,17 @@
*/
package org.springframework.data.envers.repository.support;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NonNull;
import lombok.Value;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.Optional;
import org.hibernate.envers.DefaultRevisionEntity;
import org.joda.time.DateTime;
import org.springframework.data.history.RevisionMetadata;
import org.springframework.util.Assert;
/**
* {@link RevisionMetadata} working with a {@link DefaultRevisionEntity}.
@@ -26,35 +33,25 @@ import org.springframework.util.Assert;
* @author Oliver Gierke
* @author Philip Huegelmeyer
*/
@Value
public class DefaultRevisionMetadata implements RevisionMetadata<Integer> {
private final DefaultRevisionEntity entity;
/**
* Creates a new {@link DefaultRevisionMetadata}.
*
* @param entity must not be {@literal null}.
*/
public DefaultRevisionMetadata(DefaultRevisionEntity entity) {
Assert.notNull(entity);
this.entity = entity;
}
private final @NonNull @Getter(AccessLevel.NONE) DefaultRevisionEntity entity;
/*
* (non-Javadoc)
* @see org.springframework.data.history.RevisionMetadata#getRevisionNumber()
*/
public Integer getRevisionNumber() {
return entity.getId();
public Optional<Integer> getRevisionNumber() {
return Optional.ofNullable(entity.getId());
}
/*
* (non-Javadoc)
* @see org.springframework.data.history.RevisionMetadata#getRevisionDate()
*/
public DateTime getRevisionDate() {
return new DateTime(entity.getTimestamp());
public Optional<LocalDateTime> getRevisionDate() {
return Optional.of(LocalDateTime.from(Instant.ofEpochMilli(entity.getTimestamp())));
}
/*

View File

@@ -16,13 +16,12 @@
package org.springframework.data.envers.repository.support;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import javax.persistence.EntityManager;
@@ -42,7 +41,10 @@ import org.springframework.data.history.Revisions;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.data.repository.core.EntityInformation;
import org.springframework.data.repository.history.RevisionRepository;
import org.springframework.data.repository.history.support.RevisionEntityInformation;
import org.springframework.data.util.Pair;
import org.springframework.data.util.StreamUtils;
import org.springframework.util.Assert;
/**
@@ -53,7 +55,7 @@ import org.springframework.util.Assert;
* @author Michael Igler
*/
public class EnversRevisionRepositoryImpl<T, ID extends Serializable, N extends Number & Comparable<N>>
extends SimpleJpaRepository<T, ID> implements EnversRevisionRepository<T, ID, N> {
extends SimpleJpaRepository<T, ID> implements RevisionRepository<T, ID, N> {
private final EntityInformation<T, ?> entityInformation;
private final RevisionEntityInformation revisionEntityInformation;
@@ -72,7 +74,7 @@ public class EnversRevisionRepositoryImpl<T, ID extends Serializable, N extends
super(entityInformation, entityManager);
Assert.notNull(revisionEntityInformation);
Assert.notNull(revisionEntityInformation, "RevisionEntityInformation must not be null!");
this.entityInformation = entityInformation;
this.revisionEntityInformation = revisionEntityInformation;
@@ -84,7 +86,7 @@ public class EnversRevisionRepositoryImpl<T, ID extends Serializable, N extends
* @see org.springframework.data.repository.history.RevisionRepository#findLastChangeRevision(java.io.Serializable)
*/
@SuppressWarnings("unchecked")
public Revision<N, T> findLastChangeRevision(ID id) {
public Optional<Revision<N, T>> findLastChangeRevision(ID id) {
Class<T> type = entityInformation.getJavaType();
AuditReader reader = AuditReaderFactory.get(entityManager);
@@ -92,7 +94,7 @@ public class EnversRevisionRepositoryImpl<T, ID extends Serializable, N extends
List<Number> revisions = reader.getRevisions(type, id);
if (revisions.isEmpty()) {
return null;
return Optional.empty();
}
N latestRevision = (N) revisions.get(revisions.size() - 1);
@@ -101,7 +103,8 @@ public class EnversRevisionRepositoryImpl<T, ID extends Serializable, N extends
Object revisionEntity = reader.findRevision(revisionEntityClass, latestRevision);
RevisionMetadata<N> metadata = (RevisionMetadata<N>) getRevisionMetadata(revisionEntity);
return new Revision<N, T>(metadata, reader.find(type, id, latestRevision));
return Optional.of(Revision.of(metadata, reader.find(type, id, latestRevision)));
}
/*
@@ -109,7 +112,7 @@ public class EnversRevisionRepositoryImpl<T, ID extends Serializable, N extends
* @see org.springframework.data.envers.repository.support.EnversRevisionRepository#findRevision(java.io.Serializable, java.lang.Number)
*/
@Override
public Revision<N, T> findRevision(ID id, N revisionNumber) {
public Optional<Revision<N, T>> findRevision(ID id, N revisionNumber) {
Assert.notNull(id, "Identifier must not be null!");
Assert.notNull(revisionNumber, "Revision number must not be null!");
@@ -128,7 +131,7 @@ public class EnversRevisionRepositoryImpl<T, ID extends Serializable, N extends
AuditReader reader = AuditReaderFactory.get(entityManager);
List<? extends Number> revisionNumbers = reader.getRevisions(type, id);
return revisionNumbers.isEmpty() ? new Revisions<N, T>(Collections.EMPTY_LIST)
return revisionNumbers.isEmpty() ? Revisions.none()
: getEntitiesForRevisions((List<N>) revisionNumbers, id, reader);
}
@@ -149,13 +152,13 @@ public class EnversRevisionRepositoryImpl<T, ID extends Serializable, N extends
}
if (pageable.getOffset() > revisionNumbers.size()) {
return new PageImpl<Revision<N, T>>(Collections.<Revision<N, T>>emptyList(), pageable, 0);
return new PageImpl<Revision<N, T>>(Collections.<Revision<N, T>> emptyList(), pageable, 0);
}
int upperBound = pageable.getOffset() + pageable.getPageSize();
long upperBound = pageable.getOffset() + pageable.getPageSize();
upperBound = upperBound > revisionNumbers.size() ? revisionNumbers.size() : upperBound;
List<? extends Number> subList = revisionNumbers.subList(pageable.getOffset(), upperBound);
List<? extends Number> subList = revisionNumbers.subList(toInt(pageable.getOffset()), toInt(upperBound));
Revisions<N, T> revisions = getEntitiesForRevisions((List<N>) subList, id, reader);
revisions = isDescending ? revisions.reverse() : revisions;
@@ -185,7 +188,7 @@ public class EnversRevisionRepositoryImpl<T, ID extends Serializable, N extends
revisions.put((N) number, reader.find(type, id, number));
}
return new Revisions<N, T>(toRevisions(revisions, revisionEntities));
return Revisions.of(toRevisions(revisions, revisionEntities));
}
/**
@@ -197,31 +200,24 @@ public class EnversRevisionRepositoryImpl<T, ID extends Serializable, N extends
* @return
*/
@SuppressWarnings("unchecked")
private Revision<N, T> getEntityForRevision(N revisionNumber, ID id, AuditReader reader) {
private Optional<Revision<N, T>> getEntityForRevision(N revisionNumber, ID id, AuditReader reader) {
Class<?> type = revisionEntityInformation.getRevisionEntityClass();
T revision = (T) reader.findRevision(type, revisionNumber);
Object entity = reader.find(entityInformation.getJavaType(), id, revisionNumber);
Optional<Object> entity = Optional.ofNullable(reader.find(entityInformation.getJavaType(), id, revisionNumber));
return new Revision<N, T>((RevisionMetadata<N>) getRevisionMetadata(revision), (T) entity);
return entity.map(it -> Revision.of((RevisionMetadata<N>) getRevisionMetadata(revision), (T) it));
}
@SuppressWarnings("unchecked")
private List<Revision<N, T>> toRevisions(Map<N, T> source, Map<Number, Object> revisionEntities) {
List<Revision<N, T>> result = new ArrayList<Revision<N, T>>();
for (Entry<N, T> revision : source.entrySet()) {
N revisionNumber = revision.getKey();
T entity = revision.getValue();
RevisionMetadata<N> metadata = (RevisionMetadata<N>) getRevisionMetadata(revisionEntities.get(revisionNumber));
result.add(new Revision<N, T>(metadata, entity));
}
Collections.sort(result);
return Collections.unmodifiableList(result);
return source.entrySet().stream()//
.map(entry -> Pair.of(revisionEntities.get(entry.getKey()), entry.getValue()))//
.map(pair -> Revision.of((RevisionMetadata<N>) getRevisionMetadata(pair.getFirst()), pair.getSecond()))//
.sorted()//
.collect(StreamUtils.toUnmodifiableList());
}
/**
@@ -231,10 +227,18 @@ public class EnversRevisionRepositoryImpl<T, ID extends Serializable, N extends
* @return
*/
private RevisionMetadata<?> getRevisionMetadata(Object object) {
if (object instanceof DefaultRevisionEntity) {
return new DefaultRevisionMetadata((DefaultRevisionEntity) object);
} else {
return new AnnotationRevisionMetadata<N>(object, RevisionNumber.class, RevisionTimestamp.class);
return object instanceof DefaultRevisionEntity //
? new DefaultRevisionMetadata((DefaultRevisionEntity) object) //
: new AnnotationRevisionMetadata<N>(object, RevisionNumber.class, RevisionTimestamp.class);
}
private static int toInt(long value) {
if (value > Integer.MAX_VALUE) {
throw new IllegalStateException(String.format("%s can't be mapped to an integer, too large!", value));
}
return Long.valueOf(value).intValue();
}
}

View File

@@ -15,6 +15,8 @@
*/
package org.springframework.data.envers.repository.support;
import lombok.Getter;
import org.hibernate.envers.RevisionNumber;
import org.springframework.data.repository.history.support.RevisionEntityInformation;
import org.springframework.data.util.AnnotationDetectionFieldCallback;
@@ -27,6 +29,7 @@ import org.springframework.util.ReflectionUtils;
*
* @author Oliver Gierke
*/
@Getter
public class ReflectionRevisionEntityInformation implements RevisionEntityInformation {
private final Class<?> revisionEntityClass;
@@ -39,24 +42,16 @@ public class ReflectionRevisionEntityInformation implements RevisionEntityInform
*/
public ReflectionRevisionEntityInformation(Class<?> revisionEntityClass) {
Assert.notNull(revisionEntityClass);
Assert.notNull(revisionEntityClass, "Revision entity type must not be null!");
AnnotationDetectionFieldCallback fieldCallback = new AnnotationDetectionFieldCallback(RevisionNumber.class);
ReflectionUtils.doWithFields(revisionEntityClass, fieldCallback);
this.revisionNumberType = fieldCallback.getType();
this.revisionNumberType = fieldCallback.getRequiredType();
this.revisionEntityClass = revisionEntityClass;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.history.support.RevisionEntityInformation#getRevisionNumberType()
*/
public Class<?> getRevisionNumberType() {
return revisionNumberType;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.history.support.RevisionEntityInformation#isDefaultRevisionEntity()
@@ -64,12 +59,4 @@ public class ReflectionRevisionEntityInformation implements RevisionEntityInform
public boolean isDefaultRevisionEntity() {
return false;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.history.support.RevisionEntityInformation#getRevisionEntityClass()
*/
public Class<?> getRevisionEntityClass() {
return revisionEntityClass;
}
}

View File

@@ -15,15 +15,13 @@
*/
package org.springframework.data.envers.repository.support;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.assertj.core.api.Assertions.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -88,17 +86,19 @@ public class RepositoryIntegrationTests {
countryRepository.save(de);
Revision<Integer, License> revision = licenseRepository.findLastChangeRevision(license.id);
assertThat(revision, is(notNullValue()));
Optional<Revision<Integer, License>> revision = licenseRepository.findLastChangeRevision(license.id);
Page<Revision<Integer, License>> revisions = licenseRepository.findRevisions(license.id, new PageRequest(0, 10));
Revisions<Integer, License> wrapper = new Revisions<Integer, License>(revisions.getContent());
assertThat(wrapper.getLatestRevision(), is(revision));
assertThat(revision).hasValueSatisfying(it -> {
Page<Revision<Integer, License>> page = licenseRepository.findRevisions(license.id, PageRequest.of(0, 10));
Revisions<Integer, License> revisions = Revisions.of(page.getContent());
assertThat(revisions.getLatestRevision()).isEqualTo(it);
});
}
@Test
public void returnsEmptyRevisionsForUnrevisionedEntity() {
assertThat(countryRepository.findRevisions(100L).getContent(), is(hasSize(0)));
assertThat(countryRepository.findRevisions(100L)).isEmpty();
}
/**
@@ -119,14 +119,19 @@ public class RepositoryIntegrationTests {
Revisions<Integer, Country> revisions = countryRepository.findRevisions(de.id);
assertThat(revisions, is(Matchers.<Revision<Integer, Country>>iterableWithSize(2)));
assertThat(revisions).hasSize(2);
Iterator<Revision<Integer, Country>> iterator = revisions.iterator();
Revision<Integer, Country> first = iterator.next();
Revision<Integer, Country> second = iterator.next();
assertThat(countryRepository.findRevision(de.id, first.getRevisionNumber()).getEntity().name, is("Deutschland"));
assertThat(countryRepository.findRevision(de.id, second.getRevisionNumber()).getEntity().name, is("Germany"));
assertThat(countryRepository.findRevision(de.id, first.getRequiredRevisionNumber())).hasValueSatisfying(it -> {
assertThat(it.getEntity().name).isEqualTo("Deutschland");
});
assertThat(countryRepository.findRevision(de.id, second.getRequiredRevisionNumber())).hasValueSatisfying(it -> {
assertThat(it.getEntity().name).isEqualTo("Germany");
});
}
/**
@@ -145,10 +150,11 @@ public class RepositoryIntegrationTests {
countryRepository.save(de);
List<Revision<Integer, Country>> content = countryRepository
.findRevisions(de.id, new PageRequest(0, 10, RevisionSort.desc())).getContent();
Page<Revision<Integer, Country>> page = countryRepository.findRevisions(de.id,
PageRequest.of(0, 10, RevisionSort.desc()));
assertThat(content, hasSize(2));
assertThat(content.get(0).getRevisionNumber(), is(greaterThan(content.get(1).getRevisionNumber())));
assertThat(page).hasSize(2);
assertThat(page.getContent().get(0).getRequiredRevisionNumber())
.isGreaterThan(page.getContent().get(1).getRequiredRevisionNumber());
}
}

View File

@@ -15,38 +15,15 @@
*/
package org.springframework.data.envers.sample;
import lombok.EqualsAndHashCode;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import org.springframework.util.ObjectUtils;
@MappedSuperclass
@EqualsAndHashCode
abstract class AbstractEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long id;
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof AbstractEntity)) {
return false;
}
AbstractEntity that = (AbstractEntity) obj;
return ObjectUtils.nullSafeEquals(this.id, that.id);
}
}
public @Id @GeneratedValue Long id;
}