Repository: corona-warn-app/cwa-server
File: services/distribution/src/main/java/app/coronawarn/server/services/distribution/statistics/keyfigurecard/factory/HeaderCardFactory.java (Java)

Code before:
import app.coronawarn.server.common.protocols.internal.stats.CardHeader;
import app.coronawarn.server.common.protocols.internal.stats.KeyFigureCard;
import app.coronawarn.server.services.distribution.statistics.StatisticsJsonStringObject;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public abstract class HeaderCardFactory {

  /**
   * Create KeyFigureCard object. Calls the children method `buildKeyFigureCard` for card specific properties. This
   * method adds the generic CardHeader that all KeyFigureCards must have.
   *
   * @param stats JSON Object statistics
   * @return KeyFigureCard .
   */
  public KeyFigureCard makeKeyFigureCard(StatisticsJsonStringObject stats) {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    LocalDate dateTime = LocalDate.parse(stats.getEffectiveDate(), formatter);
    if (this.getCardId() == HOSPITALIZATION_INCIDENCE_CARD.ordinal()) {
      dateTime = stats.getHospitalizationEffectiveDate() == null || stats.getHospitalizationEffectiveDate().isEmpty()
          ? LocalDate.parse(stats.getEffectiveDate(), formatter) :
          LocalDate.parse(stats.getHospitalizationEffectiveDate(), formatter);
    }
    KeyFigureCard.Builder keyFigureBuilder = makeBuilderWithDefaultHeader(dateTime);
    throwIfNullFieldsFound(stats);
    return this.buildKeyFigureCard(stats, keyFigureBuilder);
  }

  private KeyFigureCard.Builder makeBuilderWithDefaultHeader(LocalDate dateTime) {
    return KeyFigureCard.newBuilder()
        .setHeader(CardHeader.newBuilder()
            .setCardId(this.getCardId())
            .setUpdatedAt(dateTime.atStartOfDay(UTC).toEpochSecond())
            .build()
        );
  }

  private void throwIfNullFieldsFound(StatisticsJsonStringObject stats) {
    var nullFieldsOrZeroOrLessThanZero = getRequiredFieldValues(stats).stream()
        .filter(Optional::isEmpty)
        .collect(Collectors.toList());
    if (!nullFieldsOrZeroOrLessThanZero.isEmpty()) {
      throw new MissingPropertyException(this.getCardId());
    }
  }

  protected abstract int getCardId();


Review comment (suggestion):
@ioangut dateTime is already initialized with `stats.getEffectiveDate`, so it's sufficient to overwrite only in case it's the correct card and the value isn't empty... what do you think?

```suggestion
    if (this.getCardId() == HOSPITALIZATION_INCIDENCE_CARD.ordinal() && !ObjectUtils.isEmpty(stats.getHospitalizationEffectiveDate())) {
      dateTime = LocalDate.parse(stats.getHospitalizationEffectiveDate(), formatter);
    }
```

Code after:
import app.coronawarn.server.common.protocols.internal.stats.CardHeader;
import app.coronawarn.server.common.protocols.internal.stats.KeyFigureCard;
import app.coronawarn.server.services.distribution.statistics.StatisticsJsonStringObject;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.springframework.util.ObjectUtils;

public abstract class HeaderCardFactory {

  /**
   * Create KeyFigureCard object. Calls the children method `buildKeyFigureCard` for card specific properties. This
   * method adds the generic CardHeader that all KeyFigureCards must have.
   *
   * @param stats JSON Object statistics
   * @return KeyFigureCard .
   */
  public KeyFigureCard makeKeyFigureCard(StatisticsJsonStringObject stats) {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    LocalDate dateTime = LocalDate.parse(stats.getEffectiveDate(), formatter);
    if (this.getCardId() == HOSPITALIZATION_INCIDENCE_CARD.ordinal() 
        && !ObjectUtils.isEmpty(stats.getHospitalizationEffectiveDate())) {
      dateTime = LocalDate.parse(stats.getHospitalizationEffectiveDate(), formatter);
    }
    KeyFigureCard.Builder keyFigureBuilder = makeBuilderWithDefaultHeader(dateTime);
    throwIfNullFieldsFound(stats);
    return this.buildKeyFigureCard(stats, keyFigureBuilder);
  }

  private KeyFigureCard.Builder makeBuilderWithDefaultHeader(LocalDate dateTime) {
    return KeyFigureCard.newBuilder()
        .setHeader(CardHeader.newBuilder()
            .setCardId(this.getCardId())
            .setUpdatedAt(dateTime.atStartOfDay(UTC).toEpochSecond())
            .build()
        );
  }

  private void throwIfNullFieldsFound(StatisticsJsonStringObject stats) {
    var nullFieldsOrZeroOrLessThanZero = getRequiredFieldValues(stats).stream()
        .filter(Optional::isEmpty)
        .collect(Collectors.toList());
    if (!nullFieldsOrZeroOrLessThanZero.isEmpty()) {
      throw new MissingPropertyException(this.getCardId());
    }
  }

  protected abstract int getCardId();