cassandra 数据到Java对象的映射绑定

时间:2021-06-28 21:41:23

类似Hibernate和MyBatis的关系映射,自动帮你将查询数据或是修改的参数进行数据映射和绑定。

支持查询后返回数据ResultSet到Java对象的映射,支持修改、删除、查询之前参数的绑定。

在JavaEntity的命名方式不合规范情况下,可以用Map进行绑定映射。

这种做法可以适用于JDBC的sql result到Java Entity的映射绑定,但需要修改少量的代码。

代码如下:

 package com.cnblogs.hoojo.cassar.utils;

 import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.InetAddress;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID; import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils; import com.datastax.driver.core.BoundStatement;
import com.datastax.driver.core.ColumnDefinitions;
import com.datastax.driver.core.ColumnDefinitions.Definition;
import com.datastax.driver.core.DataType;
import com.datastax.driver.core.PreparedStatement;
import com.datastax.driver.core.Row;
import com.google.common.collect.Maps; /**
* <b>function:</b> cassandra 到 JavaEntity 映射转换
* @author hoojo
* @createDate 2017-1-19 下午6:20:47
* @file RowMapperUtils.java
* @package com.cnblogs.hoojo.cassar.utils
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
public class RowMapperUtils { private static final Logger logger = LoggerFactory.getLogger(RowMapperUtils.class); public static boolean DEBUG = false;
public static String LOG_LEVEL = "TRACE"; /**
* <b>function:</b> 将查询的Row转换到target 对象中返回
* @author hoojo
* @createDate 2017-1-20 下午5:36:20
* @param target 返回Java对象
* @param row {@link Row}
* @return 返回Java对象
*/
public static <T> T conversion(T target, Row row) {
return conversion(target, row, null);
} /**
* <b>function:</b> 将查询的Row转换到target 对象中返回,row对象存在List、Set集合类型情况
* @author hoojo
* @createDate 2017-1-20 下午5:36:20
* @param target 返回Java对象
* @param row {@link Row}
* @param genericClass List中存储值 的class类型
* @return 返回Java对象
*/
public static <T> T conversion(T target, Row row, Map<String, Class<?>> genericClass) {
return conversion(target, row, genericClass, null);
} /**
* <b>function:</b> 将查询的Row转换到target 对象中返回,row对象存在List、Set、Map集合类型情况
* @author hoojo
* @createDate 2017-1-20 下午5:36:20
* @param target 返回Java对象
* @param row {@link Row}
* @param valClass List中存储值 的class类型
* @param keyClass List中存储Key 的class类型
* @return 返回Java对象
*/
@SuppressWarnings("unchecked")
public static <T> T conversion(T target, Row row, Map<String, Class<?>> valClass, Map<String, Class<?>> keyClass) {
Class<T> clazz = (Class<T>) target.getClass();
return conversion(clazz, row, valClass, keyClass);
} /**
* <b>function:</b> 将查询的Row转换到clazz实例对象返回,row对象存在List、Set集合类型情况
* @author hoojo
* @createDate 2017-1-20 下午5:36:20
* @param target 返回Java对象
* @param row {@link Row}
* @return 返回Java对象
*/
public static <T> T conversion(Class<T> clazz, Row row) {
return conversion(clazz, row, null);
} /**
* <b>function:</b> 将查询的Row转换到clazz实例对象返回,row对象存在List、Set集合类型情况
* @author hoojo
* @createDate 2017-1-20 下午5:36:20
* @param target 返回Java对象
* @param row {@link Row}
* @param genericClass List中存储值 的class类型
* @return 返回Java对象
*/
public static <T> T conversion(Class<T> clazz, Row row, Map<String, Class<?>> genericClass) {
return conversion(clazz, row, genericClass, null);
} public static <T> T transform(T target, Row row, Map<String, Class<?>> valClass, Map<String, Class<?>> keyClass) { ColumnDefinitions cols = row.getColumnDefinitions();
Iterator<Definition> definitionIter = null; definitionIter = cols.iterator();
while (definitionIter.hasNext()) {
Definition definition = definitionIter.next(); DataType type = definition.getType();
String columnName = definition.getName();
debug(String.format("列名:%s,列类型:%s", columnName, type)); Object value = getData(row, type, columnName, valClass, keyClass);
debug(String.format("列名:%s,取值:%s", columnName, value)); String camelName = camelName(columnName);
try {
PropertyUtils.setProperty(target, camelName, value);
} catch (IllegalAccessException | InvocationTargetException e) {
log("设置{}值发生异常:", camelName, e);
} catch (NoSuchMethodException ex) { if (camelName.equals(camelName.toLowerCase())) {
log("This Class '{}' set '{}' method notfound.", new Object[] { target.getClass().getSimpleName(), camelName } );
} else { try {
PropertyUtils.setProperty(target, camelName.toLowerCase(), value);
} catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException e) {
log("设置{}值发生异常:", camelName, e);
} catch (NoSuchMethodException e) {
log("This Class '{}' set '{}' or set '{}' method notfound.", new Object[] { target.getClass().getSimpleName(), camelName, camelName.toLowerCase() } );
}
}
}
}
debug("target: " + target); return target;
} /**
* <b>function:</b> 将查询的Row转换到clazz实例对象返回,row对象存在List、Set、Map集合类型情况
* @author hoojo
* @createDate 2017-1-20 下午5:36:20
* @param target 返回Java对象
* @param row {@link Row}
* @param valClass List中存储值 的class类型
* @param keyClass List中存储Key 的class类型
* @return 返回Java对象
*/
public static <T> T conversion(Class<T> clazz, Row row, Map<String, Class<?>> valClass, Map<String, Class<?>> keyClass) { T target = BeanUtils.instantiate(clazz);
Map<String, PropertyDescriptor> mappedFields = getMappedFields(target.getClass()); ColumnDefinitions cols = row.getColumnDefinitions();
Iterator<Definition> definitionIter = cols.iterator();
while (definitionIter.hasNext()) {
Definition definition = definitionIter.next(); DataType type = definition.getType();
String columnName = definition.getName().toLowerCase();
debug(String.format("列名:%s,列类型:%s", columnName, type)); Object value = getData(row, type, columnName, valClass, keyClass);
debug(String.format("列名:%s,取值:%s", columnName, value)); if (mappedFields.containsKey(columnName)) {
try {
mappedFields.get(columnName).getWriteMethod().invoke(target, value);
} catch (IllegalAccessException | InvocationTargetException e) {
log("设置{}值发生异常:{}", columnName, e);
} catch (Exception e) {
log("设置{}值发生异常:{}", columnName, e.getMessage());
}
} else {
log("The target Class '{}' in Column '{}' setter method notFound", clazz.getSimpleName(), columnName);
}
}
debug("target: " + target); return target;
} /**
* <b>function:</b> 将查询的Row转换到target Map对象中返回
* @author hoojo
* @createDate 2017-1-20 下午5:36:20
* @param target 返回Map对象
* @param row {@link Row}
* @return 返回Map对象
*/
public static <T> Map<String, T> conversion(Map<String, T> target, Row row) {
return conversion(target, row, null);
} /**
* <b>function:</b> 将查询的Row转换到target Map对象中返回,row对象存在List、Set集合类型情况
* @author hoojo
* @createDate 2017-1-20 下午5:36:20
* @param target 返回Map对象
* @param row {@link Row}
* @param genericClass List中存储值 的class类型
* @return 返回Map对象
*/
public static <T> Map<String, T> conversion(Map<String, T> target, Row row, Map<String, Class<?>> genericClass) {
return conversion(target, row, genericClass, null);
} /**
* <b>function:</b> 将查询的Row转换到target Map对象中返回,row对象存在Map集合类型情况
* @author hoojo
* @createDate 2017-1-20 下午5:36:20
* @param target 返回Map对象
* @param row {@link Row}
* @param valClass MAP、List中存储值 的class类型
* @param keyClass MAP Key 的class类型
* @return 返回Map对象
*/
@SuppressWarnings("unchecked")
public static <T> Map<String, T> conversion(Map<String, T> target, Row row, Map<String, Class<?>> valClass, Map<String, Class<?>> keyClass) { if (target == null) {
target = Maps.newHashMap();
} ColumnDefinitions cols = row.getColumnDefinitions();
Iterator<Definition> definitionIter = cols.iterator();
while (definitionIter.hasNext()) {
Definition definition = definitionIter.next(); DataType type = definition.getType();
String columnName = definition.getName().toLowerCase();
debug(String.format("列名:%s,列类型:%s", columnName, type)); Object value = getData(row, type, columnName, valClass, keyClass);
debug(String.format("列名:%s,取值:%s", columnName, value)); String camelName = camelName(columnName);
if (value != null) {
target.put(camelName, (T) value);
} else {
target.put(camelName, null);
}
}
debug("target: " + target); return target;
} /**
* <b>function:</b> 为cql PreparedStatement对象自动绑定参数值
* @author hoojo
* @createDate 2017-1-20 下午5:33:18
* @param statement PreparedStatement
* @param params 参数实体
* @return BoundStatement 已绑定值
*/
public static <T> BoundStatement bind(PreparedStatement statement, Map<String, T> bindParam) { BoundStatement boundStatement = null; Map<String, T> params = Maps.newHashMap(bindParam); Set<String> keys = bindParam.keySet();
Iterator<String> iter = keys.iterator();
while (iter.hasNext()) {
String key = iter.next();
T val = bindParam.get(key);
params.put(key, val); if (!bindParam.containsKey(key.toLowerCase())) {
params.put(key.toLowerCase(), val);
} key = underscoreName(key).toLowerCase();
if (!bindParam.containsKey(key)) {
params.put(key, val);
}
} Map<String, Object> bindParams = Maps.newLinkedHashMap(); ColumnDefinitions cols = statement.getVariables();
Iterator<Definition> definitionIter = cols.iterator();
while (definitionIter.hasNext()) {
Definition definition = definitionIter.next(); DataType type = definition.getType();
String columnName = definition.getName().toLowerCase();
debug(String.format("参数列名:%s,参数列类型:%s", columnName, type)); Object param = null;
if (params.containsKey(columnName)) {
param = params.get(columnName);
} else {
log("The target Map does not exist param '{}' value.", columnName);
}
debug(String.format("参数列名:%s,参数取值:%s", columnName, param)); bindParams.put(columnName, param);
} debugCQL(statement.getQueryString(), bindParams); boundStatement = statement.bind(bindParams.values().toArray());
return boundStatement;
} /**
* <b>function:</b> 为cql PreparedStatement对象自动绑定参数值
* @author hoojo
* @createDate 2017-1-20 下午5:33:18
* @param statement PreparedStatement
* @param bindEntity 参数实体
* @return BoundStatement 已绑定值
*/
public static <T> BoundStatement bind(PreparedStatement statement, T bindEntity) { BoundStatement boundStatement = null; Map<String, Object> params = Maps.newLinkedHashMap();
Map<String, PropertyDescriptor> mappedFields = getMappedFields(bindEntity.getClass()); ColumnDefinitions cols = statement.getVariables();
Iterator<Definition> definitionIter = cols.iterator();
while (definitionIter.hasNext()) {
Definition definition = definitionIter.next(); DataType type = definition.getType();
String columnName = definition.getName().toLowerCase();
debug(String.format("参数列名:%s,参数列类型:%s", columnName, type)); Object param = null;
if (mappedFields.containsKey(columnName)) {
try {
param = mappedFields.get(columnName).getReadMethod().invoke(bindEntity);
} catch (IllegalAccessException | InvocationTargetException e) {
log("设置{}值发生异常:", columnName, e);
}
} else {
log("The target Class '{}' in Column '{}' getter method notFound", bindEntity.getClass().getSimpleName(), columnName);
}
debug(String.format("参数列名:%s,参数取值:%s", columnName, param)); params.put(columnName, param);
} debugCQL(statement.getQueryString(), params); boundStatement = statement.bind(params.values().toArray());
return boundStatement;
} /**
* <b>function:</b> 调试cql语句,将占位符替换参数值
* @author hoojo
* @createDate 2017-1-20 下午5:30:48
* @param queryString cql语句
* @param params 参数
*/
private static void debugCQL(String queryString, Map<String, Object> params) { if (DEBUG) {
Set<String> keys = params.keySet(); Object[] keyArrays = keys.toArray();
for (int i = 0; i < keys.size(); i++) { queryString = StringUtils.replaceOnce(queryString, "?", MapUtils.getString(params, keyArrays[i], "NULL"));
}
logger.info("debug cql: {}", queryString);
}
} private static void debug(String log) { if (DEBUG) {
logger.info(log);
}
} private static void log(String msg, Object... args) { if ("INFO".equalsIgnoreCase(LOG_LEVEL)) {
logger.info(msg, args);
} else if ("WARN".equalsIgnoreCase(LOG_LEVEL)) {
logger.warn(msg, args);
} else if ("DEBUG".equalsIgnoreCase(LOG_LEVEL)) {
logger.debug(msg, args);
} else if ("TRACE".equalsIgnoreCase(LOG_LEVEL)) {
logger.trace(msg, args);
} else if ("ERROR".equalsIgnoreCase(LOG_LEVEL)) {
logger.error(msg, args);
}
} /**
* <b>function:</b> 获取对象的setter方法,并返回下划线命名和全小写命名的Map集合
* @author hoojo
* @createDate 2017-1-20 下午5:31:21
* @param clazz 目标对象class
* @return Map
*/
private static Map<String, PropertyDescriptor> getMappedFields(Class<?> clazz) {
Map<String, PropertyDescriptor> mappedFields = new HashMap<String, PropertyDescriptor>(); PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(clazz);
for (PropertyDescriptor pd : pds) {
if (pd.getWriteMethod() != null) { //setUserId->userid,user_id;
mappedFields.put(pd.getName().toLowerCase(), pd); String underscoreName = underscoreName(pd.getName());
if (!pd.getName().toUpperCase().equals(underscoreName)) {
mappedFields.put(underscoreName.toLowerCase(), pd);
}
}
} return mappedFields;
} /**
* <b>function:</b> 获取cql 的值
* @author hoojo
* @createDate 2017-1-20 下午5:26:24
* @param row {@link Row}
* @param type 列类型
* @param columnName 列名
* @param valClass MAP、List中存储值 的class类型
* @param keyClass MAP Key 的class类型
* @return
*/
private static Object getData(Row row, DataType type, String columnName, Map<String, Class<?>> valClass, Map<String, Class<?>> keyClass) { Object value = null; try { if (type == DataType.bigint()) {
value = row.getLong(columnName);
} else if (type == DataType.cboolean()) {
value = row.getBool(columnName);
} else if (type == DataType.blob()) {
value = row.getBytes(columnName);
} else if (type == DataType.timestamp()) {
value = row.getDate(columnName);
} else if (type == DataType.decimal()) {
value = row.getDecimal(columnName);
} else if (type == DataType.cfloat()) {
value = row.getFloat(columnName);
} else if (type == DataType.inet()) {
value = row.getInet(columnName);
} else if (type == DataType.cint()) {
value = row.getInt(columnName);
} else if (type.isCollection() && type.asJavaClass() == List.class) {
value = getCollectionData(row, type, columnName, valClass);
} else if (type.isCollection() && type.asJavaClass() == Set.class) {
value = getCollectionData(row, type, columnName, valClass);
} else if (type.isCollection() && type.asJavaClass() == Map.class) {
value = getCollectionData(row, type, columnName, valClass, keyClass);
} else if (type == DataType.varchar()) {
value = row.getString(columnName);
} else if (type == DataType.uuid() || type == DataType.timeuuid()) {
value = row.getUUID(columnName);
} else if (type == DataType.varint()) {
value = row.getVarint(columnName);
} else if (type == DataType.cdouble()) {
value = row.getDouble(columnName);
} else if (type == DataType.text()) {
value = row.getString(columnName);
} } catch (Exception e) {
log("获取{}值发生异常:", columnName, e);
} if (value == null) {
log("Column '{}' Type({}) get cassandra data is NULL.", columnName, type);
} return value;
} /**
* <b>function:</b> 获取cql List集合泛型的值
* @author hoojo
* @createDate 2017-1-20 下午5:26:24
* @param row {@link Row}
* @param type 列类型
* @param columnName 列名
* @param valClass List Value 的class类型
* @return
*/
private static Object getCollectionData(Row row, DataType type, String columnName, Map<String, Class<?>> valClass) { Object value = null; Class<?> ofValueType = valClass != null ? valClass.get(columnName) : null;
List<DataType> typeArguments = type.getTypeArguments();
if (ofValueType == null) {
log("Column TypeArguments convter Error, CQL Type: '{} {}' --> '{} {}(NULL)'", new Object[] { columnName, type, columnName, type.getName() });
} else if (ofValueType != typeArguments.get(0).asJavaClass()) {
log("Column TypeArguments convter Error, CQL Type: '{} {}({})' --> '{} {}({})'", new Object[] { columnName, type, typeArguments.get(0).asJavaClass(), columnName, valueOf(type.asJavaClass(), ofValueType), ofValueType });
} else if (type.asJavaClass() == List.class) {
value = row.getList(columnName, ofValueType);
} else if (type.asJavaClass() == Set.class) {
value = row.getSet(columnName, ofValueType);
} return value;
} /**
* <b>function:</b> 获取cql MAP集合泛型的值
* @author hoojo
* @createDate 2017-1-20 下午5:26:24
* @param row {@link Row}
* @param type 列类型
* @param columnName 列名
* @param valClass MAP Value 的class类型
* @param keyClass MAP Key 的class类型
* @return
*/
private static Object getCollectionData(Row row, DataType type, String columnName, Map<String, Class<?>> valClass, Map<String, Class<?>> keyClass) { Object value = null; Class<?> ofKeyType = keyClass != null ? keyClass.get(columnName) : null;
Class<?> ofValueType = valClass != null ? valClass.get(columnName) : null; List<DataType> typeArguments = type.getTypeArguments();
if (ofValueType == null && ofKeyType == null) {
log("Column TypeArguments convter Error, CQL Type: '{} {}' --> '{} {}<NULL, NULL>'", new Object[] { columnName, type, columnName, type.getName() });
} else if (ofValueType == null) {
log("Column TypeArguments convter Error, CQL Type: '{} {}' --> '{} {}<{}, NULL>'", new Object[] { columnName, type, columnName, type.getName(), valueOf(ofKeyType) });
} else if (ofKeyType == null) {
log("Column TypeArguments convter Error, CQL Type: '{} {}' --> '{} {}<NULL, {}>'", new Object[] { columnName, type, columnName, type.getName(), valueOf(ofValueType) });
} else if (ofKeyType != typeArguments.get(0).asJavaClass() || ofValueType != typeArguments.get(1).asJavaClass()) {
log("Column TypeArguments convter Error, CQL Type: '{} {} (<{}, {}>)' --> '{} {}(<{}, {}>)'", new Object[] { columnName, type, typeArguments.get(0).asJavaClass(), typeArguments.get(1).asJavaClass(), columnName, valueOf(Map.class, ofValueType, ofKeyType), ofKeyType, ofValueType });
} else {
value = row.getMap(columnName, ofKeyType, ofValueType);
} return value;
} /**
* <b>function:</b> 转换为下划线命名方式
* @author hoojo
* @createDate 2017-1-20 下午5:24:50
*/
public static String underscoreName(String name) {
StringBuilder result = new StringBuilder();
if (name != null && name.length() > 0) {
// 将第一个字符处理成大写
result.append(name.substring(0, 1).toUpperCase());
// 循环处理其余字符
for (int i = 1; i < name.length(); i++) {
String s = name.substring(i, i + 1);
// 在大写字母前添加下划线
if (s.equals(s.toUpperCase()) && !Character.isDigit(s.charAt(0))) {
result.append("_");
}
// 其他字符直接转成大写
result.append(s.toUpperCase());
}
}
return result.toString();
} /**
* <b>function:</b> 驼峰式命名方式
* @author hoojo
* @createDate 2017-1-20 下午5:25:09
*/
public static String camelName(String name) {
StringBuilder sb = new StringBuilder();
if (!name.contains("_")) {
// 不含下划线,仅将首字母小写
return name.substring(0, 1).toLowerCase() + name.substring(1);
}
// 用下划线将原始字符串分割
String camels[] = name.split("_");
for (String camel : camels) {
// 跳过原始字符串中开头、结尾的下换线或双重下划线
if (camel.isEmpty()) {
continue;
}
// 处理真正的驼峰片段
if (sb.length() == 0) {
// 第一个驼峰片段,全部字母都小写
sb.append(camel.toLowerCase());
} else {
// 其他的驼峰片段,首字母大写
sb.append(camel.substring(0, 1).toUpperCase());
sb.append(camel.substring(1).toLowerCase());
}
}
return sb.toString();
} /**
* <b>function:</b> java class转换到cql类型
* @author hoojo
* @createDate 2017-1-20 下午5:24:09
* @param clazz Class
* @return {@link DataType}
*/
private static DataType valueOf(Class<?> clazz) { if (clazz == null) {
return DataType.custom("NULL");
}
if (clazz == long.class || clazz == Long.class) {
return DataType.bigint();
}
if (clazz == boolean.class || clazz == Boolean.class) {
return DataType.cboolean();
}
if (clazz == Byte.class || clazz == byte.class) {
return DataType.blob();
}
if (clazz == Date.class || clazz == Timestamp.class) {
return DataType.timestamp();
}
if (clazz == BigDecimal.class) {
return DataType.decimal();
}
if (clazz == float.class || clazz == Float.class) {
return DataType.cfloat();
}
if (clazz == InetAddress.class) {
return DataType.inet();
}
if (clazz == int.class || clazz == Integer.class) {
return DataType.cint();
}
if (clazz == String.class) {
return DataType.varchar();// text();
}
if (clazz == UUID.class) {
return DataType.uuid(); // timeuuid();
}
if (clazz == BigInteger.class) {
return DataType.varint();
} log("Class '{}' unknow DataType in cassandra.", clazz); return DataType.custom("unknow");
} /**
* <b>function:</b> 转换集合list、set到cql类型
* @author hoojo
* @createDate 2017-1-20 下午5:22:43
* @param clazz java class
* @param valueClass 集合值存储类型class
* @param keyClass 集合键存储类型class
* @return DataType
*/
public static DataType valueOf(Class<?> clazz, Class<?> valueClass, Class<?> keyClass) { if (clazz == List.class) {
return DataType.list(valueOf(valueClass));
}
if (clazz == Set.class) {
return DataType.set(valueOf(valueClass));
}
if (clazz == Map.class) {
return DataType.map(valueOf(keyClass), valueOf(valueClass));
} log("Class '{}' unknow DataType in cassandra.", clazz);
return DataType.custom("unknow");
} /**
* <b>function:</b> 转换集合list、set到cql类型
* @author hoojo
* @createDate 2017-1-20 下午5:22:43
* @param clazz java class
* @param valueClass 集合存储类型class
* @return DataType
*/
private static DataType valueOf(Class<?> clazz, Class<?> valueClass) { return valueOf(clazz, valueClass, null);
}
}