DATACASS-227 - Moved to PersistenPropertyAccessor API.

Removed all references to BeanWrapper.create(…) and rather use the PersistentPropertyAccessor API instead.

Related tickets: DATACMNS-738.
This commit is contained in:
Oliver Gierke
2015-07-22 19:07:24 +02:00
parent 74866d6055
commit 1b21340dce
3 changed files with 80 additions and 60 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2014 the original author or authors
* Copyright 2013-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.
@@ -15,6 +15,8 @@
*/
package org.springframework.data.cassandra.convert;
import static org.springframework.data.cassandra.repository.support.BasicMapId.*;
import java.io.Serializable;
import java.util.Map;
@@ -32,9 +34,10 @@ import org.springframework.data.cassandra.mapping.CassandraPersistentProperty;
import org.springframework.data.cassandra.repository.MapId;
import org.springframework.data.cassandra.repository.MapIdentifiable;
import org.springframework.data.convert.EntityInstantiator;
import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.mapping.PropertyHandler;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.BeanWrapper;
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator;
import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.mapping.model.SpELContext;
@@ -49,8 +52,6 @@ import com.datastax.driver.core.querybuilder.Insert;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Update;
import static org.springframework.data.cassandra.repository.support.BasicMapId.id;
/**
* {@link CassandraConverter} that uses a {@link MappingContext} to do sophisticated mapping of domain objects to
* {@link Row}.
@@ -59,8 +60,8 @@ import static org.springframework.data.cassandra.repository.support.BasicMapId.i
* @author Matthew T. Adams
* @author Oliver Gierke
*/
public class MappingCassandraConverter extends AbstractCassandraConverter implements CassandraConverter,
ApplicationContextAware, BeanClassLoaderAware {
public class MappingCassandraConverter extends AbstractCassandraConverter
implements CassandraConverter, ApplicationContextAware, BeanClassLoaderAware {
protected final Logger log = LoggerFactory.getLogger(getClass());
@@ -123,7 +124,6 @@ public class MappingCassandraConverter extends AbstractCassandraConverter implem
protected <S> S readEntityFromRow(final CassandraPersistentEntity<S> entity, final Row row) {
DefaultSpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(row, spELContext);
BasicCassandraRowValueProvider rowValueProvider = new BasicCassandraRowValueProvider(row, evaluator);
CassandraPersistentEntityParameterValueProvider parameterProvider = new CassandraPersistentEntityParameterValueProvider(
@@ -132,28 +132,26 @@ public class MappingCassandraConverter extends AbstractCassandraConverter implem
EntityInstantiator instantiator = instantiators.getInstantiatorFor(entity);
S instance = instantiator.createInstance(entity, parameterProvider);
BeanWrapper<S> wrapper = BeanWrapper.create(instance, conversionService);
readPropertiesFromRow(entity, rowValueProvider, getConvertingAccessor(instance, entity));
readPropertiesFromRow(entity, rowValueProvider, wrapper);
return wrapper.getBean();
return instance;
}
protected void readPropertiesFromRow(final CassandraPersistentEntity<?> entity,
final BasicCassandraRowValueProvider row, final BeanWrapper<?> wrapper) {
final BasicCassandraRowValueProvider row, final PersistentPropertyAccessor accessor) {
entity.doWithProperties(new PropertyHandler<CassandraPersistentProperty>() {
@Override
public void doWithPersistentProperty(CassandraPersistentProperty prop) {
MappingCassandraConverter.this.readPropertyFromRow(entity, prop, row, wrapper);
MappingCassandraConverter.this.readPropertyFromRow(entity, prop, row, accessor);
}
});
}
protected void readPropertyFromRow(final CassandraPersistentEntity<?> entity, final CassandraPersistentProperty prop,
final BasicCassandraRowValueProvider row, final BeanWrapper<?> wrapper) {
final BasicCassandraRowValueProvider row, final PersistentPropertyAccessor accessor) {
if (entity.isConstructorArgument(prop)) { // skip 'cause prop was set in ctor
return;
@@ -163,19 +161,19 @@ public class MappingCassandraConverter extends AbstractCassandraConverter implem
// get the key
CassandraPersistentProperty keyProperty = entity.getIdProperty();
Object key = wrapper.getProperty(keyProperty);
CassandraPersistentEntity<?> keyEntity = keyProperty.getCompositePrimaryKeyEntity();
Object key = accessor.getProperty(keyProperty);
if (key == null) {
key = instantiatePrimaryKey(keyProperty.getCompositePrimaryKeyEntity(), keyProperty, row);
key = instantiatePrimaryKey(keyEntity, keyProperty, row);
}
// wrap the key
BeanWrapper<Object> keyWrapper = BeanWrapper.create(key, conversionService);
// now recurse on using the key this time
readPropertiesFromRow(prop.getCompositePrimaryKeyEntity(), row, keyWrapper);
readPropertiesFromRow(prop.getCompositePrimaryKeyEntity(), row, getConvertingAccessor(key, keyEntity));
// now that the key's properties have been populated, set the key property on the entity
wrapper.setProperty(keyProperty, keyWrapper.getBean());
accessor.setProperty(keyProperty, key);
return;
}
@@ -184,7 +182,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter implem
}
Object obj = row.getPropertyValue(prop);
wrapper.setProperty(prop, obj);
accessor.setProperty(prop, obj);
}
protected Object instantiatePrimaryKey(CassandraPersistentEntity<?> entity, CassandraPersistentProperty keyProperty,
@@ -192,8 +190,8 @@ public class MappingCassandraConverter extends AbstractCassandraConverter implem
EntityInstantiator instantiator = instantiators.getInstantiatorFor(entity);
return instantiator.createInstance(entity, new CassandraPersistentEntityParameterValueProvider(entity,
propertyProvider, null));
return instantiator.createInstance(entity,
new CassandraPersistentEntityParameterValueProvider(entity, propertyProvider, null));
}
@Override
@@ -230,10 +228,10 @@ public class MappingCassandraConverter extends AbstractCassandraConverter implem
}
protected void writeInsertFromObject(final Object object, final Insert insert, CassandraPersistentEntity<?> entity) {
writeInsertFromWrapper(BeanWrapper.create(object, conversionService), insert, entity);
writeInsertFromWrapper(getConvertingAccessor(object, entity), insert, entity);
}
protected void writeInsertFromWrapper(final BeanWrapper<Object> wrapper, final Insert insert,
protected void writeInsertFromWrapper(final ConvertingPropertyAccessor accessor, final Insert insert,
CassandraPersistentEntity<?> entity) {
entity.doWithProperties(new PropertyHandler<CassandraPersistentProperty>() {
@@ -241,14 +239,15 @@ public class MappingCassandraConverter extends AbstractCassandraConverter implem
@Override
public void doWithPersistentProperty(CassandraPersistentProperty prop) {
Object value = wrapper.getProperty(prop, prop.getType());
Object value = accessor.getProperty(prop, prop.getType());
log.debug("prop.type -> " + prop.getType().getName());
log.debug("prop.value -> " + value);
if (prop.isCompositePrimaryKey()) {
log.debug("prop is a compositeKey");
writeInsertFromWrapper(BeanWrapper.create(value, conversionService), insert,
writeInsertFromWrapper(getConvertingAccessor(value, prop.getCompositePrimaryKeyEntity()), insert,
prop.getCompositePrimaryKeyEntity());
return;
}
@@ -262,10 +261,10 @@ public class MappingCassandraConverter extends AbstractCassandraConverter implem
}
protected void writeUpdateFromObject(final Object object, final Update update, CassandraPersistentEntity<?> entity) {
writeUpdateFromWrapper(BeanWrapper.create(object, conversionService), update, entity);
writeUpdateFromWrapper(getConvertingAccessor(object, entity), update, entity);
}
protected void writeUpdateFromWrapper(final BeanWrapper<Object> wrapper, final Update update,
protected void writeUpdateFromWrapper(final ConvertingPropertyAccessor accessor, final Update update,
final CassandraPersistentEntity<?> entity) {
entity.doWithProperties(new PropertyHandler<CassandraPersistentProperty>() {
@@ -273,11 +272,11 @@ public class MappingCassandraConverter extends AbstractCassandraConverter implem
@Override
public void doWithPersistentProperty(CassandraPersistentProperty prop) {
Object value = wrapper.getProperty(prop, prop.getType());
Object value = accessor.getProperty(prop, prop.getType());
if (prop.isCompositePrimaryKey()) {
writeUpdateFromWrapper(BeanWrapper.create(value, conversionService), update,
prop.getCompositePrimaryKeyEntity());
CassandraPersistentEntity<?> keyEntity = prop.getCompositePrimaryKeyEntity();
writeUpdateFromWrapper(getConvertingAccessor(value, keyEntity), update, keyEntity);
return;
}
@@ -292,11 +291,12 @@ public class MappingCassandraConverter extends AbstractCassandraConverter implem
});
}
protected void writeDeleteWhereFromObject(final Object object, final Where where, CassandraPersistentEntity<?> entity) {
writeDeleteWhereFromWrapper(BeanWrapper.create(object, conversionService), where, entity);
protected void writeDeleteWhereFromObject(final Object object, final Where where,
CassandraPersistentEntity<?> entity) {
writeDeleteWhereFromWrapper(getConvertingAccessor(object, entity), where, entity);
}
protected void writeDeleteWhereFromWrapper(final BeanWrapper<Object> wrapper, final Where where,
protected void writeDeleteWhereFromWrapper(final PersistentPropertyAccessor accessor, final Where where,
CassandraPersistentEntity<?> entity) {
// if the entity itself if a composite primary key, then we've recursed, so just add columns & return
@@ -304,16 +304,16 @@ public class MappingCassandraConverter extends AbstractCassandraConverter implem
entity.doWithProperties(new PropertyHandler<CassandraPersistentProperty>() {
@Override
public void doWithPersistentProperty(CassandraPersistentProperty p) {
where.and(QueryBuilder.eq(p.getColumnName().toCql(), wrapper.getProperty(p)));
where.and(QueryBuilder.eq(p.getColumnName().toCql(), accessor.getProperty(p)));
}
});
return;
}
// else, wrapper is an entity with an id
Object id = getId(wrapper, entity);
Object id = getId(accessor, entity);
if (id == null) {
String msg = String.format("no id value found in object {}", wrapper.getBean());
String msg = String.format("no id value found in object {}", accessor.getBean());
log.error(msg);
throw new IllegalArgumentException(msg);
}
@@ -327,10 +327,14 @@ public class MappingCassandraConverter extends AbstractCassandraConverter implem
}
CassandraPersistentProperty idProperty = entity.getIdProperty();
if (idProperty != null) {
if (idProperty.isCompositePrimaryKey()) {
writeDeleteWhereFromWrapper(BeanWrapper.create(id, conversionService), where,
CassandraPersistentEntity<?> idEntity = idProperty.getCompositePrimaryKeyEntity();
writeDeleteWhereFromWrapper(getConvertingAccessor(id, idEntity), where,
idProperty.getCompositePrimaryKeyEntity());
return;
}
@@ -345,14 +349,13 @@ public class MappingCassandraConverter extends AbstractCassandraConverter implem
Assert.notNull(object);
final BeanWrapper<?> wrapper = object instanceof BeanWrapper ? (BeanWrapper<?>) object : BeanWrapper.create(object,
conversionService);
final ConvertingPropertyAccessor wrapper = getConvertingAccessor(object, entity);
object = wrapper.getBean();
if (!entity.getType().isAssignableFrom(object.getClass())) {
throw new IllegalArgumentException(String.format(
"given instance of type [%s] is not of compatible expected type [%s]", object.getClass().getName(), entity
.getType().getName()));
throw new IllegalArgumentException(
String.format("given instance of type [%s] is not of compatible expected type [%s]",
object.getClass().getName(), entity.getType().getName()));
}
if (object instanceof MapIdentifiable) {
@@ -400,4 +403,19 @@ public class MappingCassandraConverter extends AbstractCassandraConverter implem
public CassandraMappingContext getMappingContext() {
return mappingContext;
}
/**
* Creates a new {@link ConvertingPropertyAccessor} for the given source and entity.
*
* @param source must not be {@literal null}.
* @param entity must not be {@literal null}.
* @return
*/
private ConvertingPropertyAccessor getConvertingAccessor(Object source, CassandraPersistentEntity<?> entity) {
PersistentPropertyAccessor accessor = source instanceof PersistentPropertyAccessor
? (PersistentPropertyAccessor) source : entity.getPropertyAccessor(source);
return new ConvertingPropertyAccessor(accessor, conversionService);
}
}

View File

@@ -22,9 +22,9 @@ import java.util.List;
import java.util.Map;
import org.springframework.cassandra.core.AsynchronousQueryListener;
import org.springframework.cassandra.core.Cancellable;
import org.springframework.cassandra.core.CqlOperations;
import org.springframework.cassandra.core.CqlTemplate;
import org.springframework.cassandra.core.Cancellable;
import org.springframework.cassandra.core.QueryForObjectListener;
import org.springframework.cassandra.core.QueryOptions;
import org.springframework.cassandra.core.SessionCallback;
@@ -39,16 +39,15 @@ import org.springframework.data.cassandra.mapping.CassandraMappingContext;
import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
import org.springframework.data.cassandra.mapping.CassandraPersistentProperty;
import org.springframework.data.convert.EntityWriter;
import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.mapping.PropertyHandler;
import org.springframework.data.mapping.model.BeanWrapper;
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
import org.springframework.util.Assert;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.ResultSetFuture;
import com.datastax.driver.core.Row;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.SimpleStatement;
import com.datastax.driver.core.Statement;
import com.datastax.driver.core.querybuilder.Batch;
import com.datastax.driver.core.querybuilder.Clause;
import com.datastax.driver.core.querybuilder.Delete;
@@ -335,9 +334,9 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
CassandraPersistentEntity<?> entity = mappingContext.getPersistentEntity(type);
if (entity.getIdProperty().isCompositePrimaryKey()) {
throw new IllegalArgumentException(String.format(
"entity class [%s] uses a composite primary key class [%s] which this method can't support", type.getName(),
entity.getIdProperty().getCompositePrimaryKeyEntity().getType().getName()));
throw new IllegalArgumentException(
String.format("entity class [%s] uses a composite primary key class [%s] which this method can't support",
type.getName(), entity.getIdProperty().getCompositePrimaryKeyEntity().getType().getName()));
}
Select select = QueryBuilder.select().all().from(entity.getTableName().toCql());
@@ -390,16 +389,18 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
if (idProperty.isCompositePrimaryKey()) {
CassandraPersistentEntity<?> idEntity = idProperty.getCompositePrimaryKeyEntity();
PersistentPropertyAccessor accessor = idEntity.getPropertyAccessor(id);
final BeanWrapper<Object> idWrapper = BeanWrapper.create(id, cassandraConverter.getConversionService());
final ConvertingPropertyAccessor idAccessor = new ConvertingPropertyAccessor(accessor,
cassandraConverter.getConversionService());
idEntity.doWithProperties(new PropertyHandler<CassandraPersistentProperty>() {
@Override
public void doWithPersistentProperty(CassandraPersistentProperty p) {
clauseCallback.doWithClause(QueryBuilder.eq(p.getColumnName().toCql(),
idWrapper.getProperty(p, p.getActualType())));
clauseCallback
.doWithClause(QueryBuilder.eq(p.getColumnName().toCql(), idAccessor.getProperty(p, p.getActualType())));
}
});
@@ -1034,7 +1035,7 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
if (query instanceof Select) {
return queryAsynchronously((Select) query, aql);
}
throw new IllegalArgumentException(String.format("Expected type String or Select; got type [%s] with value [%s]",
query.getClass(), query));
throw new IllegalArgumentException(
String.format("Expected type String or Select; got type [%s] with value [%s]", query.getClass(), query));
}
}

View File

@@ -23,7 +23,6 @@ import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
import org.springframework.data.cassandra.mapping.CassandraPersistentProperty;
import org.springframework.data.cassandra.repository.MapId;
import org.springframework.data.cassandra.repository.query.CassandraEntityInformation;
import org.springframework.data.mapping.model.BeanWrapper;
import org.springframework.data.repository.core.support.AbstractEntityInformation;
import org.springframework.util.Assert;
@@ -61,8 +60,9 @@ public class MappingCassandraEntityInformation<T, ID extends Serializable> exten
Assert.notNull(entity);
CassandraPersistentProperty idProperty = entityMetadata.getIdProperty();
if (idProperty != null) {
return (ID) BeanWrapper.create(entity, null).getProperty(idProperty);
return (ID) entityMetadata.getIdentifierAccessor(entity).getIdentifier();
}
return (ID) converter.getId(entity, entityMetadata);
@@ -71,7 +71,8 @@ public class MappingCassandraEntityInformation<T, ID extends Serializable> exten
@SuppressWarnings("unchecked")
@Override
public Class<ID> getIdType() {
return (Class<ID>) (entityMetadata.getIdProperty() == null ? MapId.class : entityMetadata.getIdProperty().getType());
return (Class<ID>) (entityMetadata.getIdProperty() == null ? MapId.class
: entityMetadata.getIdProperty().getType());
}
@Override