2014年2月15日土曜日

DbUnit用のxmlデータを取得するLoader

DbUnitでエクスポートしたxmlデータをMapやbeanにロードするクラスです。
assertの比較元のデータを作る際に利用できそうなので作ってみました。
実際にテーブルが存在しなくてもDbUnitのxml形式でデータを作れば読み込むことができます。
dbunitの部分とreflectionの部分を別のクラスに分けたかったのですが、いずれやることにして取りあえずこのまま公開します。
例のごとくあまりテストはしていません。
使用しているライブラリは下記の通りです。
 ・commons-lang3-3.2.1.jar
 ・dbunit-2.4.9.jar
 ・guava-16.0.1.jar
+各ライブラリで必要なライブラリ

FlatXmlDataSetLoader.java
package my.junit.util;

import java.io.File;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.dbunit.dataset.Column;
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.ITable;
import org.dbunit.dataset.ITableMetaData;
import org.dbunit.dataset.xml.FlatXmlDataSetBuilder;

import com.google.common.base.CaseFormat;

public class FlatXmlDataSetLoader {

 /**
  * 日付用フォーマット
  */
 private static final String[] DEFAULT_DATE_FORMATS = {
   "yyyy-MM-dd hh:mm:ss.SSS", "yyyy-MM-dd hh:mm:ss", "yyyy-MM-dd" };

 /**
  * java.util.Date用フォーマット
  */
 private String[] dateFormats = null;

 /**
  * コンストラクタ
  */
 public FlatXmlDataSetLoader() {
  this.dateFormats = DEFAULT_DATE_FORMATS;
 }

 /**
  * コンストラクタ
  */
 public FlatXmlDataSetLoader(String... dateFormats) {
  this.dateFormats = dateFormats;
 }

 /**
  * DbUnit用のxmlファイルの1レコード分をMap化したリストを取得します。
  *
  * @param filePath
  *            xmlファイルのパス
  * @param tableName
  *            取得したいテーブル
  * @return 1レコード分をMapに設定したリスト
  */
 public List<Map<String, Object>> importToMapList(String filePath,
   String tableName) {
  try {
   IDataSet dataSet = new FlatXmlDataSetBuilder().build(new File(
     filePath));
   ITable table = dataSet.getTable(tableName);
   ITableMetaData meta = table.getTableMetaData();
   Column[] columns = meta.getColumns();

   List<Map<String, Object>> records = new ArrayList<Map<String, Object>>();
   for (int i = 0; i < table.getRowCount(); i++) {
    Map<String, Object> record = new HashMap<String, Object>();
    for (Column column : columns) {
     String columnName = column.getColumnName();
     record.put(columnName, table.getValue(i, columnName));
    }
    records.add(record);
   }
   return records;
  } catch (MalformedURLException e) {
   throw new IllegalArgumentException(e);
  } catch (DataSetException e) {
   throw new IllegalArgumentException(e);
  }
 }

 /**
  * DbUnit用のxmlファイルの1レコード分をbean化したリストを取得します。
  *
  * @param filePath
  *            xmlファイルのパス
  * @param tableName
  *            取得したいテーブル
  * @param beanClass
  *            設定対象のbean class
  * @return 1レコード分をbeanに設定したリスト
  */
 public <B> List<B> importToBeanList(String filePath, String tableName,
   Class<B> beanClass) {
  List<Map<String, Object>> snakeMapList = importToMapList(filePath,
    tableName);
  List<Map<String, Object>> camelMapList = new ArrayList<Map<String, Object>>();
  for (Map<String, Object> snakeMap : snakeMapList) {
   camelMapList.add(convertToLowerCamelKey(snakeMap));
  }
  return convertMapListToBeanList(camelMapList, beanClass);
 }

 /**
  * Mapのリストをbeanのリストに変換します。
  *
  * @param mapList
  *            Mapの
  * @param beanClass
  *            設定対象のbean class
  * @return beanのリスト
  */
 public <B> List<B> convertMapListToBeanList(
   List<Map<String, Object>> mapList, Class<B> beanClass) {
  Map<String, Field> fieldsInfo = getFieldInfo(beanClass);
  List<B> beans = new ArrayList<B>();
  for (Map<String, Object> map : mapList) {
   try {
    beans.add(convertMapToBean(map, beanClass.newInstance(),
      fieldsInfo));
   } catch (InstantiationException e) {
    throw new IllegalArgumentException(e);
   } catch (IllegalAccessException e) {
    throw new IllegalArgumentException(e);
   }
  }
  return beans;
 }

 /**
  * Mapのリストをbeanのリストに変換します。
  *
  * @param map
  *            Map
  * @param beanClass
  *            設定対象のbean class
  * @return bean
  */
 public <B> B convertMapToBean(Map<String, Object> map, Class<B> beanClass) {
  try {
   return convertMapToBean(map, beanClass.newInstance());
  } catch (InstantiationException e) {
   throw new IllegalArgumentException(e);
  } catch (IllegalAccessException e) {
   throw new IllegalArgumentException(e);
  }
 }

 /**
  * Mapのリストをbeanのリストに変換します。
  *
  * @param map
  *            Map
  * @param bean
  *            設定対象のbean
  * @return bean
  */
 public <B> B convertMapToBean(Map<String, Object> map, B bean) {
  Map<String, Field> fieldMap = getFieldInfo(bean.getClass());
  return convertMapToBean(map, bean, fieldMap);
 }

 /**
  * Mapのリストをbeanのリストに変換します。
  *
  * @param map
  *            Map
  * @param bean
  *            設定対象のbean
  * @param fieldsInfo
  *            beanのフィールド情報
  * @return bean
  */
 private <B> B convertMapToBean(Map<String, Object> map, B bean,
   Map<String, Field> fieldsInfo) {
  Set<Entry<String, Field>> fieldSet = fieldsInfo.entrySet();
  for (Entry<String, Field> fieldEntry : fieldSet) {
   Field field = fieldEntry.getValue();
   Object value = map.get(fieldEntry.getKey());
   setFieldValue(bean, field, value);
  }
  return bean;
 }

 /**
  * クラスのフィールド情報を取得します。
  *
  * @param beanClass
  *            対象のクラス
  * @return フィールド名をキーにしたフィールドのマップ
  */
 private static Map<String, Field> getFieldInfo(Class<?> beanClass) {
  Field[] fields = FieldUtils.getAllFields(beanClass);
  Map<String, Field> fieldMap = new HashMap<String, Field>();
  for (Field field : fields) {
   String key = field.getName();
   fieldMap.put(key, field);
  }
  return fieldMap;
 }

 /**
  * マップのキーをスネークケースからキャメルケースに変換します。
  *
  * @param snakeMap
  *            キーがスネークケースのマップ
  * @return キーがキャメルケースのマップ
  */
 private static <V> Map<String, V> convertToLowerCamelKey(
   Map<String, V> snakeMap) {
  Map<String, V> camelMap = new HashMap<String, V>();
  Set<String> snakeKeys = snakeMap.keySet();
  for (String snake : snakeKeys) {
   String camel = CaseFormat.UPPER_UNDERSCORE.to(
     CaseFormat.LOWER_CAMEL, snake);
   camelMap.put(camel, snakeMap.get(snake));
  }
  return camelMap;
 }

 /**
  * fieldのclassに合わせた形式に変換し値を設定
  *
  * @param bean
  *            設定対象のbean
  * @param field
  *            設定対象のfield
  * @param value
  *            設定する値
  * @return true:設定完了、false:未設定
  */
 private boolean setFieldValue(Object bean, Field field, Object value) {
  if (value == null) {
   // nullの場合
   return false;
  }
  try {
   field.setAccessible(true);
   String val = value.toString();
   if (field.getType().equals(String.class)) {
    field.set(bean, val);
   } else if (field.getType().equals(char[].class)) {
    field.set(bean, val.toCharArray());
   } else if (field.getType().equals(Boolean.class)) {
    field.set(bean, new Boolean(val));
   } else if (field.getType().equals(boolean.class)) {
    field.set(bean, new Boolean(val).booleanValue());
   } else if (field.getType().equals(Byte.class)) {
    field.set(bean, Byte.valueOf(val));
   } else if (field.getType().equals(byte.class)) {
    field.set(bean, Byte.valueOf(val).byteValue());
   } else if (field.getType().equals(Integer.class)) {
    field.set(bean, Integer.valueOf(val));
   } else if (field.getType().equals(int.class)) {
    field.set(bean, Integer.valueOf(val));
   } else if (field.getType().equals(Long.class)) {
    field.set(bean, Long.valueOf(val));
   } else if (field.getType().equals(long.class)) {
    field.set(bean, Long.valueOf(val));
   } else if (field.getType().equals(Short.class)) {
    field.set(bean, Short.valueOf(val));
   } else if (field.getType().equals(short.class)) {
    field.set(bean, Short.valueOf(val));
   } else if (field.getType().equals(Double.class)) {
    field.set(bean, Double.valueOf(val));
   } else if (field.getType().equals(double.class)) {
    field.set(bean, Double.valueOf(val));
   } else if (field.getType().equals(BigDecimal.class)) {
    field.set(bean, new BigDecimal(val));
   } else if (field.getType().equals(Date.class)) {
    field.set(bean, DateUtils.parseDate(val, dateFormats));
   } else if (field.getType().equals(Timestamp.class)) {
    Date date = DateUtils.parseDate(val, dateFormats);
    field.set(bean, new Timestamp(date.getTime()));
   } else {
    return false;
   }
  } catch (Exception e) {
   throw new IllegalArgumentException(e);
  } finally {
   field.setAccessible(false);
  }
  return true;
 }

}



0 件のコメント:

コメントを投稿