+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package org.spacious_team.table_wrapper.api;
+
+import lombok.Builder;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalQueries;
+
+/**
+ * Parses Instant. Date time format can be derived from cell value or can be configured.
+ * Some date time value examples witch date time format can be correctly derived from parsing value:
+ *
+ * 2000-02-01
+ * 01.02.2000
+ * 2000.02.01
+ * 01/02/2000
+ * 2000/02/01
+ * 20:10:02
+ * 20:10:02.000
+ * 2000-02-01T20:10:02
+ * 01.02.2000 20:10:02
+ * 01.02.2000 20:10:02.000
+ * 20:10:02 2000/02/01
+ * 20:10:02.000 2000/02/01
+ * 2000-02-01T20:10:02Z
+ * 01.02.2000 20:10:02Z
+ * 01.02.2000 20:10:02.000Z
+ * 20:10:02 2000/02/01Z
+ * 01.02.2000 20:10:02UTC
+ * 01.02.2000 20:10:02GMT
+ * 01.02.2000 20:10:02Europe/Moscow
+ * 01.02.2000 20:10:02.000Europe/Moscow
+ * 01.02.2000 20:10:02MSK
+ * 2000-02-01T20:10:02+0300
+ * 01.02.2000 20:10:02+0300
+ * 2000-02-01T20:10:02+03:00
+ * 01.02.2000 20:10:02+03:00
+ * 01.02.2000 20:10:02+03:00:00
+ * 01.02.2000 20:10:02GMT+3
+ * 01.02.2000 20:10:02GMT+3:00
+ * 01.02.2000 20:10:02GMT+03:00
+ * 01.02.2000 20:10:02GMT+03:00:00
+ * 01.02.2000 20:10:02.000GMT+03:00:00
+ *
+ *
+ * @implSpec If cell value doesn't contain zone name, when configured value used.
+ * If cell value doesn't contain date, when configured value used (default configuration value is current date).
+ * If cell value doesn't contain time, when configured value used (default configuration value is 12:00:00).
+ */
+@Builder
+@ToString
+@EqualsAndHashCode
+public class InstantParser {
+ public static final InstantParser INSTANCE = InstantParser.builder().build();
+ /**
+ * If null, date time format is derived from value
+ */
+ private final @Nullable DateTimeFormatter dateTimeFormatter;
+ private final @Nullable LocalDate defaultDate;
+ @Builder.Default
+ private final LocalTime defaultTime = LocalTime.MIDNIGHT;
+ @Builder.Default
+ private final ZoneId defaultZoneId = ZoneId.systemDefault();
+
+ /**
+ * @throws DateTimeParseException If value can't be parsed
+ */
+ public Instant parseInstant(String value) {
+ if (isCustomDateTimeFormat()) {
+ return parseCustomFormatInstant(value);
+ }
+ int length = value.length();
+ if (length == 8 || length == 12) { // without and with millis
+ DateTimeFormatter formatter = getConfiguredOrParsedDateTimeFormatter(value);
+ return LocalTime.parse(value, formatter)
+ .atDate(getDefaultDateOrNow())
+ .atZone(defaultZoneId)
+ .toInstant();
+ } else if (length == 10) {
+ DateTimeFormatter formatter = getConfiguredOrParsedDateTimeFormatter(value);
+ return LocalDate.parse(value, formatter)
+ .atTime(defaultTime)
+ .atZone(defaultZoneId)
+ .toInstant();
+ } else if (length == 19 || length == 23) { // without and with millis
+ DateTimeFormatter formatter = getConfiguredOrParsedDateTimeFormatter(value);
+ return LocalDateTime.parse(value, formatter)
+ .atZone(defaultZoneId)
+ .toInstant();
+ } else if (length > 19) {
+ DateTimeFormatter formatter = getConfiguredOrParsedDateTimeFormatter(value);
+ return ZonedDateTime.parse(value, formatter)
+ .toInstant();
+ }
+ throw new DateTimeParseException("Not an instant", value, 0);
+ }
+
+ private boolean isCustomDateTimeFormat() {
+ return dateTimeFormatter != null;
+ }
+
+ private Instant parseCustomFormatInstant(String value) {
+ DateTimeFormatter formatter = getConfiguredOrParsedDateTimeFormatter(value);
+ TemporalAccessor ta = formatter.parse(value);
+ LocalDate localDate = ta.query(TemporalQueries.localDate());
+ if (localDate == null) {
+ localDate = getDefaultDateOrNow();
+ }
+ LocalTime localTime = ta.query(TemporalQueries.localTime());
+ ZoneId zoneId = ta.query(TemporalQueries.zone());
+ return localDate
+ .atTime((localTime == null) ? defaultTime : localTime)
+ .atZone((zoneId == null) ? defaultZoneId : zoneId)
+ .toInstant();
+ }
+
+ private DateTimeFormatter getConfiguredOrParsedDateTimeFormatter(String value) {
+ if (dateTimeFormatter == null) {
+ return DateTimeFormatParser.getDateTimeFormatter(value);
+ }
+ return dateTimeFormatter;
+ }
+
+ private LocalDate getDefaultDateOrNow() {
+ if (defaultDate == null) {
+ return LocalDate.now();
+ }
+ return defaultDate;
+ }
+}
diff --git a/src/main/java/org/spacious_team/table_wrapper/api/MultiLineTableColumn.java b/src/main/java/org/spacious_team/table_wrapper/api/MultiLineTableColumn.java
index d565104..349cee8 100644
--- a/src/main/java/org/spacious_team/table_wrapper/api/MultiLineTableColumn.java
+++ b/src/main/java/org/spacious_team/table_wrapper/api/MultiLineTableColumn.java
@@ -1,6 +1,6 @@
/*
* Table Wrapper API
- * Copyright (C) 2020 Vitalii Ananev
+ * Copyright (C) 2020 Spacious Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -18,10 +18,14 @@
package org.spacious_team.table_wrapper.api;
+import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import java.util.Arrays;
+import java.util.Objects;
+
+import static lombok.AccessLevel.PRIVATE;
/**
* Implements table header kind of
@@ -33,7 +37,8 @@
* Can find index for (Two -> a3 -> b1) column
*/
@ToString
-@RequiredArgsConstructor
+@EqualsAndHashCode
+@RequiredArgsConstructor(access = PRIVATE)
public class MultiLineTableColumn implements TableColumn {
private final TableColumn[] rowDescriptors;
@@ -45,9 +50,11 @@ public static MultiLineTableColumn of(TableColumn... rowDescriptors) {
}
public static MultiLineTableColumn of(String... rowDescriptors) {
- return new MultiLineTableColumn(Arrays.stream(rowDescriptors)
- .map(TableColumnImpl::of)
- .toArray(TableColumn[]::new));
+ TableColumn[] descriptors = Arrays.stream(rowDescriptors)
+ .map(Objects::requireNonNull)
+ .map(PatternTableColumn::of)
+ .toArray(TableColumn[]::new);
+ return new MultiLineTableColumn(descriptors);
}
/**
@@ -56,8 +63,7 @@ public static MultiLineTableColumn of(String... rowDescriptors) {
@Override
public int getColumnIndex(int firstColumnForSearch, ReportPageRow... headerRows) {
if (headerRows.length != rowDescriptors.length) {
- throw new RuntimeException("Внутренняя ошибка, в таблице ожидается " + rowDescriptors.length +
- " строк в заголовке");
+ throw new TableColumnNotFound("Internal error, " + rowDescriptors.length + " rows expected in table header");
}
int columnIndex = firstColumnForSearch;
int i = 0;
diff --git a/src/main/java/org/spacious_team/table_wrapper/api/MutableTableRow.java b/src/main/java/org/spacious_team/table_wrapper/api/MutableTableRow.java
index d5dc9e3..d062e9f 100644
--- a/src/main/java/org/spacious_team/table_wrapper/api/MutableTableRow.java
+++ b/src/main/java/org/spacious_team/table_wrapper/api/MutableTableRow.java
@@ -1,6 +1,6 @@
/*
* Table Wrapper API
- * Copyright (C) 2020 Vitalii Ananev
+ * Copyright (C) 2020 Spacious Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -21,32 +21,52 @@
import lombok.AccessLevel;
import lombok.Data;
import lombok.Setter;
+import lombok.SneakyThrows;
+import org.checkerframework.checker.nullness.qual.Nullable;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDateTime;
+import java.time.ZoneId;
import java.util.Iterator;
+import static java.util.Objects.requireNonNull;
+
/**
* Mutable implementation. Used by {@link AbstractTable#iterator()} and {@link AbstractTable#stream()} to eliminate
- * heap pollution. Use {@link #clone()} for using variable outside iterator or stream.
+ * heap pollution. On each iteration {@link #row} field is updated.
+ *
+ * When {@code MutableTableRow} should be passed to outside iterator or stream, call {@link #clone()} and
+ * use cloned object. Cloned object is safe when used outside iterator or stream, because cloned {@link #row} field
+ * holds its original value when {@link AbstractTable#iterator()} continues to loop.
*/
@Data
-class MutableTableRow implements TableRow {
+class MutableTableRow implements TableRow {
private final Table table;
- private final CellDataAccessObject, T> dao;
+ private final CellDataAccessObject dao;
@Setter(AccessLevel.PACKAGE)
- private volatile T row;
+ private volatile R row;
- public TableCell getCell(TableColumnDescription column) {
+ @Override
+ public @Nullable TableCell getCell(TableHeaderColumn column) {
return getCell(getCellIndex(column));
}
@Override
- public TableCell getCell(int i) {
- return row.getCell(i);
+ public @Nullable TableCell getCell(int i) {
+ @Nullable TableCell cell = row.getCell(i);
+ return updateCellDataAccessObject(cell);
+ }
+
+ private @Nullable TableCell updateCellDataAccessObject(@Nullable TableCell cell) {
+ if (cell instanceof AbstractTableCell) {
+ // hopes, dao is compatible
+ //noinspection unchecked
+ cell = ((AbstractTableCell>) cell).withCellDataAccessObject(dao);
+ }
+ return cell;
}
@Override
@@ -65,85 +85,90 @@ public int getLastCellNum() {
}
@Override
- public boolean rowContains(Object expected) {
+ public boolean rowContains(@Nullable Object expected) {
return row.rowContains(expected);
}
@Override
- public Iterator iterator() {
- return row.iterator();
+ public Iterator<@Nullable TableCell> iterator() {
+ Iterator<@Nullable TableCell> it = row.iterator();
+ return new Iterator<@Nullable TableCell>() {
+ @Override
+ public boolean hasNext() {
+ return it.hasNext();
+ }
+
+ @Override
+ public @Nullable TableCell next() {
+ @Nullable TableCell cell = it.next();
+ return updateCellDataAccessObject(cell);
+ }
+ };
}
- public Object getCellValue(TableColumnDescription column) {
+ @Override
+ public @Nullable Object getCellValue(TableHeaderColumn column) {
return dao.getValue(row, getCellIndex(column));
}
- /**
- * @throws RuntimeException if can't extract int value
- */
- public int getIntCellValue(TableColumnDescription column) {
+ @Override
+ public int getIntCellValue(TableHeaderColumn column) {
return dao.getIntValue(row, getCellIndex(column));
}
- /**
- * @throws RuntimeException if can't extract long value
- */
- public long getLongCellValue(TableColumnDescription column) {
+ @Override
+ public long getLongCellValue(TableHeaderColumn column) {
return dao.getLongValue(row, getCellIndex(column));
}
- /**
- * @throws RuntimeException if can't extract Double value
- */
- public double getDoubleCellValue(TableColumnDescription column) {
+ @Override
+ public double getDoubleCellValue(TableHeaderColumn column) {
return dao.getDoubleValue(row, getCellIndex(column));
}
- /**
- * @throws RuntimeException if can't extract BigDecimal value
- */
- public BigDecimal getBigDecimalCellValue(TableColumnDescription column) {
+ @Override
+ public BigDecimal getBigDecimalCellValue(TableHeaderColumn column) {
return dao.getBigDecimalValue(row, getCellIndex(column));
}
- /**
- * @throws RuntimeException if can't extract string value
- */
- public String getStringCellValue(TableColumnDescription column) {
+ @Override
+ public String getStringCellValue(TableHeaderColumn column) {
return dao.getStringValue(row, getCellIndex(column));
}
- /**
- * @throws RuntimeException if can't extract instant value
- */
- public Instant getInstantCellValue(TableColumnDescription column) {
+ @Override
+ public Instant getInstantCellValue(TableHeaderColumn column) {
return dao.getInstantValue(row, getCellIndex(column));
}
- /**
- * @throws RuntimeException if can't extract local date time value
- */
- public LocalDateTime getLocalDateTimeCellValue(TableColumnDescription column) {
+ @Override
+ public LocalDateTime getLocalDateTimeCellValue(TableHeaderColumn column) {
return dao.getLocalDateTimeValue(row, getCellIndex(column));
}
- private Integer getCellIndex(TableColumnDescription column) {
- return table.getHeaderDescription()
+ @Override
+ public LocalDateTime getLocalDateTimeCellValue(TableHeaderColumn column, ZoneId zoneId) {
+ return dao.getLocalDateTimeValue(row, getCellIndex(column), zoneId);
+ }
+
+ private int getCellIndex(TableHeaderColumn column) {
+ @Nullable Integer cellIndex = table.getHeaderDescription()
.get(column.getColumn());
+ @SuppressWarnings("nullness")
+ int cell = requireNonNull(cellIndex, "Cell is not found");
+ return cell;
}
/**
- * Object is mutable.
- * Clone it if it should be outside table rows loop block, {@link Table#iterator()} or {@link Table#stream()}
+ * This object is mutable.
+ * Clone it if it should be used outside table rows loop block ({@link Table#iterator()} or {@link Table#stream()}).
+ * Cloned object is safe use everywhere, this object should be used oly inside of one iteration
+ * of {@link Table#iterator()} or {@link Table#stream()}
*/
+ @Override
+ @SneakyThrows
@SuppressWarnings("unchecked")
- public MutableTableRow clone() {
- try {
- MutableTableRow tableRow = (MutableTableRow) super.clone();
- tableRow.setRow(row);
- return tableRow;
- } catch (CloneNotSupportedException e) {
- throw new RuntimeException("Can't clone " + this.getClass().getName());
- }
+ public MutableTableRow clone() {
+ return (MutableTableRow) super.clone();
}
}
diff --git a/src/main/java/org/spacious_team/table_wrapper/api/OptionalTableColumn.java b/src/main/java/org/spacious_team/table_wrapper/api/OptionalTableColumn.java
index 61fbed9..6769314 100644
--- a/src/main/java/org/spacious_team/table_wrapper/api/OptionalTableColumn.java
+++ b/src/main/java/org/spacious_team/table_wrapper/api/OptionalTableColumn.java
@@ -1,6 +1,6 @@
/*
* Table Wrapper API
- * Copyright (C) 2020 Vitalii Ananev
+ * Copyright (C) 2020 Spacious Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -18,20 +18,29 @@
package org.spacious_team.table_wrapper.api;
-public class OptionalTableColumn implements TableColumn {
+import lombok.EqualsAndHashCode;
+import lombok.RequiredArgsConstructor;
+import lombok.ToString;
- public static TableColumn of(TableColumn column) {
- return AnyOfTableColumn.of(column, TableColumn.NOCOLUMN);
- }
+import static lombok.AccessLevel.PRIVATE;
+
+@ToString(of = "column")
+@EqualsAndHashCode(of = "column")
+@RequiredArgsConstructor(access = PRIVATE)
+public class OptionalTableColumn implements TableColumn {
+ private final TableColumn column;
+ private final AnyOfTableColumn anyOfTableColumn;
- private OptionalTableColumn() {
+ public static OptionalTableColumn of(TableColumn column) {
+ return new OptionalTableColumn(column, AnyOfTableColumn.of(column, TableColumn.NOCOLUMN));
}
- /**
- * Should never be called
- */
@Override
public int getColumnIndex(int firstColumnForSearch, ReportPageRow... headerRows) {
- return TableColumn.NOCOLUMN_INDEX;
+ try {
+ return anyOfTableColumn.getColumnIndex(firstColumnForSearch, headerRows);
+ } catch (Exception e) {
+ throw new OptionalTableColumnNotFound(e);
+ }
}
}
diff --git a/src/main/java/org/spacious_team/table_wrapper/api/OptionalTableColumnNotFound.java b/src/main/java/org/spacious_team/table_wrapper/api/OptionalTableColumnNotFound.java
new file mode 100644
index 0000000..f7f3f10
--- /dev/null
+++ b/src/main/java/org/spacious_team/table_wrapper/api/OptionalTableColumnNotFound.java
@@ -0,0 +1,26 @@
+/*
+ * Table Wrapper API
+ * Copyright (C) 2022 Spacious Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package org.spacious_team.table_wrapper.api;
+
+public class OptionalTableColumnNotFound extends TableColumnNotFound {
+
+ public OptionalTableColumnNotFound(Throwable t) {
+ super(t);
+ }
+}
diff --git a/src/main/java/org/spacious_team/table_wrapper/api/PatternTableColumn.java b/src/main/java/org/spacious_team/table_wrapper/api/PatternTableColumn.java
new file mode 100644
index 0000000..868c4be
--- /dev/null
+++ b/src/main/java/org/spacious_team/table_wrapper/api/PatternTableColumn.java
@@ -0,0 +1,96 @@
+/*
+ * Table Wrapper API
+ * Copyright (C) 2020 Spacious Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package org.spacious_team.table_wrapper.api;
+
+import lombok.EqualsAndHashCode;
+import lombok.RequiredArgsConstructor;
+import lombok.ToString;
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.Set;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import static java.util.regex.Pattern.*;
+import static lombok.AccessLevel.PRIVATE;
+
+/**
+ * Finds cell column index by case-insensitive checks by all the predefined regexp patterns.
+ */
+@ToString(of = "words")
+@EqualsAndHashCode(of = "words")
+@RequiredArgsConstructor(access = PRIVATE)
+public class PatternTableColumn implements TableColumn {
+ private final Pattern[] patterns;
+ private final Set words;
+
+ /**
+ * Cell text should match to all regexp patterns.
+ */
+ public static TableColumn of(@Nullable String... words) {
+ //noinspection ConstantConditions
+ if (words == null) {
+ return LEFTMOST_COLUMN;
+ }
+ @SuppressWarnings("nullness")
+ Set nonNullWords = Arrays.stream(words)
+ .filter(Objects::nonNull)
+ .filter(s -> !s.isEmpty())
+ .collect(Collectors.toUnmodifiableSet());
+ Pattern[] patterns = nonNullWords.stream()
+ .map(PatternTableColumn::toPattern)
+ .toArray(Pattern[]::new);
+ if (patterns.length == 0) {
+ return LEFTMOST_COLUMN;
+ }
+ return new PatternTableColumn(patterns, nonNullWords);
+ }
+
+ public int getColumnIndex(int firstColumnForSearch, ReportPageRow... headerRows) {
+ for (ReportPageRow header : headerRows) {
+ for (@Nullable TableCell cell : header) {
+ @Nullable Object value;
+ if (cell != null &&
+ cell.getColumnIndex() >= firstColumnForSearch &&
+ (value = cell.getValue()) != null &&
+ value instanceof CharSequence &&
+ matches((CharSequence) value)) {
+ return cell.getColumnIndex();
+ }
+ }
+ }
+ throw new TableColumnNotFound("Header including '" + String.join(", ", words) + "' is not found");
+ }
+
+ private boolean matches(CharSequence cellText) {
+ for (Pattern pattern : patterns) {
+ if (!pattern.matcher(cellText).find()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ private static Pattern toPattern(String pattern) {
+ return Pattern.compile(pattern, CASE_INSENSITIVE | UNICODE_CASE | UNICODE_CHARACTER_CLASS);
+ }
+}
diff --git a/src/main/java/org/spacious_team/table_wrapper/api/RelativePositionTableColumn.java b/src/main/java/org/spacious_team/table_wrapper/api/RelativePositionTableColumn.java
index 1c1dd80..064c680 100644
--- a/src/main/java/org/spacious_team/table_wrapper/api/RelativePositionTableColumn.java
+++ b/src/main/java/org/spacious_team/table_wrapper/api/RelativePositionTableColumn.java
@@ -1,6 +1,6 @@
/*
* Table Wrapper API
- * Copyright (C) 2020 Vitalii Ananev
+ * Copyright (C) 2020 Spacious Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -19,17 +19,19 @@
package org.spacious_team.table_wrapper.api;
+import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
@ToString
+@EqualsAndHashCode
@RequiredArgsConstructor(staticName = "of")
public class RelativePositionTableColumn implements TableColumn {
- private final TableColumn relatedTableColumn;
- private final int relatedOffset;
+ private final TableColumn column;
+ private final int positionOffset;
@Override
public int getColumnIndex(int firstColumnForSearch, ReportPageRow... headerRows) {
- return relatedTableColumn.getColumnIndex(firstColumnForSearch, headerRows) + relatedOffset;
+ return column.getColumnIndex(firstColumnForSearch, headerRows) + positionOffset;
}
}
diff --git a/src/main/java/org/spacious_team/table_wrapper/api/ReportPage.java b/src/main/java/org/spacious_team/table_wrapper/api/ReportPage.java
index 16192fb..8964ee4 100644
--- a/src/main/java/org/spacious_team/table_wrapper/api/ReportPage.java
+++ b/src/main/java/org/spacious_team/table_wrapper/api/ReportPage.java
@@ -1,6 +1,6 @@
/*
* Table Wrapper API
- * Copyright (C) 2020 Vitalii Ananev
+ * Copyright (C) 2020 Spacious Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -18,10 +18,14 @@
package org.spacious_team.table_wrapper.api;
+import org.checkerframework.checker.nullness.qual.Nullable;
+
import java.util.function.Predicate;
+import static java.util.Objects.requireNonNull;
import static org.spacious_team.table_wrapper.api.ReportPageHelper.getCellStringValueIgnoreCasePrefixPredicate;
+@SuppressWarnings({"unused", "UnusedReturnValue"})
public interface ReportPage {
/**
@@ -72,7 +76,7 @@ default TableCellAddress find(Object value, int startRow, int endRow) {
* @param cellValuePredicate predicate for testing cell value
* @return cell address or {@link TableCellAddress#NOT_FOUND}
*/
- default TableCellAddress find(Predicate