All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hubspot.rosetta.RosettaMapper Maven / Gradle / Ivy

The newest version!
package com.hubspot.rosetta;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hubspot.rosetta.internal.TableNameExtractor;
import java.lang.reflect.Type;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.util.HashMap;
import java.util.Map;

/**
 * Core mapping functionality.
 *
 * The {@code map} methods here take iterable result sets (field names * to String values) and use Jackson to bind
 * those values to a * type instance.
 */
public class RosettaMapper {

  private static TableNameExtractor TABLE_NAME_EXTRACTOR = chooseTableNameExtractor();

  private final JavaType type;
  private final ObjectMapper objectMapper;
  private final String tableName;

  public RosettaMapper(Class type) {
    this(type, Rosetta.getMapper());
  }

  public RosettaMapper(Class type, ObjectMapper objectMapper) {
    this(type, objectMapper, null);
  }

  public RosettaMapper(Class type, String tableName) {
    this(type, Rosetta.getMapper(), tableName);
  }

  public RosettaMapper(Class 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 map = new HashMap();
    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 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 submap = (Map) 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();
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy