package com.linkedin.thirdeye.datalayer.util; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.sql.Clob; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.Timestamp; import java.sql.Types; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import org.modelmapper.ModelMapper; import org.modelmapper.config.Configuration.AccessLevel; import org.modelmapper.convention.NameTokenizers; import com.google.common.collect.BiMap; import com.linkedin.thirdeye.datalayer.dto.TaskDTO; import com.linkedin.thirdeye.datalayer.entity.AbstractEntity; public class GenericResultSetMapper { ModelMapper modelMapper = new ModelMapper(); private EntityMappingHolder entityMappingHolder; { modelMapper.getConfiguration().setSourceNameTokenizer(NameTokenizers.CAMEL_CASE) .setFieldMatchingEnabled(true).setFieldAccessLevel(AccessLevel.PRIVATE); // modelMapper.getConfiguration().setSourceNameTokenizer(NameTokenizers.UNDERSCORE) // .setMatchingStrategy(MatchingStrategies.LOOSE) // .setDestinationNameTokenizer(NameTokenizers.UNDERSCORE); } public GenericResultSetMapper(EntityMappingHolder entityMappingHolder) { this.entityMappingHolder = entityMappingHolder; } public <E extends AbstractEntity> E mapSingle(ResultSet rs, Class<? extends AbstractEntity> entityClass) throws Exception { List<E> resultMapList = (List<E>) toEntityList(rs, entityClass); if (resultMapList.size() > 0) { return resultMapList.get(0); } return null; } public <E extends AbstractEntity> List<E> mapAll(ResultSet rs, Class<E> entityClass) throws Exception { return toEntityList(rs, entityClass); } private <E extends AbstractEntity> List<E> toEntityList(ResultSet rs, Class<E> entityClass) throws Exception { String tableName = entityMappingHolder.tableToEntityNameMap.inverse().get(entityClass.getSimpleName()); LinkedHashMap<String, ColumnInfo> columnInfoMap = entityMappingHolder.columnInfoPerTable.get(tableName); List<E> entityList = new ArrayList<>(); ObjectMapper mapper = new ObjectMapper(); while (rs.next()) { AbstractEntity entityObj = entityClass.newInstance(); ResultSetMetaData resultSetMetaData = rs.getMetaData(); int numColumns = resultSetMetaData.getColumnCount(); ObjectNode objectNode = mapper.createObjectNode(); for (int i = 1; i <= numColumns; i++) { String dbColumnName = resultSetMetaData.getColumnLabel(i).toLowerCase(); ColumnInfo columnInfo = columnInfoMap.get(dbColumnName); Field field = columnInfo.field; Object val; if (columnInfo.sqlType == Types.CLOB) { Clob clob = rs.getClob(i); val = clob.getSubString(1, (int) clob.length()); } else { val = rs.getObject(i); } if (val == null) { continue; } if (field.getType().isAssignableFrom(Timestamp.class)) { objectNode.put(field.getName(), ((Timestamp) val).getTime()); } else { objectNode.put(field.getName(), val.toString()); } /* * if (Enum.class.isAssignableFrom(field.getType())) { field.set(entityObj, * Enum.valueOf(field.getType().asSubclass(Enum.class), val.toString())); } else if * (String.class.isAssignableFrom(field.getType())) { field.set(entityObj, val.toString()); * } else if (Integer.class.isAssignableFrom(field.getType())) { field.set(entityObj, * Integer.valueOf(val.toString())); } else if * (Long.class.isAssignableFrom(field.getType())) { field.set(entityObj, * Long.valueOf(val.toString())); } else { field.set(entityObj, val); } */ } entityObj = mapper.treeToValue(objectNode, entityClass); entityList.add((E) entityObj); } return entityList; } public AbstractEntity mapSingleOLD(ResultSet rs, Class<? extends AbstractEntity> entityClass) throws Exception { List<Map<String, Object>> resultMapList = toResultMapList(rs, entityClass); if (resultMapList.size() > 0) { Map<String, Object> map = resultMapList.get(0); if (map.get("workerId") != null) { ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream(new File("/tmp/map.out." + System.currentTimeMillis()))); oos.writeObject(map); oos.close(); System.out.println(map); } AbstractEntity entity = modelMapper.map(map, entityClass); System.out.println(entity); return entity; } return null; } public List<AbstractEntity> mapAllOLD(ResultSet rs, Class<? extends AbstractEntity> entityClass) throws Exception { List<Map<String, Object>> resultMapList = toResultMapList(rs, entityClass); List<AbstractEntity> resultEntityList = new ArrayList<>(); if (resultMapList.size() > 0) { for (Map<String, Object> map : resultMapList) { AbstractEntity entity = modelMapper.map(map, entityClass); resultEntityList.add(entity); } } return resultEntityList; } List<Map<String, Object>> toResultMapList(ResultSet rs, Class<? extends AbstractEntity> entityClass) throws Exception { List<Map<String, Object>> resultMapList = new ArrayList<>(); String tableName = entityMappingHolder.tableToEntityNameMap.inverse().get(entityClass.getSimpleName()); BiMap<String, String> dbNameToEntityNameMapping = entityMappingHolder.columnMappingPerTable.get(tableName); while (rs.next()) { ResultSetMetaData resultSetMetaData = rs.getMetaData(); int numColumns = resultSetMetaData.getColumnCount(); HashMap<String, Object> map = new HashMap<>(); for (int i = 1; i <= numColumns; i++) { String dbColumnName = resultSetMetaData.getColumnLabel(i).toLowerCase(); String entityFieldName = dbNameToEntityNameMapping.get(dbColumnName); Object val = rs.getObject(i); if (val != null) { map.put(entityFieldName, val.toString()); } } resultMapList.add(map); } System.out.println(resultMapList); return resultMapList; } public static void main(String[] args) throws Exception { ModelMapper mapper = new ModelMapper(); Map<String, Object> result = new HashMap<>(); //[{jobName=Test_Anomaly_Task, jobId=1, workerId=1, taskType=MONITOR, id=1, taskInfo=clob2: '{"jobExecutionId":1,"monitorType":"UPDATE","expireDaysAgo":0}', lastModified=2016-08-24 17:25:53.258, version=0, taskStartTime=1470356753227, status=RUNNING, taskEndTime=1471220753227}] result.put("jobName", "Test_Anomaly_Task"); result.put("jobId", 1L); result.put("taskType", "MONITOR"); result.put("id", 1L); result.put("taskInfo", "clob2: '{\"jobExecutionId\":1,\"monitorType\":\"UPDATE\",\"expireDaysAgo\":0}'"); result.put("taskType", "MONITOR"); result.put("lastModified", "2016-08-24 17:25:53.258"); result.put("status", "RUNNING"); result.put("lastModified", "2016-08-24 17:25:53.258"); TaskDTO taskSpec1 = mapper.map(result, TaskDTO.class); System.out.println(taskSpec1); //INPUT 2 ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("/tmp/map.out.1472093046128"))); Map<String, Object> inputMap = (Map<String, Object>) ois.readObject(); TaskDTO taskSpec2 = mapper.map(inputMap, TaskDTO.class); System.out.println(taskSpec2); } }