@Override public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }

    KafkaSupervisorIOConfig that = (KafkaSupervisorIOConfig) o;

    if (useEarliestOffset != that.useEarliestOffset) {
      return false;
    }
    if (skipOffsetGaps != that.skipOffsetGaps) {
      return false;
    }
    if (topic != null ? !topic.equals(that.topic) : that.topic != null) {
      return false;
    }
    if (replicas != null ? !replicas.equals(that.replicas) : that.replicas != null) {
      return false;
    }
    if (taskCount != null ? !taskCount.equals(that.taskCount) : that.taskCount != null) {
      return false;
    }
    if (taskDuration != null ? !taskDuration.equals(that.taskDuration) : that.taskDuration != null) {
      return false;
    }
    if (consumerProperties != null ?
        !consumerProperties.equals(that.consumerProperties) :
        that.consumerProperties != null) {
      return false;
    }
    if (startDelay != null ? !startDelay.equals(that.startDelay) : that.startDelay != null) {
      return false;
    }
    if (period != null ? !period.equals(that.period) : that.period != null) {
      return false;
    }
    if (completionTimeout != null ?
        !completionTimeout.equals(that.completionTimeout) :
        that.completionTimeout != null) {
      return false;
    }
    if (lateMessageRejectionPeriod.isPresent() ?
        !lateMessageRejectionPeriod.equals(that.lateMessageRejectionPeriod) :
        that.lateMessageRejectionPeriod.isPresent()) {
      return false;
    }
    return earlyMessageRejectionPeriod.isPresent() ?
        earlyMessageRejectionPeriod.equals(that.earlyMessageRejectionPeriod) :
        !that.earlyMessageRejectionPeriod.isPresent();
  }
This class is copied from druid source code
in order to avoid adding additional dependencies on druid-indexing-service.
druid-handler/src/java/org/apache/hadoop/hive/druid/json/KafkaSupervisorIOConfig.java