Browse Source

DATAJDBC-137 - Improve EntityInformation usage.

Moved to both the usage of the newly introduced PersistentEntity.isNew(…) and identifier lookups via PersistentEntity instead of using a custom EntityInformation implementation. JdbcRepositoryFactory now creates a PersistentEntityInformation, SimpleJdbcRepository simply works with a PersistentEntity.

Removed references to EntityInformation (a repository subsystem concept) from the template implementation. Removed BasicJdbcPersistentEntity and its tests entirely. JdbcAuditingEventListener is now using an IsNewAwareAuditingHandler.

Related tickets: DATACMNS-1333.
pull/73/head
Oliver Gierke 8 years ago
parent
commit
fca2ef6629
No known key found for this signature in database
GPG Key ID: 6E42B5787543F690
  1. 31
      src/main/java/org/springframework/data/jdbc/core/DefaultDataAccessStrategy.java
  2. 30
      src/main/java/org/springframework/data/jdbc/core/JdbcAggregateTemplate.java
  3. 27
      src/main/java/org/springframework/data/jdbc/core/conversion/JdbcEntityWriter.java
  4. 58
      src/main/java/org/springframework/data/jdbc/core/mapping/BasicJdbcPersistentEntityInformation.java
  5. 5
      src/main/java/org/springframework/data/jdbc/core/mapping/JdbcMappingContext.java
  6. 43
      src/main/java/org/springframework/data/jdbc/core/mapping/JdbcPersistentEntityInformation.java
  7. 27
      src/main/java/org/springframework/data/jdbc/domain/support/JdbcAuditingEventListener.java
  8. 2
      src/main/java/org/springframework/data/jdbc/mybatis/MyBatisDataAccessStrategy.java
  9. 10
      src/main/java/org/springframework/data/jdbc/repository/config/JdbcAuditingRegistrar.java
  10. 13
      src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java
  11. 20
      src/main/java/org/springframework/data/jdbc/repository/support/SimpleJdbcRepository.java
  12. 96
      src/test/java/org/springframework/data/jdbc/core/mapping/BasicJdbcPersistentEntityInformationUnitTests.java

31
src/main/java/org/springframework/data/jdbc/core/DefaultDataAccessStrategy.java

@ -27,15 +27,14 @@ import java.util.stream.StreamSupport;
import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.NonTransientDataAccessException; import org.springframework.dao.NonTransientDataAccessException;
import org.springframework.data.jdbc.core.mapping.BasicJdbcPersistentEntityInformation;
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
import org.springframework.data.jdbc.core.mapping.JdbcPersistentEntity; import org.springframework.data.jdbc.core.mapping.JdbcPersistentEntity;
import org.springframework.data.jdbc.core.mapping.JdbcPersistentEntityInformation;
import org.springframework.data.jdbc.core.mapping.JdbcPersistentProperty; import org.springframework.data.jdbc.core.mapping.JdbcPersistentProperty;
import org.springframework.data.jdbc.support.JdbcUtil; import org.springframework.data.jdbc.support.JdbcUtil;
import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.mapping.PropertyHandler; import org.springframework.data.mapping.PropertyHandler;
import org.springframework.data.mapping.PropertyPath; import org.springframework.data.mapping.PropertyPath;
import org.springframework.data.repository.core.EntityInformation; import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
@ -58,8 +57,8 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
private final @NonNull SqlGeneratorSource sqlGeneratorSource; private final @NonNull SqlGeneratorSource sqlGeneratorSource;
private final @NonNull JdbcMappingContext context; private final @NonNull JdbcMappingContext context;
private final @NonNull DataAccessStrategy accessStrategy;
private final @NonNull NamedParameterJdbcOperations operations; private final @NonNull NamedParameterJdbcOperations operations;
private final @NonNull DataAccessStrategy accessStrategy;
/** /**
* Creates a {@link DefaultDataAccessStrategy} which references it self for resolution of recursive data accesses. * Creates a {@link DefaultDataAccessStrategy} which references it self for resolution of recursive data accesses.
@ -79,8 +78,6 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
KeyHolder holder = new GeneratedKeyHolder(); KeyHolder holder = new GeneratedKeyHolder();
JdbcPersistentEntity<T> persistentEntity = getRequiredPersistentEntity(domainType); JdbcPersistentEntity<T> persistentEntity = getRequiredPersistentEntity(domainType);
JdbcPersistentEntityInformation<T, ?> entityInformation = context
.getRequiredPersistentEntityInformation(domainType);
MapSqlParameterSource parameterSource = getPropertyMap(instance, persistentEntity); MapSqlParameterSource parameterSource = getPropertyMap(instance, persistentEntity);
@ -103,7 +100,8 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
// if there is an id property and it was null before the save // if there is an id property and it was null before the save
// The database should have created an id and provided it. // The database should have created an id and provided it.
if (idProperty != null && idValue == null && entityInformation.isNew(instance)) {
if (idProperty != null && idValue == null && persistentEntity.isNew(instance)) {
throw new IllegalStateException(String.format(ENTITY_NEW_AFTER_INSERT, persistentEntity)); throw new IllegalStateException(String.format(ENTITY_NEW_AFTER_INSERT, persistentEntity));
} }
} }
@ -278,15 +276,12 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private <S, ID> ID getIdValueOrNull(S instance, JdbcPersistentEntity<S> persistentEntity) { private <S, ID> ID getIdValueOrNull(S instance, JdbcPersistentEntity<S> persistentEntity) {
EntityInformation<S, ID> entityInformation = (EntityInformation<S, ID>) context ID idValue = (ID) persistentEntity.getIdentifierAccessor(instance).getIdentifier();
.getRequiredPersistentEntityInformation(persistentEntity.getType());
ID idValue = entityInformation.getId(instance);
return isIdPropertyNullOrScalarZero(idValue, persistentEntity) ? null : idValue; return isIdPropertyNullOrScalarZero(idValue, persistentEntity) ? null : idValue;
} }
private <S, ID> boolean isIdPropertyNullOrScalarZero(ID idValue, JdbcPersistentEntity<S> persistentEntity) { private static <S, ID> boolean isIdPropertyNullOrScalarZero(ID idValue, JdbcPersistentEntity<S> persistentEntity) {
JdbcPersistentProperty idProperty = persistentEntity.getIdProperty(); JdbcPersistentProperty idProperty = persistentEntity.getIdProperty();
return idValue == null // return idValue == null //
@ -297,16 +292,16 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
private <S> void setIdFromJdbc(S instance, KeyHolder holder, JdbcPersistentEntity<S> persistentEntity) { private <S> void setIdFromJdbc(S instance, KeyHolder holder, JdbcPersistentEntity<S> persistentEntity) {
JdbcPersistentEntityInformation<S, ?> entityInformation = new BasicJdbcPersistentEntityInformation<>(
persistentEntity);
try { try {
getIdFromHolder(holder, persistentEntity).ifPresent(it -> { getIdFromHolder(holder, persistentEntity).ifPresent(it -> {
Class<?> targetType = persistentEntity.getRequiredIdProperty().getType(); PersistentPropertyAccessor accessor = persistentEntity.getPropertyAccessor(instance);
Object converted = convert(it, targetType); ConvertingPropertyAccessor convertingPropertyAccessor = new ConvertingPropertyAccessor(accessor,
entityInformation.setId(instance, converted); context.getConversions());
JdbcPersistentProperty idProperty = persistentEntity.getRequiredIdProperty();
convertingPropertyAccessor.setProperty(idProperty, it);
}); });
} catch (NonTransientDataAccessException e) { } catch (NonTransientDataAccessException e) {

30
src/main/java/org/springframework/data/jdbc/core/JdbcAggregateTemplate.java

@ -24,7 +24,7 @@ import org.springframework.data.jdbc.core.conversion.Interpreter;
import org.springframework.data.jdbc.core.conversion.JdbcEntityDeleteWriter; import org.springframework.data.jdbc.core.conversion.JdbcEntityDeleteWriter;
import org.springframework.data.jdbc.core.conversion.JdbcEntityWriter; import org.springframework.data.jdbc.core.conversion.JdbcEntityWriter;
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
import org.springframework.data.jdbc.core.mapping.JdbcPersistentEntityInformation; import org.springframework.data.jdbc.core.mapping.JdbcPersistentEntity;
import org.springframework.data.jdbc.core.mapping.event.AfterDeleteEvent; import org.springframework.data.jdbc.core.mapping.event.AfterDeleteEvent;
import org.springframework.data.jdbc.core.mapping.event.AfterLoadEvent; import org.springframework.data.jdbc.core.mapping.event.AfterLoadEvent;
import org.springframework.data.jdbc.core.mapping.event.AfterSaveEvent; import org.springframework.data.jdbc.core.mapping.event.AfterSaveEvent;
@ -32,6 +32,8 @@ import org.springframework.data.jdbc.core.mapping.event.BeforeDeleteEvent;
import org.springframework.data.jdbc.core.mapping.event.BeforeSaveEvent; import org.springframework.data.jdbc.core.mapping.event.BeforeSaveEvent;
import org.springframework.data.jdbc.core.mapping.event.Identifier; import org.springframework.data.jdbc.core.mapping.event.Identifier;
import org.springframework.data.jdbc.core.mapping.event.Identifier.Specified; import org.springframework.data.jdbc.core.mapping.event.Identifier.Specified;
import org.springframework.data.mapping.IdentifierAccessor;
import org.springframework.util.Assert;
/** /**
* {@link JdbcAggregateOperations} implementation, storing aggregates in and obtaining them from a JDBC data store. * {@link JdbcAggregateOperations} implementation, storing aggregates in and obtaining them from a JDBC data store.
@ -52,7 +54,7 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
private final DataAccessStrategy accessStrategy; private final DataAccessStrategy accessStrategy;
public JdbcAggregateTemplate(ApplicationEventPublisher publisher, JdbcMappingContext context, public JdbcAggregateTemplate(ApplicationEventPublisher publisher, JdbcMappingContext context,
DataAccessStrategy dataAccessStrategy) { DataAccessStrategy dataAccessStrategy) {
this.publisher = publisher; this.publisher = publisher;
this.context = context; this.context = context;
@ -66,13 +68,15 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
@Override @Override
public <T> void save(T instance) { public <T> void save(T instance) {
JdbcPersistentEntityInformation<T, ?> entityInformation = context Assert.notNull(instance, "Agggregate instance must not be null!");
.getRequiredPersistentEntityInformation((Class<T>) instance.getClass());
JdbcPersistentEntity<?> entity = context.getRequiredPersistentEntity(instance.getClass());
IdentifierAccessor identifierAccessor = entity.getIdentifierAccessor(instance);
AggregateChange change = createChange(instance); AggregateChange change = createChange(instance);
publisher.publishEvent(new BeforeSaveEvent( // publisher.publishEvent(new BeforeSaveEvent( //
Identifier.ofNullable(entityInformation.getId(instance)), // Identifier.ofNullable(identifierAccessor.getIdentifier()), //
instance, // instance, //
change // change //
)); ));
@ -80,7 +84,7 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
change.executeWith(interpreter); change.executeWith(interpreter);
publisher.publishEvent(new AfterSaveEvent( // publisher.publishEvent(new AfterSaveEvent( //
Identifier.of(entityInformation.getId(instance)), // Identifier.of(identifierAccessor.getIdentifier()), //
instance, // instance, //
change // change //
)); ));
@ -125,9 +129,10 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
@Override @Override
public <S> void delete(S entity, Class<S> domainType) { public <S> void delete(S entity, Class<S> domainType) {
JdbcPersistentEntityInformation<S, ?> entityInformation = context IdentifierAccessor identifierAccessor = context.getRequiredPersistentEntity(domainType)
.getRequiredPersistentEntityInformation(domainType); .getIdentifierAccessor(entity);
deleteTree(entityInformation.getRequiredId(entity), entity, domainType);
deleteTree(identifierAccessor.getRequiredIdentifier(), entity, domainType);
} }
@Override @Override
@ -178,11 +183,14 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
return aggregateChange; return aggregateChange;
} }
@SuppressWarnings("unchecked")
private <T> void publishAfterLoad(Iterable<T> all) { private <T> void publishAfterLoad(Iterable<T> all) {
for (T e : all) { for (T e : all) {
publishAfterLoad(context.getRequiredPersistentEntityInformation((Class<T>) e.getClass()).getRequiredId(e), e);
JdbcPersistentEntity<?> entity = context.getPersistentEntity(e.getClass());
IdentifierAccessor identifierAccessor = entity.getIdentifierAccessor(e);
publishAfterLoad(identifierAccessor.getRequiredIdentifier(), e);
} }
} }

27
src/main/java/org/springframework/data/jdbc/core/conversion/JdbcEntityWriter.java

@ -27,12 +27,12 @@ import org.springframework.data.jdbc.core.conversion.DbAction.Insert;
import org.springframework.data.jdbc.core.conversion.DbAction.Update; import org.springframework.data.jdbc.core.conversion.DbAction.Update;
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
import org.springframework.data.jdbc.core.mapping.JdbcPersistentEntity; import org.springframework.data.jdbc.core.mapping.JdbcPersistentEntity;
import org.springframework.data.jdbc.core.mapping.JdbcPersistentEntityInformation;
import org.springframework.data.jdbc.core.mapping.JdbcPersistentProperty; import org.springframework.data.jdbc.core.mapping.JdbcPersistentProperty;
import org.springframework.data.mapping.IdentifierAccessor;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.mapping.PersistentPropertyAccessor; import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.util.StreamUtils; import org.springframework.data.util.StreamUtils;
import org.springframework.util.ClassUtils;
/** /**
* Converts an entity that is about to be saved into {@link DbAction}s inside a {@link AggregateChange} that need to be * Converts an entity that is about to be saved into {@link DbAction}s inside a {@link AggregateChange} that need to be
@ -43,8 +43,13 @@ import org.springframework.util.ClassUtils;
*/ */
public class JdbcEntityWriter extends JdbcEntityWriterSupport { public class JdbcEntityWriter extends JdbcEntityWriterSupport {
private final JdbcMappingContext context;
public JdbcEntityWriter(JdbcMappingContext context) { public JdbcEntityWriter(JdbcMappingContext context) {
super(context); super(context);
this.context = context;
} }
@Override @Override
@ -54,11 +59,12 @@ public class JdbcEntityWriter extends JdbcEntityWriterSupport {
private void write(Object o, AggregateChange aggregateChange, DbAction dependingOn) { private void write(Object o, AggregateChange aggregateChange, DbAction dependingOn) {
Class<Object> type = (Class<Object>) o.getClass(); Class<?> type = o.getClass();
JdbcPersistentEntityInformation<Object, ?> entityInformation = context.getRequiredPersistentEntityInformation(type);
JdbcPropertyPath propertyPath = JdbcPropertyPath.from("", type); JdbcPropertyPath propertyPath = JdbcPropertyPath.from("", type);
if (entityInformation.isNew(o)) { PersistentEntity<?, JdbcPersistentProperty> persistentEntity = context.getRequiredPersistentEntity(type);
if (persistentEntity.isNew(o)) {
Insert<Object> insert = DbAction.insert(o, propertyPath, dependingOn); Insert<Object> insert = DbAction.insert(o, propertyPath, dependingOn);
aggregateChange.addAction(insert); aggregateChange.addAction(insert);
@ -71,10 +77,13 @@ public class JdbcEntityWriter extends JdbcEntityWriterSupport {
aggregateChange, // aggregateChange, //
propertyPath.nested(propertyAndValue.property.getName()), // propertyPath.nested(propertyAndValue.property.getName()), //
insert) // insert) //
); );
} else { } else {
deleteReferencedEntities(entityInformation.getRequiredId(o), aggregateChange); JdbcPersistentEntity<?> entity = context.getPersistentEntity(type);
IdentifierAccessor identifierAccessor = entity.getIdentifierAccessor(o);
deleteReferencedEntities(identifierAccessor.getRequiredIdentifier(), aggregateChange);
Update<Object> update = DbAction.update(o, propertyPath, dependingOn); Update<Object> update = DbAction.update(o, propertyPath, dependingOn);
aggregateChange.addAction(update); aggregateChange.addAction(update);
@ -104,7 +113,7 @@ public class JdbcEntityWriter extends JdbcEntityWriterSupport {
aggregateChange, // aggregateChange, //
propertyPath.nested(pav.property.getName()), // propertyPath.nested(pav.property.getName()), //
dependingOn) // dependingOn) //
); );
} }
private Stream<PropertyAndValue> referencedEntities(Object o) { private Stream<PropertyAndValue> referencedEntities(Object o) {
@ -116,7 +125,7 @@ public class JdbcEntityWriter extends JdbcEntityWriterSupport {
.flatMap( // .flatMap( //
p -> referencedEntity(p, persistentEntity.getPropertyAccessor(o)) // p -> referencedEntity(p, persistentEntity.getPropertyAccessor(o)) //
.map(e -> new PropertyAndValue(p, e)) // .map(e -> new PropertyAndValue(p, e)) //
); );
} }
private Stream<Object> referencedEntity(JdbcPersistentProperty p, PersistentPropertyAccessor propertyAccessor) { private Stream<Object> referencedEntity(JdbcPersistentProperty p, PersistentPropertyAccessor propertyAccessor) {

58
src/main/java/org/springframework/data/jdbc/core/mapping/BasicJdbcPersistentEntityInformation.java

@ -1,58 +0,0 @@
/*
* Copyright 2017-2018 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.jdbc.core.mapping;
import org.springframework.data.domain.Persistable;
import org.springframework.data.repository.core.support.PersistentEntityInformation;
import org.springframework.lang.Nullable;
/**
* @author Jens Schauder
* @since 1.0
*/
public class BasicJdbcPersistentEntityInformation<T, ID> extends PersistentEntityInformation<T, ID>
implements JdbcPersistentEntityInformation<T, ID> {
private final JdbcPersistentEntity<T> persistentEntity;
public BasicJdbcPersistentEntityInformation(JdbcPersistentEntity<T> persistentEntity) {
super(persistentEntity);
this.persistentEntity = persistentEntity;
}
@Override
public boolean isNew(T entity) {
return entity instanceof Persistable ? ((Persistable) entity).isNew() : super.isNew(entity);
}
@SuppressWarnings("unchecked")
@Nullable
@Override
public ID getId(T entity) {
return entity instanceof Persistable ? ((Persistable<ID>)entity).getId() : super.getId(entity);
}
/*
* (non-Javadoc)
* @see org.springframework.data.jdbc.core.mapping.model.JdbcPersistentEntityInformation#setId(java.lang.Object, java.util.Optional)
*/
@Override
public void setId(T instance, Object value) {
persistentEntity.getPropertyAccessor(instance).setProperty(persistentEntity.getRequiredIdProperty(), value);
}
}

5
src/main/java/org/springframework/data/jdbc/core/mapping/JdbcMappingContext.java

@ -139,11 +139,6 @@ public class JdbcMappingContext extends AbstractMappingContext<JdbcPersistentEnt
return new BasicJdbcPersistentProperty(property, owner, simpleTypeHolder, this); return new BasicJdbcPersistentProperty(property, owner, simpleTypeHolder, this);
} }
@SuppressWarnings("unchecked")
public <T> JdbcPersistentEntityInformation<T, ?> getRequiredPersistentEntityInformation(Class<T> type) {
return new BasicJdbcPersistentEntityInformation<>((JdbcPersistentEntity<T>) getRequiredPersistentEntity(type));
}
public ConversionService getConversions() { public ConversionService getConversions() {
return conversions; return conversions;
} }

43
src/main/java/org/springframework/data/jdbc/core/mapping/JdbcPersistentEntityInformation.java

@ -1,43 +0,0 @@
/*
* Copyright 2017-2018 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.jdbc.core.mapping;
import org.springframework.data.repository.core.EntityInformation;
/**
* @author Jens Schauder
* @since 1.0
*/
public interface JdbcPersistentEntityInformation<T, ID> extends EntityInformation<T, ID> {
void setId(T instance, Object value);
/**
* Returns the identifier of the given entity or throws and exception if it can't be obtained.
*
* @param entity must not be {@literal null}.
* @return the identifier of the given entity
* @throws IllegalArgumentException in case no identifier can be obtained for the given entity.
*/
default ID getRequiredId(T entity) {
ID id = getId(entity);
if (id == null)
throw new IllegalStateException(String.format("Could not obtain required identifier from entity %s!", entity));
return id;
}
}

27
src/main/java/org/springframework/data/jdbc/domain/support/JdbcAuditingEventListener.java

@ -18,9 +18,7 @@ package org.springframework.data.jdbc.domain.support;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
import org.springframework.data.auditing.AuditingHandler; import org.springframework.data.auditing.IsNewAwareAuditingHandler;
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
import org.springframework.data.jdbc.core.mapping.JdbcPersistentEntityInformation;
import org.springframework.data.jdbc.core.mapping.event.BeforeSaveEvent; import org.springframework.data.jdbc.core.mapping.event.BeforeSaveEvent;
import org.springframework.data.jdbc.repository.config.EnableJdbcAuditing; import org.springframework.data.jdbc.repository.config.EnableJdbcAuditing;
@ -31,14 +29,14 @@ import org.springframework.data.jdbc.repository.config.EnableJdbcAuditing;
* *
* @author Kazuki Shimizu * @author Kazuki Shimizu
* @author Jens Schauder * @author Jens Schauder
* @author Oliver Gierke
* @see EnableJdbcAuditing * @see EnableJdbcAuditing
* @since 1.0 * @since 1.0
*/ */
@RequiredArgsConstructor @RequiredArgsConstructor
public class JdbcAuditingEventListener implements ApplicationListener<BeforeSaveEvent> { public class JdbcAuditingEventListener implements ApplicationListener<BeforeSaveEvent> {
private final AuditingHandler handler; private final IsNewAwareAuditingHandler handler;
private final JdbcMappingContext context;
/** /**
* {@inheritDoc} * {@inheritDoc}
@ -47,23 +45,6 @@ public class JdbcAuditingEventListener implements ApplicationListener<BeforeSave
*/ */
@Override @Override
public void onApplicationEvent(BeforeSaveEvent event) { public void onApplicationEvent(BeforeSaveEvent event) {
handler.markAudited(event.getEntity());
Object entity = event.getEntity();
@SuppressWarnings("unchecked")
Class<Object> entityType = event.getChange().getEntityType();
JdbcPersistentEntityInformation<Object, ?> entityInformation = context
.getRequiredPersistentEntityInformation(entityType);
invokeHandler(entity, entityInformation);
}
private <T> void invokeHandler(T entity, JdbcPersistentEntityInformation<T, ?> entityInformation) {
if (entityInformation.isNew(entity)) {
handler.markCreated(entity);
} else {
handler.markModified(entity);
}
} }
} }

2
src/main/java/org/springframework/data/jdbc/mybatis/MyBatisDataAccessStrategy.java

@ -80,7 +80,7 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy {
SqlGeneratorSource sqlGeneratorSource = new SqlGeneratorSource(context); SqlGeneratorSource sqlGeneratorSource = new SqlGeneratorSource(context);
DefaultDataAccessStrategy defaultDataAccessStrategy = new DefaultDataAccessStrategy(sqlGeneratorSource, context, DefaultDataAccessStrategy defaultDataAccessStrategy = new DefaultDataAccessStrategy(sqlGeneratorSource, context,
cascadingDataAccessStrategy, operations); operations, cascadingDataAccessStrategy);
delegatingDataAccessStrategy.setDelegate(defaultDataAccessStrategy); delegatingDataAccessStrategy.setDelegate(defaultDataAccessStrategy);

10
src/main/java/org/springframework/data/jdbc/repository/config/JdbcAuditingRegistrar.java

@ -21,9 +21,11 @@ import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
import org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport; import org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport;
import org.springframework.data.auditing.config.AuditingConfiguration; import org.springframework.data.auditing.config.AuditingConfiguration;
import org.springframework.data.jdbc.domain.support.JdbcAuditingEventListener; import org.springframework.data.jdbc.domain.support.JdbcAuditingEventListener;
import org.springframework.util.Assert;
/** /**
* {@link ImportBeanDefinitionRegistrar} which registers additional beans in order to enable auditing via the * {@link ImportBeanDefinitionRegistrar} which registers additional beans in order to enable auditing via the
@ -68,7 +70,10 @@ class JdbcAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
@Override @Override
protected BeanDefinitionBuilder getAuditHandlerBeanDefinitionBuilder(AuditingConfiguration configuration) { protected BeanDefinitionBuilder getAuditHandlerBeanDefinitionBuilder(AuditingConfiguration configuration) {
BeanDefinitionBuilder builder = super.getAuditHandlerBeanDefinitionBuilder(configuration); Assert.notNull(configuration, "AuditingConfiguration must not be null!");
BeanDefinitionBuilder builder = configureDefaultAuditHandlerAttributes(configuration,
BeanDefinitionBuilder.rootBeanDefinition(IsNewAwareAuditingHandler.class));
return builder.addConstructorArgReference(JDBC_MAPPING_CONTEXT_BEAN_NAME); return builder.addConstructorArgReference(JDBC_MAPPING_CONTEXT_BEAN_NAME);
} }
@ -84,8 +89,7 @@ class JdbcAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
Class<?> listenerClass = JdbcAuditingEventListener.class; Class<?> listenerClass = JdbcAuditingEventListener.class;
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(listenerClass) // BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(listenerClass) //
.addConstructorArgReference(AUDITING_HANDLER_BEAN_NAME) // .addConstructorArgReference(AUDITING_HANDLER_BEAN_NAME);
.addConstructorArgReference(JDBC_MAPPING_CONTEXT_BEAN_NAME);
registerInfrastructureBeanWithId(builder.getRawBeanDefinition(), listenerClass.getName(), registry); registerInfrastructureBeanWithId(builder.getRawBeanDefinition(), listenerClass.getName(), registry);
} }

13
src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java

@ -21,11 +21,12 @@ import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.jdbc.core.DataAccessStrategy; import org.springframework.data.jdbc.core.DataAccessStrategy;
import org.springframework.data.jdbc.core.JdbcAggregateTemplate; import org.springframework.data.jdbc.core.JdbcAggregateTemplate;
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
import org.springframework.data.jdbc.core.mapping.JdbcPersistentEntityInformation; import org.springframework.data.jdbc.core.mapping.JdbcPersistentEntity;
import org.springframework.data.jdbc.repository.RowMapperMap; import org.springframework.data.jdbc.repository.RowMapperMap;
import org.springframework.data.repository.core.EntityInformation; import org.springframework.data.repository.core.EntityInformation;
import org.springframework.data.repository.core.RepositoryInformation; import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.PersistentEntityInformation;
import org.springframework.data.repository.core.support.RepositoryFactorySupport; import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.repository.query.QueryLookupStrategy; import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider; import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
@ -84,7 +85,10 @@ public class JdbcRepositoryFactory extends RepositoryFactorySupport {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public <T, ID> EntityInformation<T, ID> getEntityInformation(Class<T> aClass) { public <T, ID> EntityInformation<T, ID> getEntityInformation(Class<T> aClass) {
return (EntityInformation<T, ID>) context.getRequiredPersistentEntityInformation(aClass);
JdbcPersistentEntity<?> entity = context.getPersistentEntity(aClass);
return (EntityInformation<T, ID>) new PersistentEntityInformation<>(entity);
} }
/* /*
@ -94,12 +98,9 @@ public class JdbcRepositoryFactory extends RepositoryFactorySupport {
@Override @Override
protected Object getTargetRepository(RepositoryInformation repositoryInformation) { protected Object getTargetRepository(RepositoryInformation repositoryInformation) {
JdbcPersistentEntityInformation<?, ?> persistentEntityInformation = context
.getRequiredPersistentEntityInformation(repositoryInformation.getDomainType());
JdbcAggregateTemplate template = new JdbcAggregateTemplate(publisher, context, accessStrategy); JdbcAggregateTemplate template = new JdbcAggregateTemplate(publisher, context, accessStrategy);
return new SimpleJdbcRepository<>(template, persistentEntityInformation); return new SimpleJdbcRepository<>(template, context.getPersistentEntity(repositoryInformation.getDomainType()));
} }
/* /*

20
src/main/java/org/springframework/data/jdbc/repository/support/SimpleJdbcRepository.java

@ -23,7 +23,7 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
import org.springframework.data.jdbc.core.JdbcAggregateOperations; import org.springframework.data.jdbc.core.JdbcAggregateOperations;
import org.springframework.data.jdbc.core.mapping.JdbcPersistentEntityInformation; import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
/** /**
@ -35,7 +35,7 @@ import org.springframework.data.repository.CrudRepository;
public class SimpleJdbcRepository<T, ID> implements CrudRepository<T, ID> { public class SimpleJdbcRepository<T, ID> implements CrudRepository<T, ID> {
private final @NonNull JdbcAggregateOperations entityOperations; private final @NonNull JdbcAggregateOperations entityOperations;
private final @NonNull JdbcPersistentEntityInformation<T, ID> entityInformation; private final @NonNull PersistentEntity<T, ?> entity;
/* /*
* (non-Javadoc) * (non-Javadoc)
@ -67,7 +67,7 @@ public class SimpleJdbcRepository<T, ID> implements CrudRepository<T, ID> {
*/ */
@Override @Override
public Optional<T> findById(ID id) { public Optional<T> findById(ID id) {
return Optional.ofNullable(entityOperations.findById(id, entityInformation.getJavaType())); return Optional.ofNullable(entityOperations.findById(id, entity.getType()));
} }
/* /*
@ -76,7 +76,7 @@ public class SimpleJdbcRepository<T, ID> implements CrudRepository<T, ID> {
*/ */
@Override @Override
public boolean existsById(ID id) { public boolean existsById(ID id) {
return entityOperations.existsById(id, entityInformation.getJavaType()); return entityOperations.existsById(id, entity.getType());
} }
/* /*
@ -85,7 +85,7 @@ public class SimpleJdbcRepository<T, ID> implements CrudRepository<T, ID> {
*/ */
@Override @Override
public Iterable<T> findAll() { public Iterable<T> findAll() {
return entityOperations.findAll(entityInformation.getJavaType()); return entityOperations.findAll(entity.getType());
} }
/* /*
@ -94,7 +94,7 @@ public class SimpleJdbcRepository<T, ID> implements CrudRepository<T, ID> {
*/ */
@Override @Override
public Iterable<T> findAllById(Iterable<ID> ids) { public Iterable<T> findAllById(Iterable<ID> ids) {
return entityOperations.findAllById(ids, entityInformation.getJavaType()); return entityOperations.findAllById(ids, entity.getType());
} }
/* /*
@ -103,7 +103,7 @@ public class SimpleJdbcRepository<T, ID> implements CrudRepository<T, ID> {
*/ */
@Override @Override
public long count() { public long count() {
return entityOperations.count(entityInformation.getJavaType()); return entityOperations.count(entity.getType());
} }
/* /*
@ -112,7 +112,7 @@ public class SimpleJdbcRepository<T, ID> implements CrudRepository<T, ID> {
*/ */
@Override @Override
public void deleteById(ID id) { public void deleteById(ID id) {
entityOperations.deleteById(id, entityInformation.getJavaType()); entityOperations.deleteById(id, entity.getType());
} }
/* /*
@ -121,7 +121,7 @@ public class SimpleJdbcRepository<T, ID> implements CrudRepository<T, ID> {
*/ */
@Override @Override
public void delete(T instance) { public void delete(T instance) {
entityOperations.delete(instance, entityInformation.getJavaType()); entityOperations.delete(instance, entity.getType());
} }
/* /*
@ -136,6 +136,6 @@ public class SimpleJdbcRepository<T, ID> implements CrudRepository<T, ID> {
@Override @Override
public void deleteAll() { public void deleteAll() {
entityOperations.deleteAll(entityInformation.getJavaType()); entityOperations.deleteAll(entity.getType());
} }
} }

96
src/test/java/org/springframework/data/jdbc/core/mapping/BasicJdbcPersistentEntityInformationUnitTests.java

@ -1,96 +0,0 @@
/*
* Copyright 2017-2018 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.jdbc.core.mapping;
import static org.assertj.core.api.Assertions.*;
import org.junit.Test;
import org.springframework.data.annotation.Id;
import org.springframework.data.domain.Persistable;
import org.springframework.data.jdbc.core.mapping.BasicJdbcPersistentEntityInformation;
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
import org.springframework.lang.Nullable;
/**
* Unit tests for {@link BasicJdbcPersistentEntityInformation}.
*
* @author Jens Schauder
* @author Oliver Gierke
*/
public class BasicJdbcPersistentEntityInformationUnitTests {
JdbcMappingContext context = new JdbcMappingContext();
private DummyEntity dummyEntity = new DummyEntity();
private PersistableDummyEntity persistableDummyEntity = new PersistableDummyEntity();
@Test // DATAJDBC-158
public void idIsBasedOnIdAnnotatedProperty() {
dummyEntity.id = 42L;
assertThat(context.getRequiredPersistentEntityInformation(DummyEntity.class).getRequiredId(dummyEntity))
.isEqualTo(42L);
}
@Test // DATAJDBC-158
public void idIsBasedOnPersistableGetId() {
assertThat( //
context.getRequiredPersistentEntityInformation(PersistableDummyEntity.class)
.getRequiredId(persistableDummyEntity) //
).isEqualTo(23L);
}
@Test // DATAJDBC-158
public void isNewIsBasedOnIdAnnotatedPropertyBeingNull() {
assertThat(context.getRequiredPersistentEntityInformation(DummyEntity.class).isNew(dummyEntity)).isTrue();
dummyEntity.id = 42L;
assertThat(context.getRequiredPersistentEntityInformation(DummyEntity.class).isNew(dummyEntity)).isFalse();
}
@Test // DATAJDBC-158
public void isNewIsBasedOnPersistableIsNew() {
persistableDummyEntity.isNewFlag = true;
assertThat(
context.getRequiredPersistentEntityInformation(PersistableDummyEntity.class).isNew(persistableDummyEntity))
.isTrue();
persistableDummyEntity.isNewFlag = false;
assertThat(
context.getRequiredPersistentEntityInformation(PersistableDummyEntity.class).isNew(persistableDummyEntity))
.isFalse();
}
private static class DummyEntity {
@Id Long id;
}
private static class PersistableDummyEntity implements Persistable<Long> {
boolean isNewFlag;
@Nullable
@Override
public Long getId() {
return 23L;
}
@Override
public boolean isNew() {
return isNewFlag;
}
}
}
Loading…
Cancel
Save