Преглед изворни кода

Replace Error Consumer everywhere.

Dominik Fuchß пре 4 година
родитељ
комит
dd72088414
34 измењених фајлова са 460 додато и 665 уклоњено
  1. 1 2
      jplag.cli/src/main/java/de/jplag/CLI.java
  2. 262 264
      jplag.cli/src/main/java/de/jplag/logger/CollectedLogger.java
  3. 31 33
      jplag.cli/src/main/java/de/jplag/logger/CollectedLoggerFactory.java
  4. 1 1
      jplag.cli/src/main/java/de/jplag/logger/Triple.java
  5. 46 56
      jplag.cli/src/main/java/org/slf4j/impl/StaticLoggerBinder.java
  6. 0 28
      jplag.frontend-testutils/src/test/java/de/jplag/testutils/TestErrorConsumer.java
  7. 6 16
      jplag.frontend-utils/src/main/java/de/jplag/AbstractParser.java
  8. 0 20
      jplag.frontend-utils/src/main/java/de/jplag/ErrorConsumer.java
  9. 2 3
      jplag.frontend.chars/src/main/java/de/jplag/chars/Language.java
  10. 7 14
      jplag.frontend.chars/src/main/java/de/jplag/chars/Parser.java
  11. 2 3
      jplag.frontend.cpp/src/main/java/de/jplag/cpp/Language.java
  12. 3 5
      jplag.frontend.cpp/src/main/java/de/jplag/cpp/Scanner.java
  13. 2 2
      jplag.frontend.cpp/src/main/javacc/CPP.jj
  14. 3 5
      jplag.frontend.csharp-6/src/main/java/de/jplag/csharp/CSharpParserAdapter.java
  15. 2 3
      jplag.frontend.csharp-6/src/main/java/de/jplag/csharp/Language.java
  16. 1 3
      jplag.frontend.csharp-6/src/test/java/de/jplag/csharp/MinimalCSharpFrontendTest.java
  17. 6 9
      jplag.frontend.java/src/main/java/de/jplag/java/JavacAdapter.java
  18. 2 3
      jplag.frontend.java/src/main/java/de/jplag/java/Language.java
  19. 3 7
      jplag.frontend.java/src/main/java/de/jplag/java/Parser.java
  20. 2 3
      jplag.frontend.python-3/src/main/java/de/jplag/python3/Language.java
  21. 7 8
      jplag.frontend.python-3/src/main/java/de/jplag/python3/Parser.java
  22. 2 3
      jplag.frontend.rlang/src/main/java/de/jplag/rlang/Language.java
  23. 3 5
      jplag.frontend.rlang/src/main/java/de/jplag/rlang/RParserAdapter.java
  24. 2 4
      jplag.frontend.rlang/src/test/java/de/jplag/rlang/RFrontendTest.java
  25. 2 3
      jplag.frontend.scheme/src/main/java/de/jplag/scheme/Language.java
  26. 6 8
      jplag.frontend.scheme/src/main/java/de/jplag/scheme/Parser.java
  27. 2 2
      jplag.frontend.scheme/src/main/javacc/Scheme.jj
  28. 2 4
      jplag.frontend.text/src/main/java/de/jplag/text/Language.java
  29. 6 14
      jplag.frontend.text/src/main/java/de/jplag/text/Parser.java
  30. 0 79
      jplag/src/main/java/de/jplag/ErrorCollector.java
  31. 10 14
      jplag/src/main/java/de/jplag/JPlag.java
  32. 12 9
      jplag/src/main/java/de/jplag/Submission.java
  33. 21 26
      jplag/src/main/java/de/jplag/SubmissionSet.java
  34. 3 6
      jplag/src/main/java/de/jplag/SubmissionSetBuilder.java

+ 1 - 2
jplag.cli/src/main/java/de/jplag/CLI.java

@@ -7,7 +7,6 @@ import java.util.List;
 import java.util.Optional;
 import java.util.Random;
 
-import de.jplag.exceptions.RootDirectoryException;
 import net.sourceforge.argparse4j.ArgumentParsers;
 import net.sourceforge.argparse4j.inf.ArgumentParser;
 import net.sourceforge.argparse4j.inf.ArgumentParserException;
@@ -21,6 +20,7 @@ import de.jplag.clustering.ClusteringOptions;
 import de.jplag.clustering.Preprocessing;
 import de.jplag.clustering.algorithm.InterClusterSimilarity;
 import de.jplag.exceptions.ExitException;
+import de.jplag.logger.CollectedLogger;
 import de.jplag.options.JPlagOptions;
 import de.jplag.options.LanguageOption;
 import de.jplag.options.SimilarityMetric;
@@ -28,7 +28,6 @@ import de.jplag.options.Verbosity;
 import de.jplag.reporting.JsonReport;
 import de.jplag.reporting.Report;
 import de.jplag.strategy.ComparisonMode;
-import de.jplag.logger.CollectedLogger;
 
 /**
  * Command line interface class, allows using via command line.

+ 262 - 264
jplag.cli/src/main/java/de/jplag/logger/CollectedLogger.java

@@ -1,10 +1,5 @@
 package de.jplag.logger;
 
-import org.slf4j.helpers.FormattingTuple;
-import org.slf4j.helpers.MarkerIgnoringBase;
-import org.slf4j.helpers.MessageFormatter;
-import org.slf4j.spi.LocationAwareLogger;
-
 import java.io.PrintStream;
 import java.io.Serial;
 import java.text.SimpleDateFormat;
@@ -13,268 +8,271 @@ import java.util.Date;
 import java.util.List;
 import java.util.concurrent.ConcurrentLinkedDeque;
 
+import org.slf4j.helpers.FormattingTuple;
+import org.slf4j.helpers.MarkerIgnoringBase;
+import org.slf4j.helpers.MessageFormatter;
+import org.slf4j.spi.LocationAwareLogger;
+
 /**
- * This logger is able to collect errors and print them at the end.
- * Mainly adopted from org.slf4j.impl.SimpleLogger
- *
+ * This logger is able to collect errors and print them at the end. Mainly adopted from org.slf4j.impl.SimpleLogger
  * @author Dominik Fuchss
  */
 public final class CollectedLogger extends MarkerIgnoringBase {
 
-	private static final ConcurrentLinkedDeque<CollectedLogger> instances = new ConcurrentLinkedDeque<>();
-
-	public static void finalizeInstances() {
-		List<CollectedLogger> copy = new ArrayList<>(instances);
-		copy.forEach(instances::remove);
-		copy.forEach(CollectedLogger::printAllErrorsForLogger);
-	}
-
-	@Serial
-	private static final long serialVersionUID = -1278670638921140275L;
-
-	private static final int LOG_LEVEL_TRACE = LocationAwareLogger.TRACE_INT;
-	private static final int LOG_LEVEL_DEBUG = LocationAwareLogger.DEBUG_INT;
-	private static final int LOG_LEVEL_INFO = LocationAwareLogger.INFO_INT;
-	private static final int LOG_LEVEL_WARN = LocationAwareLogger.WARN_INT;
-	private static final int LOG_LEVEL_ERROR = LocationAwareLogger.ERROR_INT;
-
-	private final int currentLogLevel = LOG_LEVEL_INFO;
-
-	/**
-	 * The short name of this simple log instance
-	 */
-	private transient String shortLogName = null;
-
-	/**
-	 * Indicator whether finalization is in progress.
-	 * @see #printAllErrorsForLogger()
-	 */
-	private transient boolean isFinalizing = false;
-
-	private final transient SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-hh:mm:ss_SSS");
-
-	private final ConcurrentLinkedDeque<Triple<String, Throwable, Date>> allErrors = new ConcurrentLinkedDeque<>();
-
-	CollectedLogger(String name) {
-		this.name = name;
-		instances.add(this);
-	}
-
-	private void log(int level, String message, Throwable t) {
-		log(level, message, t, null);
-	}
-
-	private void log(int level, String message, Throwable t, Date timeOfError) {
-		if (!isLevelEnabled(level)) {
-			return;
-		}
-
-		if (level == LOG_LEVEL_ERROR && !isFinalizing) {
-			// Buffer errors for the final output
-			allErrors.add(new Triple<>(message, t, new Date()));
-			return;
-		}
-
-		StringBuilder buf = new StringBuilder(32);
-
-		// Append date-time
-		buf.append(sdf.format(timeOfError == null ? new Date() : timeOfError)).append(' ');
-
-		// Append current thread name
-		buf.append('[').append(Thread.currentThread().getName()).append("] ");
-		// Append current Level
-		buf.append('[').append(renderLevel(level)).append(']').append(' ');
-
-		// Append the name of the log instance
-		if (shortLogName == null)
-			shortLogName = computeShortName();
-		buf.append(shortLogName).append(" - ");
-		// Append the message
-		buf.append(message);
-
-		write(buf, t);
-	}
-
-	private void printAllErrorsForLogger() {
-		this.isFinalizing = true;
-		// Copy errors to prevent infinite recursion
-		var errors = new ArrayList<>(this.allErrors);
-		if (errors.isEmpty())
-			return;
-
-		info("Summary of all Errors:");
-		errors.forEach(error -> log(LOG_LEVEL_ERROR, error.first(), error.second(), error.third()));
-		isFinalizing = false;
-	}
-
-	@SuppressWarnings("java:S106")
-	void write(StringBuilder buf, Throwable t) {
-		PrintStream targetStream = System.out;
-
-		targetStream.println(buf.toString());
-		writeThrowable(t, targetStream);
-		targetStream.flush();
-	}
-
-	private void writeThrowable(Throwable t, PrintStream targetStream) {
-		if (t != null) {
-			t.printStackTrace(targetStream);
-		}
-	}
-
-	private String computeShortName() {
-		return name.substring(name.lastIndexOf(".") + 1);
-	}
-
-	private boolean isLevelEnabled(int logLevel) {
-		return logLevel >= currentLogLevel;
-	}
-
-	private String renderLevel(int level) {
-		return switch (level) {
-			case LOG_LEVEL_TRACE -> "TRACE";
-			case LOG_LEVEL_DEBUG -> "DEBUG";
-			case LOG_LEVEL_INFO -> "INFO";
-			case LOG_LEVEL_WARN -> "WARN";
-			case LOG_LEVEL_ERROR -> "ERROR";
-			default -> throw new IllegalStateException("Unrecognized level [" + level + "]");
-		};
-	}
-
-	public boolean isTraceEnabled() {
-		return isLevelEnabled(LOG_LEVEL_TRACE);
-	}
-
-	@Override
-	public void trace(String msg) {
-		log(LOG_LEVEL_TRACE, msg, null);
-	}
-
-	public void trace(String format, Object param1) {
-		formatAndLog(LOG_LEVEL_TRACE, format, param1, null);
-	}
-
-	public void trace(String format, Object param1, Object param2) {
-		formatAndLog(LOG_LEVEL_TRACE, format, param1, param2);
-	}
-
-	public void trace(String format, Object... argArray) {
-		formatAndLog(LOG_LEVEL_TRACE, format, argArray);
-	}
-
-	public void trace(String msg, Throwable t) {
-		log(LOG_LEVEL_TRACE, msg, t);
-	}
-
-	public boolean isDebugEnabled() {
-		return isLevelEnabled(LOG_LEVEL_DEBUG);
-	}
-
-	public void debug(String msg) {
-		log(LOG_LEVEL_DEBUG, msg, null);
-	}
-
-	public void debug(String format, Object param1) {
-		formatAndLog(LOG_LEVEL_DEBUG, format, param1, null);
-	}
-
-	public void debug(String format, Object param1, Object param2) {
-		formatAndLog(LOG_LEVEL_DEBUG, format, param1, param2);
-	}
-
-	public void debug(String format, Object... argArray) {
-		formatAndLog(LOG_LEVEL_DEBUG, format, argArray);
-	}
-
-	public void debug(String msg, Throwable t) {
-		log(LOG_LEVEL_DEBUG, msg, t);
-	}
-
-	public boolean isInfoEnabled() {
-		return isLevelEnabled(LOG_LEVEL_INFO);
-	}
-
-	public void info(String msg) {
-		log(LOG_LEVEL_INFO, msg, null);
-	}
-
-	public void info(String format, Object arg) {
-		formatAndLog(LOG_LEVEL_INFO, format, arg, null);
-	}
-
-	public void info(String format, Object arg1, Object arg2) {
-		formatAndLog(LOG_LEVEL_INFO, format, arg1, arg2);
-	}
-
-	public void info(String format, Object... argArray) {
-		formatAndLog(LOG_LEVEL_INFO, format, argArray);
-	}
-
-	public void info(String msg, Throwable t) {
-		log(LOG_LEVEL_INFO, msg, t);
-	}
-
-	public boolean isWarnEnabled() {
-		return isLevelEnabled(LOG_LEVEL_WARN);
-	}
-
-	public void warn(String msg) {
-		log(LOG_LEVEL_WARN, msg, null);
-	}
-
-	public void warn(String format, Object arg) {
-		formatAndLog(LOG_LEVEL_WARN, format, arg, null);
-	}
-
-	public void warn(String format, Object arg1, Object arg2) {
-		formatAndLog(LOG_LEVEL_WARN, format, arg1, arg2);
-	}
-
-	public void warn(String format, Object... argArray) {
-		formatAndLog(LOG_LEVEL_WARN, format, argArray);
-	}
-
-	public void warn(String msg, Throwable t) {
-		log(LOG_LEVEL_WARN, msg, t);
-	}
-
-	public boolean isErrorEnabled() {
-		return isLevelEnabled(LOG_LEVEL_ERROR);
-	}
-
-	public void error(String msg) {
-		log(LOG_LEVEL_ERROR, msg, null);
-	}
-
-	public void error(String format, Object arg) {
-		formatAndLog(LOG_LEVEL_ERROR, format, arg, null);
-	}
-
-	public void error(String format, Object arg1, Object arg2) {
-		formatAndLog(LOG_LEVEL_ERROR, format, arg1, arg2);
-	}
-
-	public void error(String format, Object... argArray) {
-		formatAndLog(LOG_LEVEL_ERROR, format, argArray);
-	}
-
-	public void error(String msg, Throwable t) {
-		log(LOG_LEVEL_ERROR, msg, t);
-	}
-
-	private void formatAndLog(int level, String format, Object arg1, Object arg2) {
-		if (!isLevelEnabled(level)) {
-			return;
-		}
-		FormattingTuple tp = MessageFormatter.format(format, arg1, arg2);
-		log(level, tp.getMessage(), tp.getThrowable());
-	}
-
-	private void formatAndLog(int level, String format, Object... arguments) {
-		if (!isLevelEnabled(level)) {
-			return;
-		}
-		FormattingTuple tp = MessageFormatter.arrayFormat(format, arguments);
-		log(level, tp.getMessage(), tp.getThrowable());
-	}
+    private static final ConcurrentLinkedDeque<CollectedLogger> instances = new ConcurrentLinkedDeque<>();
+
+    public static void finalizeInstances() {
+        List<CollectedLogger> copy = new ArrayList<>(instances);
+        copy.forEach(instances::remove);
+        copy.forEach(CollectedLogger::printAllErrorsForLogger);
+    }
+
+    @Serial
+    private static final long serialVersionUID = -1278670638921140275L;
+
+    private static final int LOG_LEVEL_TRACE = LocationAwareLogger.TRACE_INT;
+    private static final int LOG_LEVEL_DEBUG = LocationAwareLogger.DEBUG_INT;
+    private static final int LOG_LEVEL_INFO = LocationAwareLogger.INFO_INT;
+    private static final int LOG_LEVEL_WARN = LocationAwareLogger.WARN_INT;
+    private static final int LOG_LEVEL_ERROR = LocationAwareLogger.ERROR_INT;
+
+    private final int currentLogLevel = LOG_LEVEL_INFO;
+
+    /**
+     * The short name of this simple log instance
+     */
+    private transient String shortLogName = null;
+
+    /**
+     * Indicator whether finalization is in progress.
+     * @see #printAllErrorsForLogger()
+     */
+    private transient boolean isFinalizing = false;
+
+    private final transient SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-hh:mm:ss_SSS");
+
+    private final ConcurrentLinkedDeque<Triple<String, Throwable, Date>> allErrors = new ConcurrentLinkedDeque<>();
+
+    CollectedLogger(String name) {
+        this.name = name;
+        instances.add(this);
+    }
+
+    private void log(int level, String message, Throwable t) {
+        log(level, message, t, null);
+    }
+
+    private void log(int level, String message, Throwable t, Date timeOfError) {
+        if (!isLevelEnabled(level)) {
+            return;
+        }
+
+        if (level == LOG_LEVEL_ERROR && !isFinalizing) {
+            // Buffer errors for the final output
+            allErrors.add(new Triple<>(message, t, new Date()));
+            return;
+        }
+
+        StringBuilder buf = new StringBuilder(32);
+
+        // Append date-time
+        buf.append(sdf.format(timeOfError == null ? new Date() : timeOfError)).append(' ');
+
+        // Append current thread name
+        buf.append('[').append(Thread.currentThread().getName()).append("] ");
+        // Append current Level
+        buf.append('[').append(renderLevel(level)).append(']').append(' ');
+
+        // Append the name of the log instance
+        if (shortLogName == null)
+            shortLogName = computeShortName();
+        buf.append(shortLogName).append(" - ");
+        // Append the message
+        buf.append(message);
+
+        write(buf, t);
+    }
+
+    private void printAllErrorsForLogger() {
+        this.isFinalizing = true;
+        // Copy errors to prevent infinite recursion
+        var errors = new ArrayList<>(this.allErrors);
+        if (errors.isEmpty())
+            return;
+
+        info("Summary of all Errors:");
+        errors.forEach(error -> log(LOG_LEVEL_ERROR, error.first(), error.second(), error.third()));
+        isFinalizing = false;
+    }
+
+    @SuppressWarnings("java:S106")
+    void write(StringBuilder buf, Throwable t) {
+        PrintStream targetStream = System.out;
+
+        targetStream.println(buf.toString());
+        writeThrowable(t, targetStream);
+        targetStream.flush();
+    }
+
+    private void writeThrowable(Throwable t, PrintStream targetStream) {
+        if (t != null) {
+            t.printStackTrace(targetStream);
+        }
+    }
+
+    private String computeShortName() {
+        return name.substring(name.lastIndexOf(".") + 1);
+    }
+
+    private boolean isLevelEnabled(int logLevel) {
+        return logLevel >= currentLogLevel;
+    }
+
+    private String renderLevel(int level) {
+        return switch (level) {
+            case LOG_LEVEL_TRACE -> "TRACE";
+            case LOG_LEVEL_DEBUG -> "DEBUG";
+            case LOG_LEVEL_INFO -> "INFO";
+            case LOG_LEVEL_WARN -> "WARN";
+            case LOG_LEVEL_ERROR -> "ERROR";
+            default -> throw new IllegalStateException("Unrecognized level [" + level + "]");
+        };
+    }
+
+    public boolean isTraceEnabled() {
+        return isLevelEnabled(LOG_LEVEL_TRACE);
+    }
+
+    @Override
+    public void trace(String msg) {
+        log(LOG_LEVEL_TRACE, msg, null);
+    }
+
+    public void trace(String format, Object param1) {
+        formatAndLog(LOG_LEVEL_TRACE, format, param1, null);
+    }
+
+    public void trace(String format, Object param1, Object param2) {
+        formatAndLog(LOG_LEVEL_TRACE, format, param1, param2);
+    }
+
+    public void trace(String format, Object... argArray) {
+        formatAndLog(LOG_LEVEL_TRACE, format, argArray);
+    }
+
+    public void trace(String msg, Throwable t) {
+        log(LOG_LEVEL_TRACE, msg, t);
+    }
+
+    public boolean isDebugEnabled() {
+        return isLevelEnabled(LOG_LEVEL_DEBUG);
+    }
+
+    public void debug(String msg) {
+        log(LOG_LEVEL_DEBUG, msg, null);
+    }
+
+    public void debug(String format, Object param1) {
+        formatAndLog(LOG_LEVEL_DEBUG, format, param1, null);
+    }
+
+    public void debug(String format, Object param1, Object param2) {
+        formatAndLog(LOG_LEVEL_DEBUG, format, param1, param2);
+    }
+
+    public void debug(String format, Object... argArray) {
+        formatAndLog(LOG_LEVEL_DEBUG, format, argArray);
+    }
+
+    public void debug(String msg, Throwable t) {
+        log(LOG_LEVEL_DEBUG, msg, t);
+    }
+
+    public boolean isInfoEnabled() {
+        return isLevelEnabled(LOG_LEVEL_INFO);
+    }
+
+    public void info(String msg) {
+        log(LOG_LEVEL_INFO, msg, null);
+    }
+
+    public void info(String format, Object arg) {
+        formatAndLog(LOG_LEVEL_INFO, format, arg, null);
+    }
+
+    public void info(String format, Object arg1, Object arg2) {
+        formatAndLog(LOG_LEVEL_INFO, format, arg1, arg2);
+    }
+
+    public void info(String format, Object... argArray) {
+        formatAndLog(LOG_LEVEL_INFO, format, argArray);
+    }
+
+    public void info(String msg, Throwable t) {
+        log(LOG_LEVEL_INFO, msg, t);
+    }
+
+    public boolean isWarnEnabled() {
+        return isLevelEnabled(LOG_LEVEL_WARN);
+    }
+
+    public void warn(String msg) {
+        log(LOG_LEVEL_WARN, msg, null);
+    }
+
+    public void warn(String format, Object arg) {
+        formatAndLog(LOG_LEVEL_WARN, format, arg, null);
+    }
+
+    public void warn(String format, Object arg1, Object arg2) {
+        formatAndLog(LOG_LEVEL_WARN, format, arg1, arg2);
+    }
+
+    public void warn(String format, Object... argArray) {
+        formatAndLog(LOG_LEVEL_WARN, format, argArray);
+    }
+
+    public void warn(String msg, Throwable t) {
+        log(LOG_LEVEL_WARN, msg, t);
+    }
+
+    public boolean isErrorEnabled() {
+        return isLevelEnabled(LOG_LEVEL_ERROR);
+    }
+
+    public void error(String msg) {
+        log(LOG_LEVEL_ERROR, msg, null);
+    }
+
+    public void error(String format, Object arg) {
+        formatAndLog(LOG_LEVEL_ERROR, format, arg, null);
+    }
+
+    public void error(String format, Object arg1, Object arg2) {
+        formatAndLog(LOG_LEVEL_ERROR, format, arg1, arg2);
+    }
+
+    public void error(String format, Object... argArray) {
+        formatAndLog(LOG_LEVEL_ERROR, format, argArray);
+    }
+
+    public void error(String msg, Throwable t) {
+        log(LOG_LEVEL_ERROR, msg, t);
+    }
+
+    private void formatAndLog(int level, String format, Object arg1, Object arg2) {
+        if (!isLevelEnabled(level)) {
+            return;
+        }
+        FormattingTuple tp = MessageFormatter.format(format, arg1, arg2);
+        log(level, tp.getMessage(), tp.getThrowable());
+    }
+
+    private void formatAndLog(int level, String format, Object... arguments) {
+        if (!isLevelEnabled(level)) {
+            return;
+        }
+        FormattingTuple tp = MessageFormatter.arrayFormat(format, arguments);
+        log(level, tp.getMessage(), tp.getThrowable());
+    }
 }

+ 31 - 33
jplag.cli/src/main/java/de/jplag/logger/CollectedLoggerFactory.java

@@ -1,48 +1,46 @@
 package de.jplag.logger;
 
-import org.slf4j.ILoggerFactory;
-import org.slf4j.Logger;
-
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
+import org.slf4j.ILoggerFactory;
+import org.slf4j.Logger;
+
 /**
  * The factory for {@link CollectedLogger}.
- *
  * @author Dominik Fuchss
  */
 public final class CollectedLoggerFactory implements ILoggerFactory {
 
-	private final ConcurrentMap<String, Logger> loggerMap;
+    private final ConcurrentMap<String, Logger> loggerMap;
 
-	public CollectedLoggerFactory() {
-		loggerMap = new ConcurrentHashMap<>();
-	}
+    public CollectedLoggerFactory() {
+        loggerMap = new ConcurrentHashMap<>();
+    }
 
-	/**
-	 * Return an appropriate {@link CollectedLogger} instance by name.
-	 */
-	public Logger getLogger(String name) {
-		Logger simpleLogger = loggerMap.get(name);
-		if (simpleLogger != null) {
-			return simpleLogger;
-		} else {
-			Logger newInstance = new CollectedLogger(name);
-			Logger oldInstance = loggerMap.putIfAbsent(name, newInstance);
-			return oldInstance == null ? newInstance : oldInstance;
-		}
-	}
+    /**
+     * Return an appropriate {@link CollectedLogger} instance by name.
+     */
+    public Logger getLogger(String name) {
+        Logger simpleLogger = loggerMap.get(name);
+        if (simpleLogger != null) {
+            return simpleLogger;
+        } else {
+            Logger newInstance = new CollectedLogger(name);
+            Logger oldInstance = loggerMap.putIfAbsent(name, newInstance);
+            return oldInstance == null ? newInstance : oldInstance;
+        }
+    }
 
-	/**
-	 * Clear the internal logger cache.
-	 * <p>
-	 * This method is intended to be called by classes (in the same package) for
-	 * testing purposes. This method is internal. It can be modified, renamed or
-	 * removed at any time without notice.
-	 * <p>
-	 * You are strongly discouraged from calling this method in production code.
-	 */
-	void reset() {
-		loggerMap.clear();
-	}
+    /**
+     * Clear the internal logger cache.
+     * <p>
+     * This method is intended to be called by classes (in the same package) for testing purposes. This method is internal.
+     * It can be modified, renamed or removed at any time without notice.
+     * <p>
+     * You are strongly discouraged from calling this method in production code.
+     */
+    void reset() {
+        loggerMap.clear();
+    }
 }

+ 1 - 1
jplag.cli/src/main/java/de/jplag/logger/Triple.java

@@ -1,4 +1,4 @@
 package de.jplag.logger;
 
-public record Triple<A, B, C>(A first, B second, C third) {
+public record Triple<A, B, C> (A first, B second, C third) {
 }

+ 46 - 56
jplag.cli/src/main/java/org/slf4j/impl/StaticLoggerBinder.java

@@ -1,80 +1,70 @@
 /**
- * Copyright (c) 2004-2011 QOS.ch
- * All rights reserved.
+ * Copyright (c) 2004-2011 QOS.ch All rights reserved.
  * <p>
- * Permission is hereby granted, free  of charge, to any person obtaining
- * a  copy  of this  software  and  associated  documentation files  (the
- * "Software"), to  deal in  the Software without  restriction, including
- * without limitation  the rights to  use, copy, modify,  merge, publish,
- * distribute,  sublicense, and/or sell  copies of  the Software,  and to
- * permit persons to whom the Software  is furnished to do so, subject to
- * the following conditions:
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to the following conditions:
  * <p>
- * The  above  copyright  notice  and  this permission  notice  shall  be
- * included in all copies or substantial portions of the Software.
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
+ * Software.
  * <p>
- * THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
- * EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
- * MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 package org.slf4j.impl;
 
-import de.jplag.logger.CollectedLoggerFactory;
 import org.slf4j.ILoggerFactory;
 import org.slf4j.LoggerFactory;
 import org.slf4j.spi.LoggerFactoryBinder;
 
+import de.jplag.logger.CollectedLoggerFactory;
+
 /**
- * The binding of {@link LoggerFactory} class with an actual instance of
- * {@link ILoggerFactory} is performed using information returned by this class.
- * The class has been adopted from SimpleLogger.
- *
+ * The binding of {@link LoggerFactory} class with an actual instance of {@link ILoggerFactory} is performed using
+ * information returned by this class. The class has been adopted from SimpleLogger.
  * @author Dominik Fuchss
  */
 public class StaticLoggerBinder implements LoggerFactoryBinder {
 
-	/**
-	 * The unique instance of this class.
-	 */
-	private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();
+    /**
+     * The unique instance of this class.
+     */
+    private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();
 
-	/**
-	 * Return the singleton of this class.
-	 *
-	 * @return the StaticLoggerBinder singleton
-	 */
-	public static StaticLoggerBinder getSingleton() {
-		return SINGLETON;
-	}
+    /**
+     * Return the singleton of this class.
+     * @return the StaticLoggerBinder singleton
+     */
+    public static StaticLoggerBinder getSingleton() {
+        return SINGLETON;
+    }
 
-	/**
-	 * Declare the version of the SLF4J API this implementation is compiled against.
-	 * The value of this field is modified with each major release.
-	 */
-	// to avoid constant folding by the compiler, this field must *not* be final
-	public static String REQUESTED_API_VERSION = "1.6.99"; // !final
+    /**
+     * Declare the version of the SLF4J API this implementation is compiled against. The value of this field is modified
+     * with each major release.
+     */
+    // to avoid constant folding by the compiler, this field must *not* be final
+    public static String REQUESTED_API_VERSION = "1.6.99"; // !final
 
-	private static final String loggerFactoryClassStr = CollectedLoggerFactory.class.getName();
+    private static final String loggerFactoryClassStr = CollectedLoggerFactory.class.getName();
 
-	/**
-	 * The ILoggerFactory instance returned by the {@link #getLoggerFactory}
-	 * method should always be the same object
-	 */
-	private final ILoggerFactory loggerFactory;
+    /**
+     * The ILoggerFactory instance returned by the {@link #getLoggerFactory} method should always be the same object
+     */
+    private final ILoggerFactory loggerFactory;
 
-	private StaticLoggerBinder() {
-		loggerFactory = new CollectedLoggerFactory();
-	}
+    private StaticLoggerBinder() {
+        loggerFactory = new CollectedLoggerFactory();
+    }
 
-	public ILoggerFactory getLoggerFactory() {
-		return loggerFactory;
-	}
+    public ILoggerFactory getLoggerFactory() {
+        return loggerFactory;
+    }
 
-	public String getLoggerFactoryClassStr() {
-		return loggerFactoryClassStr;
-	}
+    public String getLoggerFactoryClassStr() {
+        return loggerFactoryClassStr;
+    }
 }

+ 0 - 28
jplag.frontend-testutils/src/test/java/de/jplag/testutils/TestErrorConsumer.java

@@ -1,28 +0,0 @@
-package de.jplag.testutils;
-
-import static org.junit.jupiter.api.Assertions.fail;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import de.jplag.ErrorConsumer;
-
-/**
- * Mock error consumer that fails the test case on error occurrence.
- * @author Timur Saglam
- */
-public class TestErrorConsumer implements ErrorConsumer {
-    private final Logger logger = LoggerFactory.getLogger("JPlag-Test");
-
-    @Override
-    public void addError(String errorMessage) {
-        logger.error(errorMessage);
-        fail(errorMessage);
-    }
-
-    @Override
-    public void print(String message, String longMessage) {
-        logger.info(message);
-    }
-
-}

+ 6 - 16
jplag.frontend-utils/src/main/java/de/jplag/AbstractParser.java

@@ -1,15 +1,18 @@
 package de.jplag;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 /**
  * Abstract parser class. Counts errors and manages an error consumer.
  * @author Emeric Kwemou
  */
 public abstract class AbstractParser {
-    protected ErrorConsumer errorConsumer;
     protected int errors = 0;
+    public final Logger logger;
 
-    public AbstractParser(ErrorConsumer errorConsumer) {
-        this.errorConsumer = errorConsumer;
+    protected AbstractParser() {
+        this.logger = LoggerFactory.getLogger(this.getClass());
     }
 
     /**
@@ -18,17 +21,4 @@ public abstract class AbstractParser {
     public boolean hasErrors() {
         return errors != 0;
     }
-
-    /**
-     * @return the error consumer that collects and prints errors.
-     */
-    public ErrorConsumer getErrorConsumer() {
-        return errorConsumer;
-    }
-
-    /**
-     * Setter for the error consumer that collects and prints errors.
-     * @param errorConsumer is the consumer to set.
-     */
-
 }

+ 0 - 20
jplag.frontend-utils/src/main/java/de/jplag/ErrorConsumer.java

@@ -1,20 +0,0 @@
-package de.jplag;
-
-/**
- * Consumes errors from a language parser.
- */
-public interface ErrorConsumer {
-
-    /**
-     * Adds an error to the error stack. The error is only printed directly when using the corresponding verbosity option.
-     * @param errorMessage is the error message.
-     */
-    void addError(String errorMessage);
-
-    /**
-     * Prints a message depending on the verbosity.
-     * @param message is the message for the normal mode.
-     * @param longMessage is the message for verbose mode.
-     */
-    void print(String message, String longMessage);
-}

+ 2 - 3
jplag.frontend.chars/src/main/java/de/jplag/chars/Language.java

@@ -2,7 +2,6 @@ package de.jplag.chars;
 
 import java.io.File;
 
-import de.jplag.ErrorConsumer;
 import de.jplag.TokenList;
 
 /*
@@ -12,8 +11,8 @@ public class Language implements de.jplag.Language {
 
     private final Parser parser;
 
-    public Language(ErrorConsumer program) {
-        parser = new Parser(program);
+    public Language() {
+        parser = new Parser();
     }
 
     @Override

+ 7 - 14
jplag.frontend.chars/src/main/java/de/jplag/chars/Parser.java

@@ -5,7 +5,6 @@ import java.io.FileReader;
 import java.nio.charset.StandardCharsets;
 
 import de.jplag.AbstractParser;
-import de.jplag.ErrorConsumer;
 import de.jplag.TokenConstants;
 import de.jplag.TokenList;
 
@@ -15,25 +14,24 @@ public class Parser extends AbstractParser {
 
     /**
      * Creates the parser.
-     * @param errorConsumer is the consumer for any occurring errors.
      */
-    public Parser(ErrorConsumer errorConsumer) {
-        super(errorConsumer);
+    public Parser() {
+        super();
     }
 
     public TokenList parse(File directory, String[] files) {
         tokens = new TokenList();
         errors = 0;
         for (String file : files) {
-            getErrorConsumer().print(null, "Parsing file " + file);
+            logger.trace("Parsing file {}", file);
             if (!parseFile(directory, file))
                 errors++;
             tokens.addToken(new CharToken(TokenConstants.FILE_END, file, this));
         }
         if (errors == 0)
-            errorConsumer.print(null, "OK");
+            logger.trace("OK");
         else
-            errorConsumer.print(null, errors + " ERROR" + (errors > 1 ? "S" : ""));
+            logger.error(errors + " ERROR" + (errors > 1 ? "S" : ""));
 
         return tokens;
     }
@@ -44,9 +42,7 @@ public class Parser extends AbstractParser {
         int length;
         int offset = 0;
 
-        try {
-            FileReader reader = new FileReader(new File(dir, file), StandardCharsets.UTF_8);
-
+        try (FileReader reader = new FileReader(new File(dir, file), StandardCharsets.UTF_8)) {
             do {
                 length = reader.read(buffer);
 
@@ -57,11 +53,8 @@ public class Parser extends AbstractParser {
                 }
                 offset += length;
             } while (length != -1);
-
-            // close file
-            reader.close();
         } catch (Exception e) {
-            e.printStackTrace();
+            logger.error(e.getMessage(), e);
             return false;
         }
         return true;

+ 2 - 3
jplag.frontend.cpp/src/main/java/de/jplag/cpp/Language.java

@@ -2,14 +2,13 @@ package de.jplag.cpp;
 
 import java.io.File;
 
-import de.jplag.ErrorConsumer;
 import de.jplag.TokenList;
 
 public class Language implements de.jplag.Language {
     private final Scanner scanner; // cpp code is scanned not parsed
 
-    public Language(ErrorConsumer errorConsumer) {
-        scanner = new Scanner(errorConsumer);
+    public Language() {
+        scanner = new Scanner();
     }
 
     @Override

+ 3 - 5
jplag.frontend.cpp/src/main/java/de/jplag/cpp/Scanner.java

@@ -3,7 +3,6 @@ package de.jplag.cpp;
 import java.io.File;
 
 import de.jplag.AbstractParser;
-import de.jplag.ErrorConsumer;
 import de.jplag.TokenList;
 
 public class Scanner extends AbstractParser {
@@ -13,10 +12,9 @@ public class Scanner extends AbstractParser {
 
     /**
      * Creates the parser.
-     * @param errorConsumer is the consumer for any occurring errors.
      */
-    public Scanner(ErrorConsumer errorConsumer) {
-        super(errorConsumer);
+    public Scanner() {
+        super();
     }
 
     public TokenList scan(File directory, String[] files) {
@@ -24,7 +22,7 @@ public class Scanner extends AbstractParser {
         errors = 0;
         for (String currentFile : files) {
             this.currentFile = currentFile;
-            getErrorConsumer().print(null, "Scanning file " + currentFile);
+            logger.trace("Scanning file {}", currentFile);
             if (!CPPScanner.scanFile(directory, currentFile, this)) {
                 errors++;
             }

+ 2 - 2
jplag.frontend.cpp/src/main/javacc/CPP.jj

@@ -37,10 +37,10 @@ public class CPPScanner implements CPPTokenConstants {
         try {
             scanner.scan();
         } catch (ParseException e) {
-            delegatingScanner.getErrorConsumer().addError("  Parsing Error in '" + fileName + "':\n  " + e.getMessage());
+            delegatingScanner.logger.error("Parsing Error in '" + fileName + "': " + e.getMessage());
             return false;
         } catch (TokenMgrException e) {
-            delegatingScanner.getErrorConsumer().addError("  Scanning Error in '" + fileName + "':\n  " + e.getMessage());
+            delegatingScanner.logger.error("Scanning Error in '" + fileName + "': " + e.getMessage());
             return false;
         }
         return true;

+ 3 - 5
jplag.frontend.csharp-6/src/main/java/de/jplag/csharp/CSharpParserAdapter.java

@@ -12,7 +12,6 @@ import org.antlr.v4.runtime.tree.ParseTree;
 import org.antlr.v4.runtime.tree.ParseTreeWalker;
 
 import de.jplag.AbstractParser;
-import de.jplag.ErrorConsumer;
 import de.jplag.TokenList;
 import de.jplag.csharp.grammar.CSharpLexer;
 import de.jplag.csharp.grammar.CSharpParser;
@@ -28,10 +27,9 @@ public class CSharpParserAdapter extends AbstractParser {
 
     /**
      * Creates the parser adapter.
-     * @param errorConsumer is the consumer for any occurring errors.
      */
-    public CSharpParserAdapter(ErrorConsumer errorConsumer) {
-        super(errorConsumer);
+    public CSharpParserAdapter() {
+        super();
     }
 
     /**
@@ -72,7 +70,7 @@ public class CSharpParserAdapter extends AbstractParser {
                 treeWalker.walk(new CSharpListener(this), parseTree);
             }
         } catch (IOException exception) {
-            getErrorConsumer().addError("Parsing Error in '" + fileName + "':" + File.separator + exception.toString());
+            logger.error("Parsing Error in '" + fileName + "':" + File.separator + exception, exception);
             return false;
         }
         return true;

+ 2 - 3
jplag.frontend.csharp-6/src/main/java/de/jplag/csharp/Language.java

@@ -3,7 +3,6 @@ package de.jplag.csharp;
 import java.io.File;
 import java.util.Arrays;
 
-import de.jplag.ErrorConsumer;
 import de.jplag.TokenList;
 
 /**
@@ -18,8 +17,8 @@ public class Language implements de.jplag.Language {
 
     private final CSharpParserAdapter parser;
 
-    public Language(ErrorConsumer program) {
-        parser = new CSharpParserAdapter(program);
+    public Language() {
+        parser = new CSharpParserAdapter();
     }
 
     @Override

+ 1 - 3
jplag.frontend.csharp-6/src/test/java/de/jplag/csharp/MinimalCSharpFrontendTest.java

@@ -20,7 +20,6 @@ import de.jplag.Token;
 import de.jplag.TokenConstants;
 import de.jplag.TokenList;
 import de.jplag.TokenPrinter;
-import de.jplag.testutils.TestErrorConsumer;
 
 class MinimalCSharpFrontendTest {
     private final Logger logger = LoggerFactory.getLogger("JPlag-Test");
@@ -33,8 +32,7 @@ class MinimalCSharpFrontendTest {
 
     @BeforeEach
     public void setUp() {
-        TestErrorConsumer consumer = new TestErrorConsumer();
-        frontend = new Language(consumer);
+        frontend = new Language();
         baseDirectory = BASE_PATH.toFile();
         assertTrue(baseDirectory.exists(), "Could not find base directory!");
     }

+ 6 - 9
jplag.frontend.java/src/main/java/de/jplag/java/JavacAdapter.java

@@ -6,12 +6,10 @@ import java.nio.charset.StandardCharsets;
 import java.nio.file.Paths;
 import java.util.Collections;
 
-import javax.tools.Diagnostic;
-import javax.tools.DiagnosticCollector;
-import javax.tools.JavaCompiler;
+import javax.tools.*;
 import javax.tools.JavaCompiler.CompilationTask;
-import javax.tools.StandardJavaFileManager;
-import javax.tools.ToolProvider;
+
+import org.slf4j.Logger;
 
 import com.sun.source.tree.CompilationUnitTree;
 import com.sun.source.tree.LineMap;
@@ -19,7 +17,6 @@ import com.sun.source.util.JavacTask;
 import com.sun.source.util.SourcePositions;
 import com.sun.source.util.Trees;
 
-import de.jplag.ErrorConsumer;
 import de.jplag.TokenConstants;
 
 public class JavacAdapter {
@@ -39,7 +36,7 @@ public class JavacAdapter {
             ast.accept(new TokenGeneratingTreeScanner(filename, parser, map, positions, ast), null);
             parser.add(TokenConstants.FILE_END, filename, 1, -1, -1);
         }
-        return processErrors(parser.getErrorConsumer(), listener);
+        return processErrors(parser.logger, listener);
     }
 
     private Iterable<? extends CompilationUnitTree> executeCompilationTask(final CompilationTask task) {
@@ -60,11 +57,11 @@ public class JavacAdapter {
         }
     }
 
-    private int processErrors(final ErrorConsumer consumer, DiagnosticCollector<Object> listener) {
+    private int processErrors(Logger logger, DiagnosticCollector<Object> listener) {
         int errors = 0;
         for (Diagnostic<?> diagnosticItem : listener.getDiagnostics()) {
             if (diagnosticItem.getKind() == javax.tools.Diagnostic.Kind.ERROR) {
-                consumer.addError(diagnosticItem.toString());
+                logger.error("{}", diagnosticItem);
                 errors++;
             }
         }

+ 2 - 3
jplag.frontend.java/src/main/java/de/jplag/java/Language.java

@@ -2,7 +2,6 @@ package de.jplag.java;
 
 import java.io.File;
 
-import de.jplag.ErrorConsumer;
 import de.jplag.TokenList;
 
 /**
@@ -11,8 +10,8 @@ import de.jplag.TokenList;
 public class Language implements de.jplag.Language {
     private final Parser parser;
 
-    public Language(ErrorConsumer errorConsumer) {
-        parser = new Parser(errorConsumer);
+    public Language() {
+        parser = new Parser();
     }
 
     @Override

+ 3 - 7
jplag.frontend.java/src/main/java/de/jplag/java/Parser.java

@@ -1,12 +1,9 @@
 package de.jplag.java;
 
-import static java.util.stream.Collectors.toList;
-
 import java.io.File;
 import java.util.Arrays;
 
 import de.jplag.AbstractParser;
-import de.jplag.ErrorConsumer;
 import de.jplag.TokenList;
 
 public class Parser extends AbstractParser {
@@ -14,16 +11,15 @@ public class Parser extends AbstractParser {
 
     /**
      * Creates the parser.
-     * @param errorConsumer is the consumer for any occurring errors.
      */
-    public Parser(ErrorConsumer errorConsumer) {
-        super(errorConsumer);
+    public Parser() {
+        super();
     }
 
     public TokenList parse(File directory, String[] files) {
         tokens = new TokenList();
         errors = 0;
-        var pathedFiles = Arrays.stream(files).map(it -> new File(directory, it)).collect(toList());
+        var pathedFiles = Arrays.stream(files).map(it -> new File(directory, it)).toList();
         errors += new JavacAdapter().parseFiles(directory, pathedFiles, this);
         return tokens;
     }

+ 2 - 3
jplag.frontend.python-3/src/main/java/de/jplag/python3/Language.java

@@ -2,15 +2,14 @@ package de.jplag.python3;
 
 import java.io.File;
 
-import de.jplag.ErrorConsumer;
 import de.jplag.TokenList;
 
 public class Language implements de.jplag.Language {
 
     private final Parser parser;
 
-    public Language(ErrorConsumer errorConsumer) {
-        parser = new Parser(errorConsumer);
+    public Language() {
+        parser = new Parser();
     }
 
     @Override

+ 7 - 8
jplag.frontend.python-3/src/main/java/de/jplag/python3/Parser.java

@@ -13,7 +13,6 @@ import org.antlr.v4.runtime.tree.ParseTree;
 import org.antlr.v4.runtime.tree.ParseTreeWalker;
 
 import de.jplag.AbstractParser;
-import de.jplag.ErrorConsumer;
 import de.jplag.TokenList;
 import de.jplag.python3.grammar.Python3Lexer;
 import de.jplag.python3.grammar.Python3Parser;
@@ -28,19 +27,19 @@ public class Parser extends AbstractParser {
      * Creates the parser.
      * @param errorConsumer is the consumer for any occurring errors.
      */
-    public Parser(ErrorConsumer errorConsumer) {
-        super(errorConsumer);
+    public Parser() {
+        super();
     }
 
     public TokenList parse(File directory, String[] files) {
         tokens = new TokenList();
         errors = 0;
-        for (int i = 0; i < files.length; i++) {
-            getErrorConsumer().print(null, "Parsing file " + files[i]);
-            if (!parseFile(directory, files[i])) {
+        for (String file : files) {
+            logger.trace("Parsing file {}", file);
+            if (!parseFile(directory, file)) {
                 errors++;
             }
-            tokens.addToken(new Python3Token(Python3TokenConstants.FILE_END, files[i], -1, -1, -1));
+            tokens.addToken(new Python3Token(Python3TokenConstants.FILE_END, file, -1, -1, -1));
         }
         return tokens;
     }
@@ -71,7 +70,7 @@ public class Parser extends AbstractParser {
             }
 
         } catch (IOException e) {
-            getErrorConsumer().addError("Parsing Error in '" + file + "':\n" + e.getMessage());
+            logger.error("Parsing Error in '" + file + "': " + e.getMessage(), e);
             return false;
         }
 

+ 2 - 3
jplag.frontend.rlang/src/main/java/de/jplag/rlang/Language.java

@@ -2,7 +2,6 @@ package de.jplag.rlang;
 
 import java.io.File;
 
-import de.jplag.ErrorConsumer;
 import de.jplag.TokenList;
 
 /**
@@ -15,8 +14,8 @@ public class Language implements de.jplag.Language {
     public static final int DEFAULT_MIN_TOKEN_MATCH = 8;
     private final RParserAdapter parserAdapter;
 
-    public Language(ErrorConsumer consumer) {
-        this.parserAdapter = new RParserAdapter(consumer);
+    public Language() {
+        this.parserAdapter = new RParserAdapter();
     }
 
     @Override

+ 3 - 5
jplag.frontend.rlang/src/main/java/de/jplag/rlang/RParserAdapter.java

@@ -11,7 +11,6 @@ import org.antlr.v4.runtime.tree.ParseTree;
 import org.antlr.v4.runtime.tree.ParseTreeWalker;
 
 import de.jplag.AbstractParser;
-import de.jplag.ErrorConsumer;
 import de.jplag.TokenList;
 import de.jplag.rlang.grammar.RFilter;
 import de.jplag.rlang.grammar.RLexer;
@@ -28,10 +27,9 @@ public class RParserAdapter extends AbstractParser implements RTokenConstants {
 
     /**
      * Creates the RParserAdapter
-     * @param errorConsumer the ErrorConsumer that parser errors are passed on to.
      */
-    public RParserAdapter(ErrorConsumer errorConsumer) {
-        super(errorConsumer);
+    public RParserAdapter() {
+        super();
     }
 
     /**
@@ -77,7 +75,7 @@ public class RParserAdapter extends AbstractParser implements RTokenConstants {
                 treeWalker.walk(new JplagRListener(this), parseTree);
             }
         } catch (IOException exception) {
-            getErrorConsumer().addError("Parsing Error in '" + fileName + "':" + File.separator + exception);
+            logger.error("Parsing Error in '" + fileName + "': " + File.separator + exception.getMessage(), exception);
             return false;
         }
         return true;

+ 2 - 4
jplag.frontend.rlang/src/test/java/de/jplag/rlang/RFrontendTest.java

@@ -19,9 +19,8 @@ import de.jplag.Token;
 import de.jplag.TokenConstants;
 import de.jplag.TokenList;
 import de.jplag.TokenPrinter;
-import de.jplag.testutils.TestErrorConsumer;
 
-public class RFrontendTest {
+class RFrontendTest {
 
     /**
      * Regular expression for lines that contain no code.
@@ -41,8 +40,7 @@ public class RFrontendTest {
 
     @BeforeEach
     void setup() {
-        TestErrorConsumer consumer = new TestErrorConsumer();
-        language = new Language(consumer);
+        language = new Language();
     }
 
     @Test

+ 2 - 3
jplag.frontend.scheme/src/main/java/de/jplag/scheme/Language.java

@@ -2,14 +2,13 @@ package de.jplag.scheme;
 
 import java.io.File;
 
-import de.jplag.ErrorConsumer;
 import de.jplag.TokenList;
 
 public class Language implements de.jplag.Language {
     private final de.jplag.scheme.Parser parser;
 
-    public Language(ErrorConsumer program) {
-        parser = new Parser(program);
+    public Language() {
+        parser = new Parser();
     }
 
     @Override

+ 6 - 8
jplag.frontend.scheme/src/main/java/de/jplag/scheme/Parser.java

@@ -3,7 +3,6 @@ package de.jplag.scheme;
 import java.io.File;
 
 import de.jplag.AbstractParser;
-import de.jplag.ErrorConsumer;
 import de.jplag.TokenList;
 
 public class Parser extends AbstractParser {
@@ -13,19 +12,18 @@ public class Parser extends AbstractParser {
 
     /**
      * Creates the parser.
-     * @param errorConsumer is the consumer for any occurring errors.
      */
-    public Parser(ErrorConsumer errorConsumer) {
-        super(errorConsumer);
+    public Parser() {
+        super();
     }
 
     public TokenList parse(File directory, String[] files) {
         tokens = new TokenList();
         errors = 0;
-        for (int i = 0; i < files.length; i++) {
-            currentFile = files[i];
-            getErrorConsumer().print(null, "Parsing file " + files[i]);
-            if (!SchemeParser.parseFile(directory, files[i], null, this))
+        for (String file : files) {
+            currentFile = file;
+            logger.trace("Parsing file {}", file);
+            if (!SchemeParser.parseFile(directory, file, null, this))
                 errors++;
             tokens.addToken(new SchemeToken(SchemeTokenConstants.FILE_END, currentFile));
         }

+ 2 - 2
jplag.frontend.scheme/src/main/javacc/Scheme.jj

@@ -78,10 +78,10 @@ public class SchemeParser implements SchemeTokenConstants {
         try {
             parser.Program();
         } catch (ParseException e) {
-            parserX.getErrorConsumer().addError("  Parsing Error in '" + fileName + "':\n  " + e.getMessage() + "\n");
+            parserX.logger.error("Parsing Error in '" + fileName + "': " + e.getMessage());
             return false;
         } catch (TokenMgrException e) {
-            parserX.getErrorConsumer().addError("  Scanning Error in '" + fileName + "':\n  " + e.getMessage() + "\n");
+            parserX.logger.error("Scanning Error in '" + fileName + "': " + e.getMessage());
             return false;
         }
         return true;

+ 2 - 4
jplag.frontend.text/src/main/java/de/jplag/text/Language.java

@@ -1,17 +1,15 @@
-
 package de.jplag.text;
 
 import java.io.File;
 
-import de.jplag.ErrorConsumer;
 import de.jplag.TokenList;
 
 public class Language implements de.jplag.Language {
 
     private final Parser parser;
 
-    public Language(ErrorConsumer errorConsumer) {
-        parser = new Parser(errorConsumer);
+    public Language() {
+        parser = new Parser();
     }
 
     @Override

+ 6 - 14
jplag.frontend.text/src/main/java/de/jplag/text/Parser.java

@@ -4,20 +4,14 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.util.Hashtable;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import antlr.Token;
 
 import de.jplag.AbstractParser;
-import de.jplag.ErrorConsumer;
 import de.jplag.TokenConstants;
 import de.jplag.TokenList;
 
 public class Parser extends AbstractParser {
 
-    private static final Logger logger = LoggerFactory.getLogger(Parser.class);
-
     protected Hashtable<String, Integer> table = new Hashtable<>();
     protected int serial = 1; // 0 is FILE_END token
 
@@ -29,17 +23,16 @@ public class Parser extends AbstractParser {
 
     /**
      * Creates the parser.
-     * @param errorConsumer is the consumer for any occurring errors.
      */
-    public Parser(ErrorConsumer errorConsumer) {
-        super(errorConsumer);
+    public Parser() {
+        super();
     }
 
     public TokenList parse(File directory, String[] files) {
         tokens = new TokenList();
         errors = 0;
         for (String file : files) {
-            getErrorConsumer().print("", "Parsing file " + file);
+            logger.trace("Parsing file {}", file);
             if (!parseFile(directory, file))
                 errors++;
             tokens.addToken(new TextToken(TokenConstants.FILE_END, file, this));
@@ -60,8 +53,7 @@ public class Parser extends AbstractParser {
             return;
         runOut = true;
         errors++;
-        errorConsumer.print("ERROR: Out of serials!", null);
-        logger.error("de.jplag.text.Parser: ERROR: Out of serials!");
+        logger.error("Out of serials!");
     }
 
     private boolean parseFile(File directory, String file) {
@@ -86,8 +78,8 @@ public class Parser extends AbstractParser {
             // close file
             inputStream.close();
         } catch (Exception e) {
-            getErrorConsumer().addError(
-                    "  Parsing Error in '" + file + "' (line " + (inputState != null ? "" + inputState.getLine() : "") + "):\n  " + e.getMessage());
+            logger.error("Parsing Error in '" + file + "' (line " + (inputState != null ? "" + inputState.getLine() : "") + "):\n  " + e.getMessage(),
+                    e);
             return false;
         }
         return true;

+ 0 - 79
jplag/src/main/java/de/jplag/ErrorCollector.java

@@ -1,79 +0,0 @@
-package de.jplag;
-
-import static de.jplag.options.Verbosity.LONG;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import de.jplag.options.JPlagOptions;
-import de.jplag.options.Verbosity;
-
-/**
- * Error collector class that collects errors but also allows printing the collected errors.
- * @author Timur Saglam
- */
-public class ErrorCollector implements ErrorConsumer {
-    // TODO DF We should replace *all* usages of the ErrorConsumer by a suitable logger
-    private final Logger logger = LoggerFactory.getLogger("JPlag");
-    private final List<String> collectedErrors; // List of errors that occurred during the execution of the errorConsumer.
-    private final JPlagOptions options;
-    private String currentSubmissionName;
-
-    public ErrorCollector(JPlagOptions options) {
-        this.options = options;
-        collectedErrors = new ArrayList<>();
-        currentSubmissionName = "<Unknown submission>";
-    }
-
-    @Override
-    public void addError(String errorMessage) {
-        collectedErrors.add("[" + currentSubmissionName + "] " + errorMessage);
-        print(null, "\t" + errorMessage);
-    }
-
-    @Override
-    public void print(String message, String longMessage) {
-        if (message == null && longMessage == null) {
-            throw new IllegalArgumentException("At least one message parameter needs to be non-null!");
-        }
-        Verbosity verbosity = options.getVerbosity();
-        if (message != null) {
-            logger.info(message);
-        }
-        if (longMessage != null && verbosity == LONG) {
-            logger.info(longMessage);
-        }
-    }
-
-    /**
-     * Print all collected errors messages in a list-like fashion.
-     */
-    public void printCollectedErrors() {
-        StringBuilder errorReport = new StringBuilder();
-        logger.error("The following errors occured: ");
-        for (String message : collectedErrors) {
-            errorReport.append(message);
-            errorReport.append('\n');
-        }
-
-        logger.error(errorReport.toString());
-    }
-
-    /**
-     * Updates the name of the currently processed submission.
-     * @param currentSubmissionName is the name.
-     */
-    public void setCurrentSubmissionName(String currentSubmissionName) {
-        this.currentSubmissionName = currentSubmissionName;
-    }
-
-    /**
-     * @return true if there is at least one error.
-     */
-    public boolean hasErrors() {
-        return !collectedErrors.isEmpty();
-    }
-}

+ 10 - 14
jplag/src/main/java/de/jplag/JPlag.java

@@ -29,14 +29,13 @@ import de.jplag.strategy.ParallelComparisonStrategy;
  * This class coordinates the whole errorConsumer flow.
  */
 public class JPlag {
-    private static final Logger logger = LoggerFactory.getLogger("JPlag");
+    private static final Logger logger = LoggerFactory.getLogger(JPlag.class);
 
     private final JPlagOptions options;
 
     private final Language language;
     private final ComparisonStrategy comparisonStrategy;
     private final GreedyStringTiling coreAlgorithm; // Contains the comparison logic.
-    private final ErrorCollector errorCollector;
     private final Set<String> excludedFileNames;
 
     /**
@@ -45,7 +44,6 @@ public class JPlag {
      */
     public JPlag(JPlagOptions options) {
         this.options = options;
-        errorCollector = new ErrorCollector(options);
         coreAlgorithm = new GreedyStringTiling(options);
         language = initializeLanguage();
         comparisonStrategy = initializeComparisonStrategy(options.getComparisonMode());
@@ -61,9 +59,9 @@ public class JPlag {
         try (BufferedReader reader = new BufferedReader(new FileReader(exclusionFileName, JPlagOptions.CHARSET))) {
             final var excludedFileNames = reader.lines().collect(Collectors.toSet());
             if (options.getVerbosity() == LONG) {
-                errorCollector.print(null, "Excluded files:");
+                logger.info("Excluded files:");
                 for (var excludedFilename : excludedFileNames) {
-                    errorCollector.print(null, " " + excludedFilename);
+                    logger.info(excludedFilename);
                 }
             }
             return excludedFileNames;
@@ -80,7 +78,7 @@ public class JPlag {
      */
     public JPlagResult run() throws ExitException {
         // Parse and validate submissions.
-        SubmissionSetBuilder builder = new SubmissionSetBuilder(language, options, errorCollector, excludedFileNames);
+        SubmissionSetBuilder builder = new SubmissionSetBuilder(language, options, excludedFileNames);
         SubmissionSet submissionSet = builder.buildSubmissionSet();
 
         if (submissionSet.hasBaseCode()) {
@@ -94,7 +92,7 @@ public class JPlag {
 
         // Compare valid submissions.
         JPlagResult result = comparisonStrategy.compareSubmissions(submissionSet);
-        errorCollector.print("\nTotal time for comparing submissions: " + TimeUtil.formatDuration(result.getDuration()), null);
+        logger.info("\nTotal time for comparing submissions: " + TimeUtil.formatDuration(result.getDuration()));
 
         result.setClusteringResult(ClusteringFactory.getClusterings(result.getComparisons(), options.getClusteringOptions()));
 
@@ -112,19 +110,17 @@ public class JPlag {
         LanguageOption languageOption = this.options.getLanguageOption();
 
         try {
-            Constructor<?> constructor = Class.forName(languageOption.getClassPath()).getConstructor(ErrorConsumer.class);
-            Object[] constructorParams = {errorCollector};
-
-            Language language = (Language) constructor.newInstance(constructorParams);
+            Constructor<?> constructor = Class.forName(languageOption.getClassPath()).getConstructor();
+            Language language = (Language) constructor.newInstance();
 
             this.options.setLanguage(language);
             this.options.setLanguageDefaults(language);
-            logger.info("Initialized language " + language.getName());
+            logger.info("Initialized language {}", language.getName());
             return language;
         } catch (NoSuchMethodException | SecurityException | ClassNotFoundException | InstantiationException | IllegalAccessException
                 | IllegalArgumentException | InvocationTargetException e) {
-            e.printStackTrace();
-            throw new IllegalStateException("Language instantiation failed:" + e.getMessage());
+            logger.error(e.getMessage(), e);
+            throw new IllegalStateException("Language instantiation failed:" + e.getMessage(), e);
         }
 
     }

+ 12 - 9
jplag/src/main/java/de/jplag/Submission.java

@@ -6,10 +6,15 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.Collection;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 /**
  * Represents a single submission. A submission can contain multiple files.
  */
 public class Submission implements Comparable<Submission> {
+    private static final Logger logger = LoggerFactory.getLogger(Submission.class);
+
     /**
      * Directory name for storing submission files with parse errors if so requested.
      */
@@ -51,7 +56,6 @@ public class Submission implements Comparable<Submission> {
     private JPlagComparison baseCodeComparison;
 
     private final Language language;
-    private final ErrorCollector errorCollector;
 
     /**
      * Creates a submission.
@@ -60,19 +64,18 @@ public class Submission implements Comparable<Submission> {
      * @param isNew states whether the submission must be checked for plagiarism.
      * @param files are the files of the submissions, if the root is a single file it should just contain one file.
      * @param language is the language of the submission.
-     * @param errorCollector is the interface for error reporting.
      */
-    public Submission(String name, File submissionRootFile, boolean isNew, Collection<File> files, Language language, ErrorCollector errorCollector) {
+    public Submission(String name, File submissionRootFile, boolean isNew, Collection<File> files, Language language) {
         this.name = name;
         this.submissionRootFile = submissionRootFile;
         this.isNew = isNew;
         this.files = files;
         this.language = language;
-        this.errorCollector = errorCollector;
     }
 
     @Override
     public int compareTo(Submission other) {
+        // TODO DF: "equals(Object obj)" should be overridden along with the "compareTo(T obj)" method
         return name.compareTo(other.name);
     }
 
@@ -204,12 +207,12 @@ public class Submission implements Comparable<Submission> {
             try {
                 Files.copy(file.toPath(), new File(submissionDirectory, file.getName()).toPath());
             } catch (IOException exception) {
-                errorCollector.print("Error copying file: " + exception + "\n", null);
+                logger.error("Error copying file: " + exception.getMessage(), exception);
             }
         }
     }
 
-    private File createSubdirectory(File parent, String... subdirectoryNames) {
+    private static File createSubdirectory(File parent, String... subdirectoryNames) {
         File subdirectory = parent;
         for (String name : subdirectoryNames) {
             subdirectory = new File(subdirectory, name);
@@ -246,8 +249,8 @@ public class Submission implements Comparable<Submission> {
      * @return Whether parsing was successful.
      */
     /* package-private */ boolean parse(boolean debugParser) {
-        if (files == null || files.size() == 0) {
-            errorCollector.print("ERROR: nothing to parse for submission \"" + name + "\"", null);
+        if (files == null || files.isEmpty()) {
+            logger.error("ERROR: nothing to parse for submission \"{}\"", name);
             tokenList = null;
             hasErrors = true; // invalidate submission
             return false;
@@ -258,7 +261,7 @@ public class Submission implements Comparable<Submission> {
         tokenList = language.parse(submissionRootFile, relativeFilePaths);
         if (!language.hasErrors()) {
             if (tokenList.size() < 3) {
-                errorCollector.print("Submission \"" + name + "\" is too short!", null);
+                logger.error("Submission \"{}\" is too short!", name);
                 tokenList = null;
                 hasErrors = true; // invalidate submission
                 return false;

+ 21 - 26
jplag/src/main/java/de/jplag/SubmissionSet.java

@@ -7,6 +7,9 @@ import java.util.List;
 import java.util.Optional;
 import java.util.stream.Collectors;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import de.jplag.exceptions.BasecodeException;
 import de.jplag.exceptions.ExitException;
 import de.jplag.exceptions.SubmissionException;
@@ -16,6 +19,8 @@ import de.jplag.options.JPlagOptions;
  * Collection of all submissions and their basecode if it exists. Parses all submissions upon creation.
  */
 public class SubmissionSet {
+    private static final Logger logger = LoggerFactory.getLogger(SubmissionSet.class);
+
     /**
      * Submissions to check for plagiarism.
      */
@@ -27,8 +32,6 @@ public class SubmissionSet {
      * Base code submission if it exists.
      */
     private final Optional<Submission> baseCodeSubmission;
-
-    private final ErrorCollector errorCollector;
     private final JPlagOptions options;
     private int errors = 0;
     private String currentSubmissionName;
@@ -37,11 +40,9 @@ public class SubmissionSet {
      * @param submissions Submissions to check for plagiarism.
      * @param baseCode Base code submission if it exists.
      */
-    public SubmissionSet(List<Submission> submissions, Optional<Submission> baseCode, ErrorCollector errorCollector, JPlagOptions options)
-            throws ExitException {
+    public SubmissionSet(List<Submission> submissions, Optional<Submission> baseCode, JPlagOptions options) throws ExitException {
         this.allSubmissions = submissions;
         this.baseCodeSubmission = baseCode;
-        this.errorCollector = errorCollector;
         this.options = options;
         parseAllSubmissions();
         this.submissions = filterValidSubmissions();
@@ -108,9 +109,6 @@ public class SubmissionSet {
         } catch (OutOfMemoryError exception) {
             throw new SubmissionException("Out of memory during parsing of submission \"" + currentSubmissionName + "\"", exception);
         }
-        if (errorCollector.hasErrors()) {
-            errorCollector.printCollectedErrors();
-        }
     }
 
     /**
@@ -118,16 +116,15 @@ public class SubmissionSet {
      */
     private void parseBaseCodeSubmission(Submission baseCode) throws BasecodeException {
         long startTime = System.currentTimeMillis();
-        errorCollector.print("----- Parsing basecode submission: " + baseCode.getName(), null);
+        logger.info("----- Parsing basecode submission: " + baseCode.getName());
         if (!baseCode.parse(options.isDebugParser())) {
-            errorCollector.printCollectedErrors();
             throw new BasecodeException("Could not successfully parse basecode submission!");
         } else if (baseCode.getNumberOfTokens() < options.getMinimumTokenMatch()) {
             throw new BasecodeException("Basecode submission contains fewer tokens than minimum match length allows!");
         }
-        errorCollector.print("Basecode submission parsed!", null);
+        logger.info("Basecode submission parsed!");
         long duration = System.currentTimeMillis() - startTime;
-        errorCollector.print(null, "Time for parsing Basecode: " + TimeUtil.formatDuration(duration));
+        logger.trace("Time for parsing Basecode: " + TimeUtil.formatDuration(duration));
 
     }
 
@@ -136,7 +133,7 @@ public class SubmissionSet {
      */
     private void parseSubmissions(List<Submission> submissions) {
         if (submissions.isEmpty()) {
-            errorCollector.print("No submissions to parse!", null);
+            logger.warn("No submissions to parse!");
             return;
         }
 
@@ -146,16 +143,15 @@ public class SubmissionSet {
         for (Submission submission : submissions) {
             boolean ok;
 
-            errorCollector.print(null, "------ Parsing submission: " + submission.getName());
+            logger.trace("------ Parsing submission: " + submission.getName());
             currentSubmissionName = submission.getName();
-            errorCollector.setCurrentSubmissionName(currentSubmissionName);
 
             if (!(ok = submission.parse(options.isDebugParser()))) {
                 errors++;
             }
 
             if (submission.getTokenList() != null && submission.getNumberOfTokens() < options.getMinimumTokenMatch()) {
-                errorCollector.addError("Submission contains fewer tokens than minimum match length allows!");
+                logger.error("Submission {} contains fewer tokens than minimum match length allows!", currentSubmissionName);
                 submission.setTokenList(null);
                 tooShort++;
                 ok = false;
@@ -163,31 +159,30 @@ public class SubmissionSet {
             }
 
             if (ok) {
-                errorCollector.print(null, "OK");
+                logger.trace("OK");
             } else {
-                errorCollector.print(null, "ERROR -> Submission removed");
+                logger.error("ERROR -> Submission {} removed", currentSubmissionName);
             }
         }
 
         int validSubmissions = submissions.size() - errors - tooShort;
-        errorCollector.print(validSubmissions + " submissions parsed successfully!", null);
-        errorCollector.print(errors + " parser error" + (errors != 1 ? "s!" : "!") + "", null);
-        errorCollector.print(tooShort + " too short submission" + (tooShort != 1 ? "s!" : "!") + "", null);
+        logger.trace(validSubmissions + " submissions parsed successfully!");
+        logger.trace(errors + " parser error" + (errors != 1 ? "s!" : "!"));
+        logger.trace(tooShort + " too short submission" + (tooShort != 1 ? "s!" : "!"));
         printDetails(submissions, startTime, tooShort);
-        errorCollector.print("", null); // new line
     }
 
     private void printDetails(List<Submission> submissions, long startTime, int tooShort) {
         if (tooShort == 1) {
-            errorCollector.print(null, tooShort + " submission is not valid because it contains fewer tokens than minimum match length allows.");
+            logger.trace(tooShort + " submission is not valid because it contains fewer tokens than minimum match length allows.");
         } else if (tooShort > 1) {
-            errorCollector.print(null, tooShort + " submissions are not valid because they contain fewer tokens than minimum match length allows.");
+            logger.trace(tooShort + " submissions are not valid because they contain fewer tokens than minimum match length allows.");
         }
 
         long duration = System.currentTimeMillis() - startTime;
         String timePerSubmission = submissions.size() > 0 ? Long.toString(duration / submissions.size()) : "n/a";
-        errorCollector.print(null, "Total time for parsing: " + TimeUtil.formatDuration(duration));
-        errorCollector.print(null, "Time per parsed submission: " + timePerSubmission + " msec");
+        logger.trace("Total time for parsing: " + TimeUtil.formatDuration(duration));
+        logger.trace("Time per parsed submission: " + timePerSubmission + " msec");
     }
 
 }

+ 3 - 6
jplag/src/main/java/de/jplag/SubmissionSetBuilder.java

@@ -24,20 +24,17 @@ public class SubmissionSetBuilder {
 
     private final Language language;
     private final JPlagOptions options;
-    private final ErrorCollector errorCollector;
     private final Set<String> excludedFileNames; // Set of file names to be excluded in comparison.
 
     /**
      * Creates a builder for submission sets.
      * @param language is the language of the submissions.
      * @param options are the configured options.
-     * @param errorCollector is the interface for error reporting.
      * @param excludedFileNames a list of file names to be excluded
      */
-    public SubmissionSetBuilder(Language language, JPlagOptions options, ErrorCollector errorCollector, Set<String> excludedFileNames) {
+    public SubmissionSetBuilder(Language language, JPlagOptions options, Set<String> excludedFileNames) {
         this.language = language;
         this.options = options;
-        this.errorCollector = errorCollector;
         this.excludedFileNames = excludedFileNames;
     }
 
@@ -69,7 +66,7 @@ public class SubmissionSetBuilder {
 
         // Merge everything in a submission set.
         List<Submission> submissions = new ArrayList<>(foundSubmissions.values());
-        return new SubmissionSet(submissions, baseCodeSubmission, errorCollector, options);
+        return new SubmissionSet(submissions, baseCodeSubmission, options);
     }
 
     /**
@@ -280,7 +277,7 @@ public class SubmissionSetBuilder {
         }
 
         submissionFile = makeCanonical(submissionFile, it -> new SubmissionException("Cannot create submission: " + submissionName, it));
-        return new Submission(submissionName, submissionFile, isNew, parseFilesRecursively(submissionFile), language, errorCollector);
+        return new Submission(submissionName, submissionFile, isNew, parseFilesRecursively(submissionFile), language);
     }
 
     /**