diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/StringMatchFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/StringMatchFilterTest.java
new file mode 100644
index 00000000000..24a428f1626
--- /dev/null
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/StringMatchFilterTest.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.logging.log4j.core.filter;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for {@link StringMatchFilter}.
+ */
+class StringMatchFilterTest {
+
+ /**
+ * Test the normal valid programmatic instantiation of a {@link StringMatchFilter} via its builder.
+ */
+ @Test
+ void testFilterBuilderOK() {
+ StringMatchFilter.Builder stringMatchFilterBuilder = StringMatchFilter.newBuilder();
+ stringMatchFilterBuilder.setText("foo");
+ StringMatchFilter stringMatchFilter = stringMatchFilterBuilder.build();
+ assertNotNull(stringMatchFilter, "The filter should not be null.");
+ assertEquals("foo", stringMatchFilter.getText());
+ }
+
+ /**
+ * Test that if no match-string is set on the builder, the '{@link StringMatchFilter.Builder#build()}' returns
+ * {@code null}.
+ */
+ @Test
+ void testFilterBuilderFailsWithNullText() {
+ StringMatchFilter.Builder stringMatchFilterBuilder = StringMatchFilter.newBuilder();
+ Assertions.assertNull(stringMatchFilterBuilder.build());
+ }
+
+ /**
+ * Test that if a {@code null} string is set as a match-pattern, a {@link NullPointerException} is thrown.
+ */
+ @Test
+ @SuppressWarnings({"DataFlowIssue" // invalid null parameter explicitly being tested
+ })
+ void testFilterBuilderFailsWithExceptionOnNullText() {
+ StringMatchFilter.Builder stringMatchFilterBuilder = StringMatchFilter.newBuilder();
+ Assertions.assertThrows(NullPointerException.class, () -> stringMatchFilterBuilder.setText(null));
+ }
+
+ /**
+ * Test that if an empty ({@code ""}) string is set as a match-pattern, an {@code IllegalArgumentException} is thrown.
+ */
+ @Test
+ void testFilterBuilderFailsWithExceptionOnEmptyText() {
+ StringMatchFilter.Builder stringMatchFilterBuilder = StringMatchFilter.newBuilder();
+ Assertions.assertThrows(IllegalArgumentException.class, () -> stringMatchFilterBuilder.setText(""));
+ }
+
+ /**
+ * Test that if a {@link StringMatchFilter} is specified with a 'text' attribute it is correctly instantiated.
+ *
+ * @param configuration the configuration
+ */
+ @Test
+ @LoggerContextSource("log4j2-stringmatchfilter-3153-ok.xml")
+ void testConfigurationWithTextPOS(final Configuration configuration) {
+ final Filter filter = configuration.getFilter();
+ assertNotNull(filter, "The filter should not be null.");
+ assertInstanceOf(
+ StringMatchFilter.class, filter, "Expected a StringMatchFilter, but got: " + filter.getClass());
+ assertEquals("FooBar", ((StringMatchFilter) filter).getText());
+ }
+
+ /**
+ * Test that if a {@link StringMatchFilter} is specified without a 'text' attribute it is not instantiated.
+ *
+ *
+ * @param configuration the configuration
+ */
+ @Test
+ @LoggerContextSource("log4j2-stringmatchfilter-3153-nok.xml")
+ void testConfigurationWithTextNEG(final Configuration configuration) {
+ final Filter filter = configuration.getFilter();
+ assertNull(filter, "The filter should be null.");
+ }
+}
diff --git a/log4j-core-test/src/test/resources/log4j2-stringmatchfilter-3153-nok.xml b/log4j-core-test/src/test/resources/log4j2-stringmatchfilter-3153-nok.xml
new file mode 100644
index 00000000000..607a6ada7e0
--- /dev/null
+++ b/log4j-core-test/src/test/resources/log4j2-stringmatchfilter-3153-nok.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
diff --git a/log4j-core-test/src/test/resources/log4j2-stringmatchfilter-3153-ok.xml b/log4j-core-test/src/test/resources/log4j2-stringmatchfilter-3153-ok.xml
new file mode 100644
index 00000000000..598dfaa3025
--- /dev/null
+++ b/log4j-core-test/src/test/resources/log4j2-stringmatchfilter-3153-ok.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/StringMatchFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/StringMatchFilter.java
index 51ee3b2a201..155c59ee450 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/StringMatchFilter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/StringMatchFilter.java
@@ -16,6 +16,7 @@
*/
package org.apache.logging.log4j.core.filter;
+import java.util.Objects;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.core.Filter;
@@ -26,7 +27,10 @@
import org.apache.logging.log4j.plugins.Plugin;
import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
import org.apache.logging.log4j.plugins.PluginFactory;
+import org.apache.logging.log4j.plugins.util.Assert;
+import org.apache.logging.log4j.plugins.validation.constraints.Required;
import org.apache.logging.log4j.util.PerformanceSensitive;
+import org.jspecify.annotations.NonNull;
/**
* This filter returns the onMatch result if the message in the event matches the specified text
@@ -37,12 +41,15 @@
@PerformanceSensitive("allocation")
public final class StringMatchFilter extends AbstractFilter {
- public static final String ATTR_MATCH = "match";
private final String text;
- private StringMatchFilter(final String text, final Result onMatch, final Result onMismatch) {
- super(onMatch, onMismatch);
- this.text = text;
+ private StringMatchFilter(final Builder builder) {
+ super(builder.getOnMatch(), builder.getOnMismatch());
+ this.text = Assert.requireNonEmpty(builder.text, "The 'text' argument must not be null or empty.");
+ }
+
+ public String getText() {
+ return text;
}
@Override
@@ -230,28 +237,35 @@ public String toString() {
}
@PluginFactory
- public static StringMatchFilter.Builder newBuilder() {
- return new StringMatchFilter.Builder();
+ public static Builder newBuilder() {
+ return new Builder();
}
- public static class Builder extends AbstractFilterBuilder
- implements org.apache.logging.log4j.core.util.Builder {
+ public static class Builder extends AbstractFilterBuilder
+ implements org.apache.logging.log4j.plugins.util.Builder {
+
@PluginBuilderAttribute
- private String text = "";
+ @Required(message = "No text provided for StringMatchFilter")
+ private String text;
/**
* Sets the text to search in event messages.
* @param text the text to search in event messages.
* @return this instance.
*/
- public StringMatchFilter.Builder setMatchString(final String text) {
- this.text = text;
+ public Builder setText(@NonNull final String text) {
+ Objects.requireNonNull(text, "The 'text' argument must not be null.");
+ this.text = Assert.requireNonEmpty(text, "The 'text' argument must not be empty.");
return this;
}
@Override
public StringMatchFilter build() {
- return new StringMatchFilter(this.text, this.getOnMatch(), this.getOnMismatch());
+ if (this.text == null) {
+ LOGGER.error("Unable to create StringMatchFilter: The 'text' attribute must be configured.");
+ return null;
+ }
+ return new StringMatchFilter(this);
}
}
}
diff --git a/src/changelog/.3.x.x/3509_fix_StringMatchFilter_Validation.xml b/src/changelog/.3.x.x/3509_fix_StringMatchFilter_Validation.xml
new file mode 100644
index 00000000000..897c339bdcc
--- /dev/null
+++ b/src/changelog/.3.x.x/3509_fix_StringMatchFilter_Validation.xml
@@ -0,0 +1,8 @@
+
+
+
+ Fix validation in StringMatchFilter.
+