Repository: checkstyle/checkstyle

Problem statement:
Remove Global Static Locale
https://github.com/checkstyle/checkstyle/blob/a368230b7df8ca70839f97d30a8d8adebd8b9ff3/src/main/java/com/puppycrawl/tools/checkstyle/api/Violation.java#L68
https://github.com/checkstyle/checkstyle/blob/a368230b7df8ca70839f97d30a8d8adebd8b9ff3/src/main/java/com/puppycrawl/tools/checkstyle/Checker.java#L434

Identified in several issues,
https://github.com/checkstyle/checkstyle/pull/12053#discussion_r955646247
https://github.com/checkstyle/checkstyle/issues/12101
https://github.com/checkstyle/checkstyle/issues/7436

Setting any type of locale in a global area, either by `Violation.setLocale` or `Locale.setDefault`, is a very bad idea.

It is very easy to corrupt the locale if developers creating tests aren't careful as changing this value can impact all other tests since it is global. Even if developers are careful, its hard to remember all the little places that can change the locale without in-depth knowledge all the time.

Example:
https://github.com/checkstyle/checkstyle/blob/d287d78e7ee1218092f0c386cddd78ea81448fc3/src/test/java/com/puppycrawl/tools/checkstyle/CheckerTest.java#L478 -- We set the locale to italy and don't do any reversion. I am not sure how this hasn't been an issue already but I think we have been lucky on test run ordering.
https://github.com/checkstyle/checkstyle/blob/0eadd97b8af5b79e7c49f82958fbb3d863bfdf61/src/it/java/org/checkstyle/base/AbstractItModuleTestSupport.java#L286 -- We set the locale to English but CI and most users run in English.
https://github.com/checkstyle/checkstyle/blob/d287d78e7ee1218092f0c386cddd78ea81448fc3/src/test/java/com/puppycrawl/tools/checkstyle/api/ViolationTest.java#L445 -- Example of where we have to be extra careful and reset the global locale back after testing.

If we ever create a config with a locale set and load it in a test, it would also cause a global issue.

We need to remove this method somehow and pass the locale either by stack or have a central, non-static, area be the main source of it like Checker.

We also need to forbid `Locale.setDefault`. (either ForbiddenAPIs or xpath)


Hints:

Patch:
diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/Checker.java b/src/main/java/com/puppycrawl/tools/checkstyle/Checker.java
--- a/src/main/java/com/puppycrawl/tools/checkstyle/Checker.java
+++ b/src/main/java/com/puppycrawl/tools/checkstyle/Checker.java
@@ -431,7 +431,7 @@ public void fireFileFinished(String fileName) {
     @Override
     protected void finishLocalSetup() throws CheckstyleException {
         final Locale locale = new Locale(localeLanguage, localeCountry);
-        Violation.setLocale(locale);
+        LocalizedMessage.setLocale(locale);
 
         if (moduleFactory == null) {
             if (moduleClassLoader == null) {
diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/DefaultLogger.java b/src/main/java/com/puppycrawl/tools/checkstyle/DefaultLogger.java
--- a/src/main/java/com/puppycrawl/tools/checkstyle/DefaultLogger.java
+++ b/src/main/java/com/puppycrawl/tools/checkstyle/DefaultLogger.java
@@ -24,7 +24,6 @@
 import java.io.PrintWriter;
 import java.io.Writer;
 import java.nio.charset.StandardCharsets;
-import java.util.Locale;
 
 import com.puppycrawl.tools.checkstyle.api.AuditEvent;
 import com.puppycrawl.tools.checkstyle.api.AuditListener;
@@ -161,7 +160,7 @@ public void addError(AuditEvent event) {
     public void addException(AuditEvent event, Throwable throwable) {
         synchronized (errorWriter) {
             final LocalizedMessage exceptionMessage = new LocalizedMessage(
-                    Definitions.CHECKSTYLE_BUNDLE, Locale.getDefault(), DefaultLogger.class,
+                    Definitions.CHECKSTYLE_BUNDLE, DefaultLogger.class,
                     ADD_EXCEPTION_MESSAGE, event.getFileName());
             errorWriter.println(exceptionMessage.getMessage());
             throwable.printStackTrace(errorWriter);
@@ -171,7 +170,7 @@ public void addException(AuditEvent event, Throwable throwable) {
     @Override
     public void auditStarted(AuditEvent event) {
         final LocalizedMessage auditStartMessage = new LocalizedMessage(
-                Definitions.CHECKSTYLE_BUNDLE, Locale.getDefault(), DefaultLogger.class,
+                Definitions.CHECKSTYLE_BUNDLE, DefaultLogger.class,
                 AUDIT_STARTED_MESSAGE);
         infoWriter.println(auditStartMessage.getMessage());
         infoWriter.flush();
@@ -180,7 +179,7 @@ public void auditStarted(AuditEvent event) {
     @Override
     public void auditFinished(AuditEvent event) {
         final LocalizedMessage auditFinishMessage = new LocalizedMessage(
-                Definitions.CHECKSTYLE_BUNDLE, Locale.getDefault(), DefaultLogger.class,
+                Definitions.CHECKSTYLE_BUNDLE, DefaultLogger.class,
                 AUDIT_FINISHED_MESSAGE);
         infoWriter.println(auditFinishMessage.getMessage());
         closeStreams();
diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/DetailNodeTreeStringPrinter.java b/src/main/java/com/puppycrawl/tools/checkstyle/DetailNodeTreeStringPrinter.java
--- a/src/main/java/com/puppycrawl/tools/checkstyle/DetailNodeTreeStringPrinter.java
+++ b/src/main/java/com/puppycrawl/tools/checkstyle/DetailNodeTreeStringPrinter.java
@@ -29,7 +29,6 @@
 import com.puppycrawl.tools.checkstyle.api.DetailNode;
 import com.puppycrawl.tools.checkstyle.api.FileText;
 import com.puppycrawl.tools.checkstyle.api.JavadocTokenTypes;
-import com.puppycrawl.tools.checkstyle.api.Violation;
 import com.puppycrawl.tools.checkstyle.utils.JavadocUtil;
 import com.puppycrawl.tools.checkstyle.utils.ParserUtil;
 
@@ -91,15 +90,12 @@ private static DetailNode parseJavadocAsDetailNode(String javadocComment) {
      * @return error violation
      */
     private static String getParseErrorMessage(ParseErrorMessage parseErrorMessage) {
-        final Violation lmessage = new Violation(
-                parseErrorMessage.getLineNumber(),
+        final LocalizedMessage message = new LocalizedMessage(
                 "com.puppycrawl.tools.checkstyle.checks.javadoc.messages",
-                parseErrorMessage.getMessageKey(),
-                parseErrorMessage.getMessageArguments(),
-                "",
                 DetailNodeTreeStringPrinter.class,
-                null);
-        return "[ERROR:" + parseErrorMessage.getLineNumber() + "] " + lmessage.getViolation();
+                parseErrorMessage.getMessageKey(),
+                parseErrorMessage.getMessageArguments());
+        return "[ERROR:" + parseErrorMessage.getLineNumber() + "] " + message.getMessage();
     }
 
     /**
diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/LocalizedMessage.java b/src/main/java/com/puppycrawl/tools/checkstyle/LocalizedMessage.java
--- a/src/main/java/com/puppycrawl/tools/checkstyle/LocalizedMessage.java
+++ b/src/main/java/com/puppycrawl/tools/checkstyle/LocalizedMessage.java
@@ -40,14 +40,12 @@
  */
 public class LocalizedMessage {
 
+    /** The locale to localise messages to. **/
+    private static Locale sLocale = Locale.getDefault();
+
     /** Name of the resource bundle to get messages from. **/
     private final String bundle;
 
-    /**
-     * The locale to localise messages to.
-     **/
-    private final Locale locale;
-
     /** Class of the source for this message. */
     private final Class<?> sourceClass;
 
@@ -65,15 +63,13 @@ public class LocalizedMessage {
      * Creates a new {@code LocalizedMessage} instance.
      *
      * @param bundle resource bundle name
-     * @param locale The locale to localise messages to.
      * @param sourceClass the Class that is the source of the message
      * @param key the key to locate the translation.
      * @param args arguments for the translation.
      */
-    public LocalizedMessage(String bundle, Locale locale, Class<?> sourceClass, String key,
+    public LocalizedMessage(String bundle, Class<?> sourceClass, String key,
             Object... args) {
         this.bundle = bundle;
-        this.locale = locale;
         this.sourceClass = sourceClass;
         this.key = key;
         if (args == null) {
@@ -84,6 +80,20 @@ public LocalizedMessage(String bundle, Locale locale, Class<?> sourceClass, Stri
         }
     }
 
+    /**
+     * Sets a locale to use for localization.
+     *
+     * @param locale the locale to use for localization
+     */
+    public static void setLocale(Locale locale) {
+        if (Locale.ENGLISH.getLanguage().equals(locale.getLanguage())) {
+            sLocale = Locale.ROOT;
+        }
+        else {
+            sLocale = locale;
+        }
+    }
+
     /**
      * Gets the translated message.
      *
@@ -119,7 +129,7 @@ public String getMessage() {
      * @return a ResourceBundle.
      */
     private ResourceBundle getBundle() {
-        return ResourceBundle.getBundle(bundle, locale, sourceClass.getClassLoader(),
+        return ResourceBundle.getBundle(bundle, sLocale, sourceClass.getClassLoader(),
                 new Utf8Control());
     }
 
diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/Main.java b/src/main/java/com/puppycrawl/tools/checkstyle/Main.java
--- a/src/main/java/com/puppycrawl/tools/checkstyle/Main.java
+++ b/src/main/java/com/puppycrawl/tools/checkstyle/Main.java
@@ -48,7 +48,6 @@
 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
 import com.puppycrawl.tools.checkstyle.api.Configuration;
 import com.puppycrawl.tools.checkstyle.api.RootModule;
-import com.puppycrawl.tools.checkstyle.api.Violation;
 import com.puppycrawl.tools.checkstyle.utils.ChainedPropertyUtil;
 import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
 import com.puppycrawl.tools.checkstyle.utils.XpathUtil;
@@ -146,12 +145,12 @@ else if (parseResult.isUsageHelpRequested()) {
         finally {
             // return exit code base on validation of Checker
             if (errorCounter > 0) {
-                final Violation errorCounterViolation = new Violation(1,
-                        Definitions.CHECKSTYLE_BUNDLE, ERROR_COUNTER,
-                        new String[] {String.valueOf(errorCounter)}, null, Main.class, null);
+                final LocalizedMessage errorCounterViolation = new LocalizedMessage(
+                        Definitions.CHECKSTYLE_BUNDLE, Main.class,
+                        ERROR_COUNTER, String.valueOf(errorCounter));
                 // print error count statistic to error output stream,
                 // output stream might be used by validation report content
-                System.err.println(errorCounterViolation.getViolation());
+                System.err.println(errorCounterViolation.getMessage());
             }
         }
         Runtime.getRuntime().exit(exitStatus);
@@ -439,10 +438,10 @@ private static Properties loadProperties(File file)
             properties.load(stream);
         }
         catch (final IOException ex) {
-            final Violation loadPropertiesExceptionMessage = new Violation(1,
-                    Definitions.CHECKSTYLE_BUNDLE, LOAD_PROPERTIES_EXCEPTION,
-                    new String[] {file.getAbsolutePath()}, null, Main.class, null);
-            throw new CheckstyleException(loadPropertiesExceptionMessage.getViolation(), ex);
+            final LocalizedMessage loadPropertiesExceptionMessage = new LocalizedMessage(
+                    Definitions.CHECKSTYLE_BUNDLE, Main.class,
+                    LOAD_PROPERTIES_EXCEPTION, file.getAbsolutePath());
+            throw new CheckstyleException(loadPropertiesExceptionMessage.getMessage(), ex);
         }
 
         return ChainedPropertyUtil.getResolvedProperties(properties);
diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/PackageObjectFactory.java b/src/main/java/com/puppycrawl/tools/checkstyle/PackageObjectFactory.java
--- a/src/main/java/com/puppycrawl/tools/checkstyle/PackageObjectFactory.java
+++ b/src/main/java/com/puppycrawl/tools/checkstyle/PackageObjectFactory.java
@@ -31,7 +31,6 @@
 import java.util.stream.Stream;
 
 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
-import com.puppycrawl.tools.checkstyle.api.Violation;
 import com.puppycrawl.tools.checkstyle.utils.ModuleReflectionUtil;
 
 /**
@@ -209,10 +208,10 @@ public Object createModule(String name) throws CheckstyleException {
                         + STRING_SEPARATOR + nameCheck + STRING_SEPARATOR
                         + joinPackageNamesWithClassName(nameCheck, packages);
             }
-            final Violation exceptionMessage = new Violation(1,
-                Definitions.CHECKSTYLE_BUNDLE, UNABLE_TO_INSTANTIATE_EXCEPTION_MESSAGE,
-                new String[] {name, attemptedNames}, null, getClass(), null);
-            throw new CheckstyleException(exceptionMessage.getViolation());
+            final LocalizedMessage exceptionMessage = new LocalizedMessage(
+                Definitions.CHECKSTYLE_BUNDLE, getClass(),
+                UNABLE_TO_INSTANTIATE_EXCEPTION_MESSAGE, name, attemptedNames);
+            throw new CheckstyleException(exceptionMessage.getMessage());
         }
         return instance;
     }
@@ -285,10 +284,10 @@ private Object createObjectFromFullModuleNames(String name, Set<String> fullModu
             final String optionalNames = fullModuleNames.stream()
                     .sorted()
                     .collect(Collectors.joining(STRING_SEPARATOR));
-            final Violation exceptionMessage = new Violation(1,
-                    Definitions.CHECKSTYLE_BUNDLE, AMBIGUOUS_MODULE_NAME_EXCEPTION_MESSAGE,
-                    new String[] {name, optionalNames}, null, getClass(), null);
-            throw new CheckstyleException(exceptionMessage.getViolation());
+            final LocalizedMessage exceptionMessage = new LocalizedMessage(
+                    Definitions.CHECKSTYLE_BUNDLE, getClass(),
+                    AMBIGUOUS_MODULE_NAME_EXCEPTION_MESSAGE, name, optionalNames);
+            throw new CheckstyleException(exceptionMessage.getMessage());
         }
         return returnValue;
     }
diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/api/Violation.java b/src/main/java/com/puppycrawl/tools/checkstyle/api/Violation.java
--- a/src/main/java/com/puppycrawl/tools/checkstyle/api/Violation.java
+++ b/src/main/java/com/puppycrawl/tools/checkstyle/api/Violation.java
@@ -46,9 +46,6 @@ public final class Violation
     /** The default severity level if one is not specified. */
     private static final SeverityLevel DEFAULT_SEVERITY = SeverityLevel.ERROR;
 
-    /** The locale to localise violations to. **/
-    private static Locale sLocale = Locale.getDefault();
-
     /** The line number. **/
     private final int lineNo;
     /** The column number. **/
@@ -358,20 +355,6 @@ public String getSourceName() {
         return sourceClass.getName();
     }
 
-    /**
-     * Sets a locale to use for localization.
-     *
-     * @param locale the locale to use for localization
-     */
-    public static void setLocale(Locale locale) {
-        if (Locale.ENGLISH.getLanguage().equals(locale.getLanguage())) {
-            sLocale = Locale.ROOT;
-        }
-        else {
-            sLocale = locale;
-        }
-    }
-
     /**
      * Indicates whether some other object is "equal to" this one.
      * Suppression on enumeration is needed so code stays consistent.
@@ -448,26 +431,15 @@ else if (other.moduleId == null) {
      * @return the translated violation
      */
     public String getViolation() {
-        String violation = getCustomViolation();
+        final String violation;
 
-        if (violation == null) {
-            violation = new LocalizedMessage(bundle, sLocale, sourceClass, key, args).getMessage();
-        }
-        return violation;
-    }
-
-    /**
-     * Returns the formatted custom violation if one is configured.
-     *
-     * @return the formatted custom violation or {@code null}
-     *          if there is no custom violation
-     */
-    private String getCustomViolation() {
-        String violation = null;
         if (customMessage != null) {
-            final MessageFormat formatter = new MessageFormat(customMessage, Locale.ROOT);
-            violation = formatter.format(args);
+            violation = new MessageFormat(customMessage, Locale.ROOT).format(args);
+        }
+        else {
+            violation = new LocalizedMessage(bundle, sourceClass, key, args).getMessage();
         }
+
         return violation;
     }
 
diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/checks/TranslationCheck.java b/src/main/java/com/puppycrawl/tools/checkstyle/checks/TranslationCheck.java
--- a/src/main/java/com/puppycrawl/tools/checkstyle/checks/TranslationCheck.java
+++ b/src/main/java/com/puppycrawl/tools/checkstyle/checks/TranslationCheck.java
@@ -45,6 +45,7 @@
 
 import com.puppycrawl.tools.checkstyle.Definitions;
 import com.puppycrawl.tools.checkstyle.GlobalStatefulCheck;
+import com.puppycrawl.tools.checkstyle.LocalizedMessage;
 import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck;
 import com.puppycrawl.tools.checkstyle.api.FileText;
 import com.puppycrawl.tools.checkstyle.api.MessageDispatcher;
@@ -318,11 +319,9 @@ public void setRequiredTranslations(String... translationCodes) {
     private void validateUserSpecifiedLanguageCodes(Set<String> languageCodes) {
         for (String code : languageCodes) {
             if (!isValidLanguageCode(code)) {
-                final Violation msg = new Violation(1, TRANSLATION_BUNDLE,
-                        WRONG_LANGUAGE_CODE_KEY, new Object[] {code}, getId(), getClass(), null);
-                final String exceptionMessage = String.format(Locale.ROOT,
-                        "%s [%s]", msg.getViolation(), TranslationCheck.class.getSimpleName());
-                throw new IllegalArgumentException(exceptionMessage);
+                final LocalizedMessage msg = new LocalizedMessage(TRANSLATION_BUNDLE,
+                        getClass(), WRONG_LANGUAGE_CODE_KEY, code);
+                throw new IllegalArgumentException(msg.getMessage());
             }
         }
     }


Test patch:
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/CheckerTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/CheckerTest.java
--- a/src/test/java/com/puppycrawl/tools/checkstyle/CheckerTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/CheckerTest.java
@@ -491,7 +491,7 @@ public void testFinishLocalSetupFullyInitialized() throws Exception {
             .that(context.get("basedir"))
             .isEqualTo("testBaseDir");
 
-        final Field sLocale = Violation.class.getDeclaredField("sLocale");
+        final Field sLocale = LocalizedMessage.class.getDeclaredField("sLocale");
         sLocale.setAccessible(true);
         final Locale locale = (Locale) sLocale.get(null);
         assertWithMessage("Locale is set to unexpected value")
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/DefaultLoggerTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/DefaultLoggerTest.java
--- a/src/test/java/com/puppycrawl/tools/checkstyle/DefaultLoggerTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/DefaultLoggerTest.java
@@ -307,17 +307,17 @@ public void testStreamsNotClosedByLogger() throws IOException {
     }
 
     private static LocalizedMessage getAuditStartMessageClass() {
-        return new LocalizedMessage(Definitions.CHECKSTYLE_BUNDLE, Locale.getDefault(),
+        return new LocalizedMessage(Definitions.CHECKSTYLE_BUNDLE,
                 DefaultLogger.class, "DefaultLogger.auditStarted");
     }
 
     private static LocalizedMessage getAuditFinishMessageClass() {
-        return new LocalizedMessage(Definitions.CHECKSTYLE_BUNDLE, Locale.getDefault(),
+        return new LocalizedMessage(Definitions.CHECKSTYLE_BUNDLE,
                 DefaultLogger.class, "DefaultLogger.auditFinished");
     }
 
     private static LocalizedMessage getAddExceptionMessageClass(Object... arguments) {
-        return new LocalizedMessage(Definitions.CHECKSTYLE_BUNDLE, Locale.getDefault(),
+        return new LocalizedMessage(Definitions.CHECKSTYLE_BUNDLE,
                 DefaultLogger.class, "DefaultLogger.addException", arguments);
     }
 
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/DetailNodeTreeStringPrinterTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/DetailNodeTreeStringPrinterTest.java
--- a/src/test/java/com/puppycrawl/tools/checkstyle/DetailNodeTreeStringPrinterTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/DetailNodeTreeStringPrinterTest.java
@@ -30,7 +30,6 @@
 import org.junit.jupiter.api.Test;
 
 import com.puppycrawl.tools.checkstyle.JavadocDetailNodeParser.ParseErrorMessage;
-import com.puppycrawl.tools.checkstyle.api.Violation;
 import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
 
 public class DetailNodeTreeStringPrinterTest extends AbstractTreeTestSupport {
@@ -83,15 +82,13 @@ public void testMissedHtmlTagParseErrorMessage() throws Exception {
         final String actual = TestUtil.invokeStaticMethod(DetailNodeTreeStringPrinter.class,
                 "getParseErrorMessage",
                 new ParseErrorMessage(35, MSG_JAVADOC_MISSED_HTML_CLOSE, 7, "xyz"));
-        final Violation violation = new Violation(
-                35,
+        final LocalizedMessage violation = new LocalizedMessage(
                 "com.puppycrawl.tools.checkstyle.checks.javadoc.messages",
-                MSG_JAVADOC_MISSED_HTML_CLOSE,
-                new Object[] {7, "xyz"},
-                "",
                 DetailNodeTreeStringPrinter.class,
-                null);
-        final String expected = "[ERROR:35] " + violation.getViolation();
+                MSG_JAVADOC_MISSED_HTML_CLOSE,
+                7,
+                "xyz");
+        final String expected = "[ERROR:35] " + violation.getMessage();
         assertWithMessage("Javadoc parse error violation for missed HTML tag "
                 + "doesn't meet expectations")
             .that(actual)
@@ -104,15 +101,13 @@ public void testParseErrorMessage() throws Exception {
                 "getParseErrorMessage",
                 new ParseErrorMessage(10, MSG_JAVADOC_PARSE_RULE_ERROR,
                         9, "no viable alternative at input ' xyz'", "SOME_JAVADOC_ELEMENT"));
-        final Violation violation = new Violation(
-                10,
+        final LocalizedMessage violation = new LocalizedMessage(
                 "com.puppycrawl.tools.checkstyle.checks.javadoc.messages",
-                MSG_JAVADOC_PARSE_RULE_ERROR,
-                new Object[] {9, "no viable alternative at input ' xyz'", "SOME_JAVADOC_ELEMENT"},
-                "",
                 DetailNodeTreeStringPrinter.class,
-                null);
-        final String expected = "[ERROR:10] " + violation.getViolation();
+                MSG_JAVADOC_PARSE_RULE_ERROR,
+                9,
+                "no viable alternative at input ' xyz'", "SOME_JAVADOC_ELEMENT");
+        final String expected = "[ERROR:10] " + violation.getMessage();
         assertWithMessage("Javadoc parse error violation doesn't meet expectations")
             .that(actual)
             .isEqualTo(expected);
@@ -124,15 +119,13 @@ public void testWrongSingletonParseErrorMessage() throws Exception {
                 "getParseErrorMessage",
                 new ParseErrorMessage(100, MSG_JAVADOC_WRONG_SINGLETON_TAG,
                         9, "tag"));
-        final Violation violation = new Violation(
-                100,
+        final LocalizedMessage violation = new LocalizedMessage(
                 "com.puppycrawl.tools.checkstyle.checks.javadoc.messages",
-                MSG_JAVADOC_WRONG_SINGLETON_TAG,
-                new Object[] {9, "tag"},
-                "",
                 DetailNodeTreeStringPrinter.class,
-                null);
-        final String expected = "[ERROR:100] " + violation.getViolation();
+                MSG_JAVADOC_WRONG_SINGLETON_TAG,
+                9,
+                "tag");
+        final String expected = "[ERROR:100] " + violation.getMessage();
         assertWithMessage("Javadoc parse error violation for void elements with close tag "
                     + "doesn't meet expectations")
             .that(actual)
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/LocalizedMessageTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/LocalizedMessageTest.java
--- a/src/test/java/com/puppycrawl/tools/checkstyle/LocalizedMessageTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/LocalizedMessageTest.java
@@ -20,6 +20,7 @@
 package com.puppycrawl.tools.checkstyle;
 
 import static com.google.common.truth.Truth.assertWithMessage;
+import static org.junit.jupiter.api.Assumptions.assumeFalse;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -30,7 +31,9 @@
 import java.util.ResourceBundle;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Test;
+import org.junitpioneer.jupiter.DefaultLocale;
 
 import com.puppycrawl.tools.checkstyle.LocalizedMessage.Utf8Control;
 
@@ -45,16 +48,18 @@
  */
 public class LocalizedMessageTest {
 
+    private static final Locale DEFAULT_LOCALE = Locale.getDefault();
+
     @Test
     public void testNullArgs() {
         final LocalizedMessage messageClass = new LocalizedMessage(Definitions.CHECKSTYLE_BUNDLE,
-                Locale.getDefault(), DefaultLogger.class, "DefaultLogger.addException", "myfile");
+                DefaultLogger.class, "DefaultLogger.addException", "myfile");
         assertWithMessage("Violation should contain exception info")
                 .that(messageClass.getMessage())
                 .contains("Error auditing myfile");
 
         final LocalizedMessage nullClass = new LocalizedMessage(Definitions.CHECKSTYLE_BUNDLE,
-                Locale.getDefault(), DefaultLogger.class, "DefaultLogger.addException");
+                DefaultLogger.class, "DefaultLogger.addException");
         final String outputForNullArgs = nullClass.getMessage();
         assertWithMessage("Violation should contain exception info")
                 .that(outputForNullArgs)
@@ -206,6 +211,74 @@ protected URLConnection openConnection(URL ignore) {
                 .isNull();
     }
 
+    /**
+     * Verifies that the language specified with the system property {@code user.language} exists.
+     */
+    @Test
+    public void testLanguageIsValid() {
+        final String language = DEFAULT_LOCALE.getLanguage();
+        assumeFalse(language.isEmpty(), "Locale not set");
+        assertWithMessage("Invalid language")
+                .that(Locale.getISOLanguages())
+                .asList()
+                .contains(language);
+    }
+
+    /**
+     * Verifies that the country specified with the system property {@code user.country} exists.
+     */
+    @Test
+    public void testCountryIsValid() {
+        final String country = DEFAULT_LOCALE.getCountry();
+        assumeFalse(country.isEmpty(), "Locale not set");
+        assertWithMessage("Invalid country")
+                .that(Locale.getISOCountries())
+                .asList()
+                .contains(country);
+    }
+
+    @Test
+    public void testMessageInFrench() {
+        final LocalizedMessage violation = createSampleViolation();
+        LocalizedMessage.setLocale(Locale.FRENCH);
+
+        assertWithMessage("Invalid violation")
+            .that(violation.getMessage())
+            .isEqualTo("Instruction vide.");
+    }
+
+    @DefaultLocale("fr")
+    @Test
+    public void testEnforceEnglishLanguageBySettingUnitedStatesLocale() {
+        LocalizedMessage.setLocale(Locale.US);
+        final LocalizedMessage violation = createSampleViolation();
+
+        assertWithMessage("Invalid violation")
+            .that(violation.getMessage())
+            .isEqualTo("Empty statement.");
+    }
+
+    @DefaultLocale("fr")
+    @Test
+    public void testEnforceEnglishLanguageBySettingRootLocale() {
+        LocalizedMessage.setLocale(Locale.ROOT);
+        final LocalizedMessage violation = createSampleViolation();
+
+        assertWithMessage("Invalid violation")
+            .that(violation.getMessage())
+            .isEqualTo("Empty statement.");
+    }
+
+    private static LocalizedMessage createSampleViolation() {
+        return new LocalizedMessage("com.puppycrawl.tools.checkstyle.checks.coding.messages",
+                LocalizedMessage.class, "empty.statement");
+    }
+
+    @AfterEach
+    public void tearDown() {
+        LocalizedMessage.setLocale(DEFAULT_LOCALE);
+    }
+
     /**
      * Mocked ClassLoader for testing URL loading.
      *
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/MainTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/MainTest.java
--- a/src/test/java/com/puppycrawl/tools/checkstyle/MainTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/MainTest.java
@@ -186,16 +186,16 @@ public class MainTest {
     @TempDir
     public File temporaryFolder;
 
-    private final Violation auditStartMessage = new Violation(1,
-            Definitions.CHECKSTYLE_BUNDLE, "DefaultLogger.auditStarted", null, null,
-            getClass(), null);
+    private final LocalizedMessage auditStartMessage = new LocalizedMessage(
+            Definitions.CHECKSTYLE_BUNDLE, getClass(),
+            "DefaultLogger.auditStarted");
 
-    private final Violation auditFinishMessage = new Violation(1,
-            Definitions.CHECKSTYLE_BUNDLE, "DefaultLogger.auditFinished", null, null,
-            getClass(), null);
+    private final LocalizedMessage auditFinishMessage = new LocalizedMessage(
+            Definitions.CHECKSTYLE_BUNDLE, getClass(),
+            "DefaultLogger.auditFinished");
 
-    private final String noViolationsOutput = auditStartMessage.getViolation() + EOL
-                    + auditFinishMessage.getViolation() + EOL;
+    private final String noViolationsOutput = auditStartMessage.getMessage() + EOL
+                    + auditFinishMessage.getMessage() + EOL;
 
     private static String getPath(String filename) {
         return "src/test/resources/com/puppycrawl/tools/checkstyle/main/" + filename;
@@ -388,8 +388,8 @@ public void testExistingTargetFile(@SysErr Capturable systemErr, @SysOut Captura
                 getPath("InputMain.java"));
         assertWithMessage("Unexpected output log")
             .that(systemOut.getCapturedData())
-            .isEqualTo(addEndOfLine(auditStartMessage.getViolation(),
-                auditFinishMessage.getViolation()));
+            .isEqualTo(addEndOfLine(auditStartMessage.getMessage(),
+                auditFinishMessage.getMessage()));
         assertWithMessage("Unexpected system error log")
             .that(systemErr.getCapturedData())
             .isEqualTo("");
@@ -470,8 +470,8 @@ public void testExistingTargetFilePlainOutput(@SysErr Capturable systemErr,
                 getPath("InputMain.java"));
         assertWithMessage("Unexpected output log")
             .that(systemOut.getCapturedData())
-            .isEqualTo(addEndOfLine(auditStartMessage.getViolation(),
-                auditFinishMessage.getViolation()));
+            .isEqualTo(addEndOfLine(auditStartMessage.getMessage(),
+                auditFinishMessage.getMessage()));
         assertWithMessage("Unexpected system error log")
             .that(systemErr.getCapturedData())
             .isEqualTo("");
@@ -493,14 +493,14 @@ public void testExistingTargetFileWithViolations(@SysErr Capturable systemErr,
         final String expectedPath = getFilePath("InputMain.java");
         assertWithMessage("Unexpected output log")
             .that(systemOut.getCapturedData())
-            .isEqualTo(addEndOfLine(auditStartMessage.getViolation(),
+            .isEqualTo(addEndOfLine(auditStartMessage.getMessage(),
                     "[WARN] " + expectedPath + ":3:14: "
                         + invalidPatternMessageMain.getViolation()
                         + " [TypeName]",
                     "[WARN] " + expectedPath + ":5:7: "
                         + invalidPatternMessageMainInner.getViolation()
                         + " [TypeName]",
-                    auditFinishMessage.getViolation()));
+                    auditFinishMessage.getMessage()));
         assertWithMessage("Unexpected system error log")
             .that(systemErr.getCapturedData())
             .isEqualTo("");
@@ -555,12 +555,12 @@ public void testExistingTargetFileWithError(@SysErr Capturable systemErr,
         final String expectedPath = getFilePath("InputMain.java");
         assertWithMessage("Unexpected output log")
             .that(systemOut.getCapturedData())
-            .isEqualTo(addEndOfLine(auditStartMessage.getViolation(),
+            .isEqualTo(addEndOfLine(auditStartMessage.getMessage(),
                     "[ERROR] " + expectedPath + ":3:14: "
                         + invalidPatternMessageMain.getViolation() + " [TypeName]",
                     "[ERROR] " + expectedPath + ":5:7: "
                         + invalidPatternMessageMainInner.getViolation() + " [TypeName]",
-                    auditFinishMessage.getViolation()));
+                    auditFinishMessage.getMessage()));
         assertWithMessage("Unexpected system error log")
             .that(systemErr.getCapturedData())
             .isEqualTo(addEndOfLine(errorCounterTwoMessage.getViolation()));
@@ -588,10 +588,10 @@ public void testExistingTargetFileWithOneError(@SysErr Capturable systemErr,
         final String expectedPath = getFilePath("InputMain1.java");
         assertWithMessage("Unexpected output log")
             .that(systemOut.getCapturedData())
-            .isEqualTo(addEndOfLine(auditStartMessage.getViolation(),
+            .isEqualTo(addEndOfLine(auditStartMessage.getMessage(),
                     "[ERROR] " + expectedPath + ":3:14: "
                         + invalidPatternMessageMain.getViolation() + " [TypeName]",
-                    auditFinishMessage.getViolation()));
+                    auditFinishMessage.getMessage()));
         assertWithMessage("Unexpected system error log")
             .that(systemErr.getCapturedData())
             .isEqualTo(addEndOfLine(errorCounterTwoMessage.getViolation()));
@@ -611,9 +611,9 @@ public void testExistingTargetFileWithOneErrorAgainstSunCheck(@SysErr Capturable
         final String expectedPath = getFilePath("InputMain1.java");
         assertWithMessage("Unexpected output log")
             .that(systemOut.getCapturedData())
-            .isEqualTo(addEndOfLine(auditStartMessage.getViolation(),
+            .isEqualTo(addEndOfLine(auditStartMessage.getMessage(),
                 "[ERROR] " + expectedPath + ":1: " + message.getViolation() + " [JavadocPackage]",
-                auditFinishMessage.getViolation()));
+                auditFinishMessage.getMessage()));
         assertWithMessage("Unexpected system error log")
             .that(systemErr.getCapturedData())
             .isEqualTo(addEndOfLine(errorCounterTwoMessage.getViolation()));
@@ -670,8 +670,8 @@ public void testExistingTargetFilePlainOutputProperties(@SysErr Capturable syste
                 "-p", getPath("InputMainMycheckstyle.properties"), getPath("InputMain.java"));
         assertWithMessage("Unexpected output log")
             .that(systemOut.getCapturedData())
-            .isEqualTo(addEndOfLine(auditStartMessage.getViolation(),
-                auditFinishMessage.getViolation()));
+            .isEqualTo(addEndOfLine(auditStartMessage.getMessage(),
+                auditFinishMessage.getMessage()));
         assertWithMessage("Unexpected system error log")
             .that(systemErr.getCapturedData())
             .isEqualTo("");
@@ -685,8 +685,8 @@ public void testPropertyFileWithPropertyChaining(@SysErr Capturable systemErr,
 
         assertWithMessage("Unexpected output log")
             .that(systemOut.getCapturedData())
-            .isEqualTo(addEndOfLine(auditStartMessage.getViolation(),
-                auditFinishMessage.getViolation()));
+            .isEqualTo(addEndOfLine(auditStartMessage.getMessage(),
+                auditFinishMessage.getMessage()));
         assertWithMessage("Unexpected system error log")
             .that(systemErr.getCapturedData())
             .isEqualTo("");
@@ -813,7 +813,7 @@ public void testExistingDirectoryWithViolations(@SysErr Capturable systemErr,
                 getPath(""));
         final String expectedPath = getFilePath("") + File.separator;
         final StringBuilder sb = new StringBuilder(28);
-        sb.append(auditStartMessage.getViolation())
+        sb.append(auditStartMessage.getMessage())
                 .append(EOL);
         final String format = "[WARN] " + expectedPath + outputValues[0][0] + ".java:"
                 + outputValues[0][1] + ": ";
@@ -824,7 +824,7 @@ public void testExistingDirectoryWithViolations(@SysErr Capturable systemErr,
             final String line = format + violation + " [FileLength]";
             sb.append(line).append(EOL);
         }
-        sb.append(auditFinishMessage.getViolation())
+        sb.append(auditFinishMessage.getMessage())
                 .append(EOL);
         assertWithMessage("Unexpected output log")
             .that(systemOut.getCapturedData())
@@ -1740,19 +1740,20 @@ public void testCustomSimpleRootModule(@SysErr Capturable systemErr) {
         assertMainReturnCode(-2, "-c", getPath("InputMainConfig-custom-simple-root-module.xml"),
                 getPath("InputMain.java"));
         final String checkstylePackage = "com.puppycrawl.tools.checkstyle.";
-        final Violation unableToInstantiateExceptionMessage = new Violation(1,
+        final LocalizedMessage unableToInstantiateExceptionMessage = new LocalizedMessage(
                 Definitions.CHECKSTYLE_BUNDLE,
+                getClass(),
                 "PackageObjectFactory.unableToInstantiateExceptionMessage",
-                new String[] {"TestRootModuleChecker", checkstylePackage
+                "TestRootModuleChecker",
+                checkstylePackage
                         + "TestRootModuleChecker, "
                         + "TestRootModuleCheckerCheck, " + checkstylePackage
-                        + "TestRootModuleCheckerCheck"},
-                null, getClass(), null);
+                        + "TestRootModuleCheckerCheck");
         assertWithMessage(
                 "Unexpected system error log")
                         .that(systemErr.getCapturedData()
                                 .startsWith(checkstylePackage + "api.CheckstyleException: "
-                                        + unableToInstantiateExceptionMessage.getViolation()))
+                                        + unableToInstantiateExceptionMessage.getMessage()))
                         .isTrue();
         assertWithMessage("Invalid checker state")
                 .that(TestRootModuleChecker.isProcessed())
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/PackageObjectFactoryTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/PackageObjectFactoryTest.java
--- a/src/test/java/com/puppycrawl/tools/checkstyle/PackageObjectFactoryTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/PackageObjectFactoryTest.java
@@ -156,12 +156,12 @@ public void testMakeCheckFromName() {
             assertWithMessage("Exception is expected").fail();
         }
         catch (CheckstyleException ex) {
-            final Violation exceptionMessage = new Violation(1,
-                    Definitions.CHECKSTYLE_BUNDLE, UNABLE_TO_INSTANTIATE_EXCEPTION_MESSAGE,
-                    new String[] {name, null}, null, factory.getClass(), null);
+            final LocalizedMessage exceptionMessage = new LocalizedMessage(
+                    Definitions.CHECKSTYLE_BUNDLE, factory.getClass(),
+                    UNABLE_TO_INSTANTIATE_EXCEPTION_MESSAGE, name, null);
             assertWithMessage("Invalid exception message")
                 .that(ex.getMessage())
-                .isEqualTo(exceptionMessage.getViolation());
+                .isEqualTo(exceptionMessage.getMessage());
         }
     }
 
@@ -177,12 +177,12 @@ public void testCreateModuleWithNonExistName() {
                 final String attemptedNames = BASE_PACKAGE + PACKAGE_SEPARATOR + name
                     + STRING_SEPARATOR + name + CHECK_SUFFIX + STRING_SEPARATOR
                     + BASE_PACKAGE + PACKAGE_SEPARATOR + name + CHECK_SUFFIX;
-                final Violation exceptionMessage = new Violation(1,
-                    Definitions.CHECKSTYLE_BUNDLE, UNABLE_TO_INSTANTIATE_EXCEPTION_MESSAGE,
-                    new String[] {name, attemptedNames}, null, factory.getClass(), null);
+                final LocalizedMessage exceptionMessage = new LocalizedMessage(
+                    Definitions.CHECKSTYLE_BUNDLE, factory.getClass(),
+                    UNABLE_TO_INSTANTIATE_EXCEPTION_MESSAGE, name, attemptedNames);
                 assertWithMessage("Invalid exception message")
                     .that(ex.getMessage())
-                    .isEqualTo(exceptionMessage.getViolation());
+                    .isEqualTo(exceptionMessage.getMessage());
             }
         }
     }
@@ -250,12 +250,12 @@ public void testCreateObjectFromFullModuleNamesWithAmbiguousException() {
         catch (CheckstyleException ex) {
             final String optionalNames = barPackage + PACKAGE_SEPARATOR + name
                     + STRING_SEPARATOR + fooPackage + PACKAGE_SEPARATOR + name;
-            final Violation exceptionMessage = new Violation(1,
-                    Definitions.CHECKSTYLE_BUNDLE, AMBIGUOUS_MODULE_NAME_EXCEPTION_MESSAGE,
-                    new String[] {name, optionalNames}, null, getClass(), null);
+            final LocalizedMessage exceptionMessage = new LocalizedMessage(
+                    Definitions.CHECKSTYLE_BUNDLE, getClass(),
+                    AMBIGUOUS_MODULE_NAME_EXCEPTION_MESSAGE, name, optionalNames);
             assertWithMessage("Invalid exception message")
                 .that(ex.getMessage())
-                .isEqualTo(exceptionMessage.getViolation());
+                .isEqualTo(exceptionMessage.getMessage());
         }
     }
 
@@ -278,12 +278,12 @@ public void testCreateObjectFromFullModuleNamesWithCantInstantiateException() {
                     + checkName + STRING_SEPARATOR
                     + package1 + PACKAGE_SEPARATOR + checkName + STRING_SEPARATOR
                     + package2 + PACKAGE_SEPARATOR + checkName;
-            final Violation exceptionMessage = new Violation(1,
-                    Definitions.CHECKSTYLE_BUNDLE, UNABLE_TO_INSTANTIATE_EXCEPTION_MESSAGE,
-                    new String[] {name, attemptedNames}, null, getClass(), null);
+            final LocalizedMessage exceptionMessage = new LocalizedMessage(
+                    Definitions.CHECKSTYLE_BUNDLE, getClass(),
+                    UNABLE_TO_INSTANTIATE_EXCEPTION_MESSAGE, name, attemptedNames);
             assertWithMessage("Invalid exception message")
                 .that(ex.getMessage())
-                .isEqualTo(exceptionMessage.getViolation());
+                .isEqualTo(exceptionMessage.getMessage());
         }
     }
 
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/api/ViolationTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/api/ViolationTest.java
--- a/src/test/java/com/puppycrawl/tools/checkstyle/api/ViolationTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/api/ViolationTest.java
@@ -21,11 +21,7 @@
 
 import static com.google.common.truth.Truth.assertWithMessage;
 import static com.puppycrawl.tools.checkstyle.utils.CommonUtil.EMPTY_OBJECT_ARRAY;
-import static org.junit.jupiter.api.Assumptions.assumeFalse;
 
-import java.util.Locale;
-
-import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Test;
 import org.junitpioneer.jupiter.DefaultLocale;
 
@@ -34,34 +30,6 @@
 
 public class ViolationTest {
 
-    private static final Locale DEFAULT_LOCALE = Locale.getDefault();
-
-    /**
-     * Verifies that the language specified with the system property {@code user.language} exists.
-     */
-    @Test
-    public void testLanguageIsValid() {
-        final String language = DEFAULT_LOCALE.getLanguage();
-        assumeFalse(language.isEmpty(), "Locale not set");
-        assertWithMessage("Invalid language")
-                .that(Locale.getISOLanguages())
-                .asList()
-                .contains(language);
-    }
-
-    /**
-     * Verifies that the country specified with the system property {@code user.country} exists.
-     */
-    @Test
-    public void testCountryIsValid() {
-        final String country = DEFAULT_LOCALE.getCountry();
-        assumeFalse(country.isEmpty(), "Locale not set");
-        assertWithMessage("Invalid country")
-                .that(Locale.getISOCountries())
-                .asList()
-                .contains(country);
-    }
-
     @Test
     public void testEqualsAndHashCode() {
         final EqualsVerifierReport ev = EqualsVerifier.forClass(Violation.class)
@@ -98,42 +66,10 @@ public void testGetSourceName() {
             .isEqualTo("com.puppycrawl.tools.checkstyle.api.Violation");
     }
 
+    @DefaultLocale("en")
     @Test
     public void testMessageInEnglish() {
         final Violation violation = createSampleViolation();
-        Violation.setLocale(Locale.ENGLISH);
-
-        assertWithMessage("Invalid violation")
-            .that(violation.getViolation())
-            .isEqualTo("Empty statement.");
-    }
-
-    @Test
-    public void testMessageInFrench() {
-        final Violation violation = createSampleViolation();
-        Violation.setLocale(Locale.FRENCH);
-
-        assertWithMessage("Invalid violation")
-            .that(violation.getViolation())
-            .isEqualTo("Instruction vide.");
-    }
-
-    @DefaultLocale("fr")
-    @Test
-    public void testEnforceEnglishLanguageBySettingUnitedStatesLocale() {
-        Violation.setLocale(Locale.US);
-        final Violation violation = createSampleViolation();
-
-        assertWithMessage("Invalid violation")
-            .that(violation.getViolation())
-            .isEqualTo("Empty statement.");
-    }
-
-    @DefaultLocale("fr")
-    @Test
-    public void testEnforceEnglishLanguageBySettingRootLocale() {
-        Violation.setLocale(Locale.ROOT);
-        final Violation violation = createSampleViolation();
 
         assertWithMessage("Invalid violation")
             .that(violation.getViolation())
@@ -143,7 +79,6 @@ public void testEnforceEnglishLanguageBySettingRootLocale() {
     @DefaultLocale("fr")
     @Test
     public void testGetKey() {
-        Violation.setLocale(Locale.US);
         final Violation violation = createSampleViolation();
 
         assertWithMessage("Invalid violation key")
@@ -252,9 +187,4 @@ private static Violation createSampleViolationWithColumn(int column) {
                 EMPTY_OBJECT_ARRAY, "module", Violation.class, null);
     }
 
-    @AfterEach
-    public void tearDown() {
-        Violation.setLocale(DEFAULT_LOCALE);
-    }
-
 }
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/checks/TranslationCheckTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/checks/TranslationCheckTest.java
--- a/src/test/java/com/puppycrawl/tools/checkstyle/checks/TranslationCheckTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/checks/TranslationCheckTest.java
@@ -231,12 +231,12 @@ public void testLogIoExceptionFileNotFound() throws Exception {
         assertWithMessage("expected number of errors to fire")
             .that(dispatcher.savedErrors)
             .hasSize(1);
-        final Violation violation = new Violation(1,
+        final Violation violation = new Violation(0,
                 Definitions.CHECKSTYLE_BUNDLE, "general.fileNotFound",
-                null, null, getClass(), null);
+                null, null, TranslationCheck.class, null);
         assertWithMessage("Invalid violation")
-            .that(dispatcher.savedErrors.iterator().next().getViolation())
-            .isEqualTo(violation.getViolation());
+            .that(dispatcher.savedErrors.iterator().next())
+            .isEqualTo(violation);
     }
 
     @Test
@@ -256,12 +256,12 @@ public void testLogIoException() throws Exception {
         assertWithMessage("expected number of errors to fire")
             .that(dispatcher.savedErrors.size())
             .isEqualTo(1);
-        final Violation violation = new Violation(1,
+        final Violation violation = new Violation(0,
                 Definitions.CHECKSTYLE_BUNDLE, "general.exception",
-                new String[] {exception.getMessage()}, null, getClass(), null);
+                new String[] {exception.getMessage()}, null, TranslationCheck.class, null);
         assertWithMessage("Invalid violation")
-            .that(dispatcher.savedErrors.iterator().next().getViolation())
-            .isEqualTo(violation.getViolation());
+            .that(dispatcher.savedErrors.iterator().next())
+            .isEqualTo(violation);
     }
 
     @Test
@@ -269,9 +269,9 @@ public void testLogIllegalArgumentException() throws Exception {
         final DefaultConfiguration checkConfig = createModuleConfig(TranslationCheck.class);
         checkConfig.addProperty("baseName", "^bad.*$");
         final String[] expected = {
-            "0: " + new Violation(1, Definitions.CHECKSTYLE_BUNDLE, "general.exception",
-                new String[] {"Malformed \\uxxxx encoding." }, null, getClass(),
-                    null).getViolation(), "1: " + getCheckMessage(MSG_KEY, "test"),
+            "0: " + getCheckMessage(Checker.class, "general.exception",
+                    "Malformed \\uxxxx encoding."),
+            "1: " + getCheckMessage(MSG_KEY, "test"),
         };
         final File[] propertyFiles = {
             new File(getPath("bad.properties")),
@@ -607,9 +607,6 @@ public void testWrongUserSpecifiedLanguageCodes() {
             assertWithMessage("Error message is unexpected")
                     .that(exceptionMessage)
                     .contains("11");
-            assertWithMessage("Error message is unexpected")
-                    .that(exceptionMessage)
-                    .endsWith("[TranslationCheck]");
         }
     }