From 1b21340dce6a80d26f39f59077087bde13e409b6 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 22 Jul 2015 19:07:24 +0200 Subject: [PATCH] DATACASS-227 - Moved to PersistenPropertyAccessor API. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed all references to BeanWrapper.create(…) and rather use the PersistentPropertyAccessor API instead. Related tickets: DATACMNS-738. --- .../convert/MappingCassandraConverter.java | 108 ++++++++++-------- .../cassandra/core/CassandraTemplate.java | 25 ++-- .../MappingCassandraEntityInformation.java | 7 +- 3 files changed, 80 insertions(+), 60 deletions(-) diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/MappingCassandraConverter.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/MappingCassandraConverter.java index a6196741d..151e22190 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/MappingCassandraConverter.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/convert/MappingCassandraConverter.java @@ -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 readEntityFromRow(final CassandraPersistentEntity 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 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() { @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 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 wrapper, final Insert insert, + protected void writeInsertFromWrapper(final ConvertingPropertyAccessor accessor, final Insert insert, CassandraPersistentEntity entity) { entity.doWithProperties(new PropertyHandler() { @@ -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 wrapper, final Update update, + protected void writeUpdateFromWrapper(final ConvertingPropertyAccessor accessor, final Update update, final CassandraPersistentEntity entity) { entity.doWithProperties(new PropertyHandler() { @@ -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 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() { @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); + } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java index c13d3a7f9..ee22c5c86 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java @@ -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 idWrapper = BeanWrapper.create(id, cassandraConverter.getConversionService()); + final ConvertingPropertyAccessor idAccessor = new ConvertingPropertyAccessor(accessor, + cassandraConverter.getConversionService()); idEntity.doWithProperties(new PropertyHandler() { @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)); } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/MappingCassandraEntityInformation.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/MappingCassandraEntityInformation.java index 63e84493b..320759d40 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/MappingCassandraEntityInformation.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/support/MappingCassandraEntityInformation.java @@ -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 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 exten @SuppressWarnings("unchecked") @Override public Class getIdType() { - return (Class) (entityMetadata.getIdProperty() == null ? MapId.class : entityMetadata.getIdProperty().getType()); + return (Class) (entityMetadata.getIdProperty() == null ? MapId.class + : entityMetadata.getIdProperty().getType()); } @Override