package com.lhx.test;
import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.alibaba.dubbo.common.utils.StringUtils;
import com.alibaba.fastjson.JSON;
import com.lhx.test.utils.CSVRead;
import com.lhx.test.utils.StringValidate;
import org.junit.Test;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;
/**
* Created by Li hongxin on 2019/6/19
* Desc : 解析list里面的数据,转换成对象
*/
public class ParseList {
private static final String SPLIT_SYMBOL = "_";
private static final String array[] = {
"java.lang.String",
"java.lang.Long",
"long",
"java.lang.Integer",
"int",
"java.lang.Boolean",
"boolean",
"java.lang.Double",
"double",
"java.lang.Float",
"float",
"java.lang.Character",
"char",
"java.lang.Short",
"short",
"java.lang.Byte",
"byte",
"java.util.Date"
};
private static final String REGEX1 = "(\\d{4})/(\\d{1,2})/(\\d{1,2})";
private static final String REGEX2 = "(\\d{4})-(\\d{2})-(\\d{2})";
private static final String REGEX3 = "(\\d{4})/(\\d{1,2})/(\\d{1,2}) (\\d{2}):(\\d{2}):(\\d{2})";
private static final String REGEX4 = "(\\d{4})-(\\d{2})-(\\d{2}) (\\d{2}):(\\d{2}):(\\d{2})";
private static final String TEMPLATE1 = "yyyy/MM/dd";
private static final String TEMPLATE2 = "yyyy-MM-dd";
private static final String TEMPLATE3 = "yyyy/MM/dd hh:mm:ss";
private static final String TEMPLATE4 = "yyyy-MM-dd hh:mm:ss";
private static final Pattern pattern1 = Pattern.compile(REGEX1);
private static final Pattern pattern2 = Pattern.compile(REGEX2);
private static final Pattern pattern3 = Pattern.compile(REGEX3);
private static final Pattern pattern4 = Pattern.compile(REGEX4);
private static final SimpleDateFormat sdf1 = new SimpleDateFormat(TEMPLATE1);
private static final SimpleDateFormat sdf2 = new SimpleDateFormat(TEMPLATE2);
private static final SimpleDateFormat sdf3 = new SimpleDateFormat(TEMPLATE3);
private static final SimpleDateFormat sdf4 = new SimpleDateFormat(TEMPLATE4);
// 测试
public static <T> void testThread(String path, String charset, char elementSeparator, char quoteChar, Class<T> clz, boolean underlined) throws Exception {
DataInputStream in = new DataInputStream(new FileInputStream(new File(path)));
BufferedReader reader= new BufferedReader(new InputStreamReader(in,charset));
CSVRead csvRead = new CSVRead(reader, elementSeparator, quoteChar);
List<ArrayList<String>> lists = csvRead.readFile();
System.out.println(Thread.currentThread() + "---------" + JSON.toJSONString(toJavaBean(lists, clz, underlined)));
}
/**
* Created by lhx on 2019/6/19 17:30
* Desc : 把数据转换成任何指定泛型的对象集合,根据对象的属性获取对应属性下的转换后的值并进行赋值
* outer 数据集合
* clz 要转换成的对象
* underlined CSV文件中的字段名是否为下划线格式的
*/
public static <T> List<T> toJavaBean(List<ArrayList<String>> outer, Class<T> clz, boolean underlined) throws Exception {
if (null == outer || outer.size() < 2) {
return null;
}
List<T> resultList = new ArrayList<T>();
//先转换原文件中获取的字段名为驼峰格式的
ArrayList<String> originalNames = outer.get(0);
int fieldCount = originalNames.size();
if (underlined) {
//如果是下划线格式的,则转换为驼峰格式的
toCamelCase(originalNames);
}
//初始化两个集合,接收bean对象的有效字段名和字段对应的类型
List<String> beanFieldNames = new ArrayList<String>(fieldCount);
List<String> fieldTypes = new ArrayList<String>(fieldCount);
//递归取出当前类和父类以及更高级的类的所有除Object类之外的字段以及属性
recurrenceFetch(beanFieldNames, fieldTypes, originalNames, clz);
List<String> _beanFieldNames = getList(String.class, fieldCount);
List<String> _fieldTypes = getList(String.class, fieldCount);
List<Integer> _index = getList(Integer.class, fieldCount);
for (int i = 0; i < fieldCount; i++) {
String _fieldName = originalNames.get(i);
if (beanFieldNames.contains(_fieldName)) {
//如果此索引下含有该字段名,则记录该字段名,字段属性,在原数据list的索引位置,
_beanFieldNames.set(i, _fieldName);
_fieldTypes.set(i, fieldTypes.get(beanFieldNames.indexOf(_fieldName)));
_index.add(i);
}
}
//解析数据
for (int dataIndex = 1; dataIndex < outer.size(); dataIndex++) {
ArrayList<String> inner = outer.get(dataIndex);
T newInstance = clz.newInstance();
for (int i = 0; i < Math.min(inner.size(), fieldCount); i++) {
// 递归给当前类和父类和除了Object之外的超类赋值
newInstance = recurrenceAssign(_index, _beanFieldNames, _fieldTypes, inner, newInstance, clz, i);
}
resultList.add(newInstance);
}
return resultList;
}
// 返回指定类型和长度的集合并进行初始化
private static <T> List<T> getList(Class<T> clz, int initSize) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
if (0 >= initSize) {
return new ArrayList<T>(0);
}
//ArrayList初始化长度为10,大于10的则按照arrayList底层扩容算法进行扩容
initSize = initSize < 10 ? 10 : (initSize + (initSize >> 1));
List<T> list = new ArrayList<T>(initSize);
int count = 0;
String className = clz.getName();
while (count < initSize) {
T newInstance;
if (array[0].equals(className)) {
newInstance = clz.getConstructor(String.class).newInstance("");
} else if (array[1].equals(className)) {
newInstance = clz.getConstructor(long.class).newInstance(-1L);
} else if (array[3].equals(className)) {
newInstance = clz.getConstructor(int.class).newInstance(-1);
} else if (array[7].equals(className)) {
newInstance = clz.getConstructor(double.class).newInstance(-1);
} else {
newInstance = null;
}
list.add(newInstance);
count++;
}
return list;
}
// 递归给当前类和除了Object之外的超类赋值
private static <T> T recurrenceAssign(List<Integer> _index, List<String> _beanFieldNames, List<String> _fieldTypes, ArrayList<String> inner, T newInstance, Class<?> clz, int i) {
if (_index.contains(i)) {
String fieldName = _beanFieldNames.get(i);
String fieldType = _fieldTypes.get(i);
String value = inner.get(i);
Object realValue = getRealValue(fieldType, value);
Field field;
try {
if ("isNew".equals(fieldName)) {
realValue = dealNum((String)realValue);
}
field = clz.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(newInstance, realValue);
} catch (Exception e) {
//当前类没有此字段,去父类中找, 如果匹配上,则进行赋值,直到匹配到Object为止,
// 如果匹配不到,抛出java.lang.NoSuchFieldException异常,catch到之后进行递归父类的字段,
if (e instanceof NoSuchFieldException) {
Class<?> superclass = newInstance.getClass().getSuperclass();
if (Object.class != superclass) {
recurrenceAssign(_index, _beanFieldNames, _fieldTypes, inner, newInstance, superclass, i);
}
}
}
}
return newInstance;
}
//递归迭代出本对象以及除Object之外所有超类的属性
private static void recurrenceFetch(List<String> beanFieldNames, List<String> fieldTypes, ArrayList<String> originalNames, Class<?> clz) {
Field[] fields = clz.getDeclaredFields();
if (Object.class != clz) {
iterate(beanFieldNames, fieldTypes, originalNames, fields);
Class<?> superclass = clz.getSuperclass();
recurrenceFetch(beanFieldNames, fieldTypes, originalNames, superclass);
}
}
//迭代出所有属性名和属性
private static void iterate(List<String> beanFieldNames, List<String> fieldTypes, ArrayList<String> originalNames, Field[] fields) {
for (Field field : fields) {
String name = field.getName();
if (originalNames.contains(name)) {
beanFieldNames.add(name);
fieldTypes.add(field.getType().getName());
}
}
}
//把有效值进行翻译成每个字段对应的属性所对应的值
private static Object getRealValue(final String fieldType, String value) {
String[] comparedArray = array;
if (comparedArray[0].equals(fieldType)) {
value = dealNum(value);
return value;
}
if (comparedArray[1].equals(fieldType) || comparedArray[2].equals(fieldType)) {
value = dealNum(value);
return Long.valueOf(value);
}
if (comparedArray[3].equals(fieldType) || comparedArray[4].equals(fieldType)) {
value = dealNum(value);
return Integer.valueOf(value);
}
if (comparedArray[5].equals(fieldType) || comparedArray[6].equals(fieldType)) {
return Boolean.valueOf(value);
}
if (comparedArray[7].equals(fieldType) || comparedArray[8].equals(fieldType)) {
return Double.valueOf(value);
}
if (comparedArray[9].equals(fieldType) || comparedArray[10].equals(fieldType)) {
return Float.valueOf(value);
}
if (comparedArray[11].equals(fieldType) || comparedArray[12].equals(fieldType)) {
return value.charAt(0);
}
if (comparedArray[13].equals(fieldType) || comparedArray[14].equals(fieldType)) {
value = dealNum(value);
return Short.valueOf(value);
}
if (comparedArray[15].equals(fieldType) || comparedArray[16].equals(fieldType)) {
value = dealNum(value);
return Byte.valueOf(value);
}
if (comparedArray[17].equals(fieldType)) {
return parseDate(value);
}
return value;
}
//处理数字,由于CSV文件生成的时候,数字都会带小数点,如:21.0/39.0/0.0等,导致解析为int或者long类型的时候,报错.解析之后返回小数点之前的数字
public static String dealNum(String str) {
if (StringUtils.isBlank(str)) {
return "";
}
if (Pattern.compile("(\\d+)\\.(\\d+)").matcher(str).matches()) {
str = str.substring(0, str.indexOf("."));
}
return str;
}
//解析时间,如果不符合正则列举的这几种,则无法解析,返回null,别的类型会报错
private static Date parseDate(String value) {
if (StringUtils.isBlank(value)) {
return null;
}
try {
if (pattern1.matcher(value).matches()) {
return sdf1.parse(value);
}
if (pattern2.matcher(value).matches()) {
return sdf2.parse(value);
}
if (pattern3.matcher(value).matches()) {
return sdf3.parse(value);
}
if (pattern4.matcher(value).matches()) {
return sdf4.parse(value);
}
} catch (ParseException e) {
return null;
}
return null;
}
/**
* Created by lhx on 2019/6/19 17:44
* Desc : 下划线格式转换为驼峰格式
* fileNames 要进行转换的数据
* beanFieldsName 要转换到对象的对象名
* @returns 返回驼峰格式的数据
*/
private static void toCamelCase(ArrayList<String> fieldNames) {
if (CollectionUtils.isEmpty(fieldNames)) {
return;
}
for (int i = 0; i < fieldNames.size(); i++) {
String fieldName = fieldNames.get(i);
if (StringValidate.isNotBlank(fieldName)) {
fieldName = fieldName.toLowerCase();
if (fieldName.contains(SPLIT_SYMBOL)) {
String[] split = fieldName.split(SPLIT_SYMBOL);
String temp = split[0];
for (int j = 1; j < split.length; j++) {
String str = split[j];
temp = temp + str.substring(0, 1).toUpperCase() + str.substring(1, str.length());
}
fieldName = temp;
}
//使用驼峰格式替换下划线格式
fieldNames.set(i, fieldName);
}
}
}
//去驼峰,转为下划线
private static void deCamelCase(ArrayList<String> fieldNames) {
if (CollectionUtils.isEmpty(fieldNames)) {
return;
}
for (int i = 0; i < fieldNames.size(); i++) {
String fieldName = fieldNames.get(i);
if (StringValidate.isNotBlank(fieldName)) {
//去空格
fieldName = fieldName.replace(" ", "");
//逐个字符遍历
StringBuilder sb = new StringBuilder(16);
for (Character chr : fieldName.toCharArray()) {
if (Character.isLetter(chr)) {
if (Character.isUpperCase(chr)) {
chr = Character.toLowerCase(chr);
sb.append(SPLIT_SYMBOL).append(chr);
} else {
sb.append(chr);
}
} else {
sb.append(chr);
}
}
fieldName = sb.toString().toUpperCase();
//使用驼峰格式替换下划线格式
fieldNames.set(i, fieldName);
}
}
}
}