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); } } } }