// Path: RosettaCore/src/main/java/com/hubspot/rosetta/RosettaMapper.java
// public class RosettaMapper<T> {
//   private static TableNameExtractor TABLE_NAME_EXTRACTOR = chooseTableNameExtractor();
// 
//   private final JavaType type;
//   private final ObjectMapper objectMapper;
//   private final String tableName;
// 
//   public RosettaMapper(Class<T> type) {
//     this(type, Rosetta.getMapper());
//   }
// 
//   public RosettaMapper(Class<T> type, ObjectMapper objectMapper) {
//     this(type, objectMapper, null);
//   }
// 
//   public RosettaMapper(Class<T> type, String tableName) {
//     this(type, Rosetta.getMapper(), tableName);
//   }
// 
//   public RosettaMapper(Class<T> type, ObjectMapper objectMapper, String tableName) {
//     this((Type) type, objectMapper, tableName);
//   }
// 
//   public RosettaMapper(Type type, ObjectMapper objectMapper, String tableName) {
//     this.type = objectMapper.constructType(type);
//     this.objectMapper = objectMapper;
//     this.tableName = tableName;
//   }
// 
//   /**
//    * Map a single ResultSet row to a T instance.
//    *
//    * @throws SQLException
//    */
//   public T mapRow(ResultSet rs) throws SQLException {
//     Map<String, Object> map = new HashMap<String, Object>();
//     ResultSetMetaData metadata = rs.getMetaData();
// 
//     for (int i = 1; i <= metadata.getColumnCount(); ++i) {
//       String label = metadata.getColumnLabel(i);
// 
//       final Object value;
//       // calling getObject on a BLOB/CLOB produces weird results
//       switch (metadata.getColumnType(i)) {
//         case Types.BLOB:
//           value = rs.getBytes(i);
//           break;
//         case Types.CLOB:
//           value = rs.getString(i);
//           break;
//         default:
//           value = rs.getObject(i);
//       }
// 
//       // don't use table name extractor because we don't want aliased table name
//       boolean overwrite = this.tableName != null && this.tableName.equals(metadata.getTableName(i));
//       String tableName = TABLE_NAME_EXTRACTOR.getTableName(metadata, i);
//       if (tableName != null && !tableName.isEmpty()) {
//         String qualifiedName = tableName + "." + metadata.getColumnName(i);
//         add(map, qualifiedName, value, overwrite);
//       }
// 
//       add(map, label, value, overwrite);
//     }
// 
//     return objectMapper.convertValue(map, type);
//   }
// 
//   private void add(Map<String, Object> map, String label, Object value, boolean overwrite) {
//     if (label.contains(".")) {
//       int periodIndex = label.indexOf('.');
//       String prefix = label.substring(0, periodIndex);
//       String suffix = label.substring(periodIndex + 1);
// 
//       @SuppressWarnings("unchecked")
//       Map<String, Object> submap = (Map<String, Object>) map.get(prefix);
//       if (submap == null) {
//         submap = new HashMap<>();
//         map.put(prefix, submap);
//       }
// 
//       add(submap, suffix, value, overwrite);
//     } else {
//       if (overwrite || !map.containsKey(label)) {
//         map.put(label, value);
//       }
//     }
//   }
// 
//   private static TableNameExtractor chooseTableNameExtractor() {
//     try {
//       Class.forName("com.mysql.jdbc.ResultSetMetaData");
//       return (TableNameExtractor) Class.forName("com.mysql.jdbc.MysqlTableNameExtractor").newInstance();
//     } catch (Exception e) {
//       return new TableNameExtractor.Default();
//     }
//   }
// }
// 
// Path: RosettaCore/src/main/java/com/hubspot/rosetta/util/SqlTableNameExtractor.java
// public class SqlTableNameExtractor {
// 
//   private SqlTableNameExtractor() {
//     throw new AssertionError();
//   }
// 
//   public static String extractTableName(final String sql) {
//     String lowerCaseSql = sql.toLowerCase();
// 
//     String from = " from ";
//     int fromIndex = lowerCaseSql.indexOf(from);
//     if (fromIndex < 0) {
//       return null;
//     }
// 
//     String tableString = sql.substring(fromIndex + from.length());
//     if (tableString.startsWith("(")) {
//       return null;
//     }
// 
//     int endTableIndex = -1;
//     for (int i = 0; i < tableString.length(); i++) {
//       char c = tableString.charAt(i);
//       if (c == ' ' || c == ',' || c == ';') {
//         endTableIndex = i;
//         break;
//       }
//     }
// 
//     return endTableIndex < 0 ? tableString : tableString.substring(0, endTableIndex);
//   }
// }


import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.skife.jdbi.v2.BuiltInArgumentFactory;
import org.skife.jdbi.v2.ResultSetMapperFactory;
import org.skife.jdbi.v2.StatementContext;
import org.skife.jdbi.v2.tweak.ResultSetMapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hubspot.rosetta.RosettaMapper;
import com.hubspot.rosetta.util.SqlTableNameExtractor;
package com.hubspot.rosetta.jdbi;




public class RosettaMapperFactory implements ResultSetMapperFactory {

  @Override
  public boolean accepts(@SuppressWarnings("rawtypes") Class type, StatementContext ctx) {
    return !(type.isPrimitive() || type.isArray() || type.isAnnotation() || BuiltInArgumentFactory.canAccept(type));
  }

  @Override
  @SuppressWarnings({ "rawtypes", "unchecked" })
  public ResultSetMapper mapperFor(Class rawType, StatementContext ctx) {
    ObjectMapper objectMapper = RosettaObjectMapperOverride.resolve(ctx);

    final Type genericType;
    if (ctx.getSqlObjectMethod() == null) {
      genericType = rawType;
    } else {
      genericType = determineGenericReturnType(rawType, ctx.getSqlObjectMethod().getGenericReturnType());
    }
// Path: RosettaCore/src/main/java/com/hubspot/rosetta/RosettaMapper.java
// public class RosettaMapper<T> {
//   private static TableNameExtractor TABLE_NAME_EXTRACTOR = chooseTableNameExtractor();
// 
//   private final JavaType type;
//   private final ObjectMapper objectMapper;
//   private final String tableName;
// 
//   public RosettaMapper(Class<T> type) {
//     this(type, Rosetta.getMapper());
//   }
// 
//   public RosettaMapper(Class<T> type, ObjectMapper objectMapper) {
//     this(type, objectMapper, null);
//   }
// 
//   public RosettaMapper(Class<T> type, String tableName) {
//     this(type, Rosetta.getMapper(), tableName);
//   }
// 
//   public RosettaMapper(Class<T> type, ObjectMapper objectMapper, String tableName) {
//     this((Type) type, objectMapper, tableName);
//   }
// 
//   public RosettaMapper(Type type, ObjectMapper objectMapper, String tableName) {
//     this.type = objectMapper.constructType(type);
//     this.objectMapper = objectMapper;
//     this.tableName = tableName;
//   }
// 
//   /**
//    * Map a single ResultSet row to a T instance.
//    *
//    * @throws SQLException
//    */
//   public T mapRow(ResultSet rs) throws SQLException {
//     Map<String, Object> map = new HashMap<String, Object>();
//     ResultSetMetaData metadata = rs.getMetaData();
// 
//     for (int i = 1; i <= metadata.getColumnCount(); ++i) {
//       String label = metadata.getColumnLabel(i);
// 
//       final Object value;
//       // calling getObject on a BLOB/CLOB produces weird results
//       switch (metadata.getColumnType(i)) {
//         case Types.BLOB:
//           value = rs.getBytes(i);
//           break;
//         case Types.CLOB:
//           value = rs.getString(i);
//           break;
//         default:
//           value = rs.getObject(i);
//       }
// 
//       // don't use table name extractor because we don't want aliased table name
//       boolean overwrite = this.tableName != null && this.tableName.equals(metadata.getTableName(i));
//       String tableName = TABLE_NAME_EXTRACTOR.getTableName(metadata, i);
//       if (tableName != null && !tableName.isEmpty()) {
//         String qualifiedName = tableName + "." + metadata.getColumnName(i);
//         add(map, qualifiedName, value, overwrite);
//       }
// 
//       add(map, label, value, overwrite);
//     }
// 
//     return objectMapper.convertValue(map, type);
//   }
// 
//   private void add(Map<String, Object> map, String label, Object value, boolean overwrite) {
//     if (label.contains(".")) {
//       int periodIndex = label.indexOf('.');
//       String prefix = label.substring(0, periodIndex);
//       String suffix = label.substring(periodIndex + 1);
// 
//       @SuppressWarnings("unchecked")
//       Map<String, Object> submap = (Map<String, Object>) map.get(prefix);
//       if (submap == null) {
//         submap = new HashMap<>();
//         map.put(prefix, submap);
//       }
// 
//       add(submap, suffix, value, overwrite);
//     } else {
//       if (overwrite || !map.containsKey(label)) {
//         map.put(label, value);
//       }
//     }
//   }
// 
//   private static TableNameExtractor chooseTableNameExtractor() {
//     try {
//       Class.forName("com.mysql.jdbc.ResultSetMetaData");
//       return (TableNameExtractor) Class.forName("com.mysql.jdbc.MysqlTableNameExtractor").newInstance();
//     } catch (Exception e) {
//       return new TableNameExtractor.Default();
//     }
//   }
// }
// 
// Path: RosettaCore/src/main/java/com/hubspot/rosetta/util/SqlTableNameExtractor.java
// public class SqlTableNameExtractor {
// 
//   private SqlTableNameExtractor() {
//     throw new AssertionError();
//   }
// 
//   public static String extractTableName(final String sql) {
//     String lowerCaseSql = sql.toLowerCase();
// 
//     String from = " from ";
//     int fromIndex = lowerCaseSql.indexOf(from);
//     if (fromIndex < 0) {
//       return null;
//     }
// 
//     String tableString = sql.substring(fromIndex + from.length());
//     if (tableString.startsWith("(")) {
//       return null;
//     }
// 
//     int endTableIndex = -1;
//     for (int i = 0; i < tableString.length(); i++) {
//       char c = tableString.charAt(i);
//       if (c == ' ' || c == ',' || c == ';') {
//         endTableIndex = i;
//         break;
//       }
//     }
// 
//     return endTableIndex < 0 ? tableString : tableString.substring(0, endTableIndex);
//   }
// }


// Path: RosettaJdbi/src/main/java/com/hubspot/rosetta/jdbi/RosettaMapperFactory.java
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.skife.jdbi.v2.BuiltInArgumentFactory;
import org.skife.jdbi.v2.ResultSetMapperFactory;
import org.skife.jdbi.v2.StatementContext;
import org.skife.jdbi.v2.tweak.ResultSetMapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hubspot.rosetta.RosettaMapper;
import com.hubspot.rosetta.util.SqlTableNameExtractor;

package com.hubspot.rosetta.jdbi;




public class RosettaMapperFactory implements ResultSetMapperFactory {

  @Override
  public boolean accepts(@SuppressWarnings("rawtypes") Class type, StatementContext ctx) {
    return !(type.isPrimitive() || type.isArray() || type.isAnnotation() || BuiltInArgumentFactory.canAccept(type));
  }

  @Override
  @SuppressWarnings({ "rawtypes", "unchecked" })
  public ResultSetMapper mapperFor(Class rawType, StatementContext ctx) {
    ObjectMapper objectMapper = RosettaObjectMapperOverride.resolve(ctx);

    final Type genericType;
    if (ctx.getSqlObjectMethod() == null) {
      genericType = rawType;
    } else {
      genericType = determineGenericReturnType(rawType, ctx.getSqlObjectMethod().getGenericReturnType());
    }
    String tableName = SqlTableNameExtractor.extractTableName(ctx.getRewrittenSql());