ParseErrorStrategy.java

1
/*
2
 * Copyright 2004 the original author or authors.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package com.ancientprogramming.fixedformat4j.io.read;
17
18
import com.ancientprogramming.fixedformat4j.exception.FixedFormatException;
19
import org.slf4j.Logger;
20
import org.slf4j.LoggerFactory;
21
22
/**
23
 * Strategy invoked when a matched line fails to parse into a record object.
24
 *
25
 * <p>Implement this interface to define custom error handling — for example, collecting
26
 * failed lines for a post-processing error report. Two built-in strategies are provided as
27
 * static factory methods: {@link #throwException()} and {@link #skipAndLog()}.</p>
28
 *
29
 * <p>Because this is a {@link FunctionalInterface}, a lambda can be passed wherever a
30
 * {@code ParseErrorStrategy} is expected:</p>
31
 * <pre>{@code
32
 * .parseErrorStrategy((wrapped, line, lineNumber) ->
33
 *     errorList.add("Line " + lineNumber + ": " + wrapped.getMessage()))
34
 * }</pre>
35
 *
36
 * <p>To abort processing on error, throw from the lambda. To skip the line, return normally.</p>
37
 *
38
 * @author Jacob von Eyben - <a href="https://eybenconsult.com">https://eybenconsult.com</a>
39
 * @since 1.8.0
40
 */
41
@FunctionalInterface
42
public interface ParseErrorStrategy {
43
44
  Logger LOG = LoggerFactory.getLogger(ParseErrorStrategy.class);
45
46
  /**
47
   * Handles a line that matched a pattern but could not be parsed into a record object.
48
   *
49
   * <p>Throw a {@link FixedFormatException} to abort processing, or return normally to
50
   * skip the record and continue with the next line.</p>
51
   *
52
   * @param wrapped    a {@link FixedFormatException} wrapping the original parse failure;
53
   *                   the exception message includes the line number
54
   * @param line       the raw content of the line, without any trailing line-ending characters
55
   * @param lineNumber the 1-based line number within the source being read
56
   */
57
  void handle(FixedFormatException wrapped, String line, long lineNumber);
58
59
  /**
60
   * Returns a strategy that rethrows the parse exception immediately (fail-fast).
61
   *
62
   * @return a fail-fast strategy; never {@code null}
63
   */
64
  static ParseErrorStrategy throwException() {
65 1 1. throwException : replaced return value with null for com/ancientprogramming/fixedformat4j/io/read/ParseErrorStrategy::throwException → KILLED
    return (wrapped, line, lineNumber) -> { throw wrapped; };
66
  }
67
68
  /**
69
   * Returns a strategy that skips the line and logs details at WARN level via SLF4J.
70
   * Processing continues with the next line.
71
   *
72
   * <p><strong>Note:</strong> logging only occurs if an SLF4J binding is present on the
73
   * classpath at runtime. If no binding is configured, the warning is silently discarded.
74
   * When guaranteed error visibility is required, use a custom lambda strategy instead.</p>
75
   *
76
   * @return a skip-and-log strategy; never {@code null}
77
   */
78
  static ParseErrorStrategy skipAndLog() {
79 1 1. skipAndLog : replaced return value with null for com/ancientprogramming/fixedformat4j/io/read/ParseErrorStrategy::skipAndLog → KILLED
    return (wrapped, line, lineNumber) ->
80
        LOG.warn("Skipping line {}: {} — {}", lineNumber, line,
81 7 1. lambda$skipAndLog$1 : removed conditional - replaced equality check with false → KILLED
2. lambda$skipAndLog$1 : removed call to com/ancientprogramming/fixedformat4j/exception/FixedFormatException::getMessage → KILLED
3. lambda$skipAndLog$1 : negated conditional → KILLED
4. lambda$skipAndLog$1 : removed call to com/ancientprogramming/fixedformat4j/exception/FixedFormatException::getCause → KILLED
5. lambda$skipAndLog$1 : removed call to java/lang/Throwable::getMessage → KILLED
6. lambda$skipAndLog$1 : removed call to com/ancientprogramming/fixedformat4j/exception/FixedFormatException::getCause → KILLED
7. lambda$skipAndLog$1 : removed conditional - replaced equality check with true → KILLED
            wrapped.getCause() != null ? wrapped.getCause().getMessage() : wrapped.getMessage());
82
  }
83
}

Mutations

65

1.1
Location : throwException
Killed by : com.ancientprogramming.fixedformat4j.io.TestStrategiesAndHandlers.[engine:junit-jupiter]/[class:com.ancientprogramming.fixedformat4j.io.TestStrategiesAndHandlers]/[method:throwExceptionRethrowsSameInstance()]
replaced return value with null for com/ancientprogramming/fixedformat4j/io/read/ParseErrorStrategy::throwException → KILLED

79

1.1
Location : skipAndLog
Killed by : com.ancientprogramming.fixedformat4j.io.TestStrategiesAndHandlers.[engine:junit-jupiter]/[class:com.ancientprogramming.fixedformat4j.io.TestStrategiesAndHandlers]/[method:skipAndLogWithoutCauseLogsWrappedMessage()]
replaced return value with null for com/ancientprogramming/fixedformat4j/io/read/ParseErrorStrategy::skipAndLog → KILLED

81

1.1
Location : lambda$skipAndLog$1
Killed by : com.ancientprogramming.fixedformat4j.io.TestStrategiesAndHandlers.[engine:junit-jupiter]/[class:com.ancientprogramming.fixedformat4j.io.TestStrategiesAndHandlers]/[method:skipAndLogWithCauseLogsCauseMessage()]
removed conditional - replaced equality check with false → KILLED

2.2
Location : lambda$skipAndLog$1
Killed by : com.ancientprogramming.fixedformat4j.io.TestStrategiesAndHandlers.[engine:junit-jupiter]/[class:com.ancientprogramming.fixedformat4j.io.TestStrategiesAndHandlers]/[method:skipAndLogWithoutCauseLogsWrappedMessage()]
removed call to com/ancientprogramming/fixedformat4j/exception/FixedFormatException::getMessage → KILLED

3.3
Location : lambda$skipAndLog$1
Killed by : com.ancientprogramming.fixedformat4j.io.TestStrategiesAndHandlers.[engine:junit-jupiter]/[class:com.ancientprogramming.fixedformat4j.io.TestStrategiesAndHandlers]/[method:skipAndLogWithoutCauseLogsWrappedMessage()]
negated conditional → KILLED

4.4
Location : lambda$skipAndLog$1
Killed by : com.ancientprogramming.fixedformat4j.io.TestStrategiesAndHandlers.[engine:junit-jupiter]/[class:com.ancientprogramming.fixedformat4j.io.TestStrategiesAndHandlers]/[method:skipAndLogWithCauseLogsCauseMessage()]
removed call to com/ancientprogramming/fixedformat4j/exception/FixedFormatException::getCause → KILLED

5.5
Location : lambda$skipAndLog$1
Killed by : com.ancientprogramming.fixedformat4j.io.TestStrategiesAndHandlers.[engine:junit-jupiter]/[class:com.ancientprogramming.fixedformat4j.io.TestStrategiesAndHandlers]/[method:skipAndLogWithCauseLogsCauseMessage()]
removed call to java/lang/Throwable::getMessage → KILLED

6.6
Location : lambda$skipAndLog$1
Killed by : com.ancientprogramming.fixedformat4j.io.TestStrategiesAndHandlers.[engine:junit-jupiter]/[class:com.ancientprogramming.fixedformat4j.io.TestStrategiesAndHandlers]/[method:skipAndLogWithCauseLogsCauseMessage()]
removed call to com/ancientprogramming/fixedformat4j/exception/FixedFormatException::getCause → KILLED

7.7
Location : lambda$skipAndLog$1
Killed by : com.ancientprogramming.fixedformat4j.io.TestStrategiesAndHandlers.[engine:junit-jupiter]/[class:com.ancientprogramming.fixedformat4j.io.TestStrategiesAndHandlers]/[method:skipAndLogWithoutCauseLogsWrappedMessage()]
removed conditional - replaced equality check with true → KILLED

Active mutators

Tests examined


Report generated by PIT 1.23.1 support