@Override
  public Object deserialize(Writable blob) throws SerDeException {
    log.trace("Deserializing from SerDe");
    if (!(blob instanceof MapWritable)) {
      throw new SerDeException("Expected MapWritable. Got " + blob.getClass().getName());
    }

    if ((row == null) || (hiveColumnNames == null)) {
      throw new SerDeException("JDBC SerDe hasn't been initialized properly");
    }

    row.clear();
    MapWritable input = (MapWritable) blob;
    Text columnKey = new Text();

    for (int i = 0; i < hiveColumnNames.length; i++) {
      columnKey.set(hiveColumnNames[i]);
      Writable value = input.get(columnKey);
      Object rowVal;

      if(value instanceof NullWritable) {
        rowVal = null;
      } else {
        rowVal = ((ObjectWritable)value).get();

        switch (hiveColumnTypes[i].getPrimitiveCategory()) {
        case INT:
          if (rowVal instanceof Number) {
            rowVal = ((Number)rowVal).intValue();
          } else {
            rowVal = Integer.valueOf(rowVal.toString());
          }
          break;
        case SHORT:
          if (rowVal instanceof Number) {
            rowVal = ((Number)rowVal).shortValue();
          } else {
            rowVal = Short.valueOf(rowVal.toString());
          }
          break;
        case BYTE:
          if (rowVal instanceof Number) {
            rowVal = ((Number)rowVal).byteValue();
          } else {
            rowVal = Byte.valueOf(rowVal.toString());
          }
          break;
        case LONG:
          if (rowVal instanceof Long) {
            rowVal = ((Number)rowVal).longValue(); 
          } else {
            rowVal = Long.valueOf(rowVal.toString());
          }
          break;
        case FLOAT:
          if (rowVal instanceof Number) {
            rowVal = ((Number)rowVal).floatValue(); 
          } else {
            rowVal = Float.valueOf(rowVal.toString());
          }
          break;
        case DOUBLE:
          if (rowVal instanceof Number) {
            rowVal = ((Number)rowVal).doubleValue(); 
          } else {
            rowVal = Double.valueOf(rowVal.toString());
          }
          break;
        case DECIMAL:
          int scale = ((DecimalTypeInfo)hiveColumnTypes[i]).getScale();
          rowVal = HiveDecimal.create(rowVal.toString());
          ((HiveDecimal)rowVal).setScale(scale, BigDecimal.ROUND_HALF_EVEN);
          break;
        case BOOLEAN:
          if (rowVal instanceof Number) {
            rowVal = ((Number) value).intValue() != 0;
          } else {
            rowVal = Boolean.valueOf(rowVal.toString());
          }
          break;
        case CHAR:
        case VARCHAR:
        case STRING:
          if (rowVal instanceof java.sql.Date) {
            rowVal = DateUtils.getDateFormat().format((java.sql.Date)rowVal);
          } else {
            rowVal = rowVal.toString();
          }
          break;
        case DATE:
          if (rowVal instanceof java.sql.Date) {
            LocalDate localDate = ((java.sql.Date) rowVal).toLocalDate();
            rowVal = Date.of(localDate.getYear(), localDate.getMonthValue(), localDate.getDayOfMonth());
          } else {
            rowVal = Date.valueOf (rowVal.toString());
          }
          break;
        case TIMESTAMP:
          if (rowVal instanceof java.sql.Timestamp) {
            LocalDateTime localDateTime = ((java.sql.Timestamp) rowVal).toLocalDateTime();
            rowVal = Timestamp.ofEpochSecond(localDateTime.toEpochSecond(UTC), localDateTime.getNano());
          } else {
            rowVal = Timestamp.valueOf (rowVal.toString());
          }
          break;
        default:
          //do nothing
          break;
        }
      }
      row.add(rowVal);
    }
    return row;
  }
This method gets called multiple times by Hive. On some invocations, the properties will be empty.
We need to detect when the properties are not empty to initialize the class variables.
jdbc-handler/src/main/java/org/apache/hive/storage/jdbc/JdbcSerDe.java