You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by ma...@apache.org on 2022/03/27 02:51:53 UTC
[logging-log4j2] 03/03: Make TypeConverter plugins injectable
This is an automated email from the ASF dual-hosted git repository.
mattsicker pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit e8fdd738da0e7f67dbb04c4baaa400aa4ca7c0c2
Author: Matt Sicker <ma...@apache.org>
AuthorDate: Sat Mar 26 21:51:29 2022 -0500
Make TypeConverter plugins injectable
This adds Injector::getTypeConverter to replace some old utility classes for holding static state.
Signed-off-by: Matt Sicker <ma...@apache.org>
---
.../logging/log4j/cassandra/CassandraManager.java | 16 +-
.../config/plugins/convert/TypeConvertersTest.java | 28 +--
.../plugins/convert/CoreTypeConvertersTest.java | 25 ++-
.../log4j/core/appender/db/ColumnMapping.java | 24 ++-
.../config/plugins/convert/CoreTypeConverters.java | 37 ++--
.../plugins/visit/PluginAttributeVisitor.java | 18 +-
.../visit/PluginBuilderAttributeVisitor.java | 7 +-
.../logging/log4j/couchdb/CouchDbProvider.java | 14 +-
.../log4j/jdbc/appender/JdbcDatabaseManager.java | 40 ++--
.../json/util/RecyclerFactoryConverter.java | 3 +-
.../template/json/util/RecyclerFactoriesTest.java | 13 +-
.../logging/log4j/mongodb3/MongoDb3Provider.java | 33 ++--
.../plugins/convert/TypeConverterRegistryTest.java | 22 ++-
.../log4j/plugins/convert/TypeConverter.java | 38 +++-
.../plugins/convert/TypeConverterRegistry.java | 210 ---------------------
.../log4j/plugins/convert/TypeConverters.java | 96 ----------
.../logging/log4j/plugins/di/DefaultInjector.java | 128 +++++++++++++
.../apache/logging/log4j/plugins/di/Injector.java | 11 ++
.../validation/validators/ValidPortValidator.java | 15 +-
.../plugins/visit/PluginAttributeVisitor.java | 18 +-
.../visit/PluginBuilderAttributeVisitor.java | 15 +-
.../asciidoc/manual/json-template-layout.adoc.vm | 3 +-
22 files changed, 380 insertions(+), 434 deletions(-)
diff --git a/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraManager.java b/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraManager.java
index 7ae8393..88f87d7 100644
--- a/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraManager.java
+++ b/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraManager.java
@@ -16,12 +16,6 @@
*/
package org.apache.logging.log4j.cassandra;
-import java.io.Serializable;
-import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
import com.datastax.driver.core.BatchStatement;
import com.datastax.driver.core.BoundStatement;
import com.datastax.driver.core.Cluster;
@@ -31,7 +25,6 @@ import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.ManagerFactory;
import org.apache.logging.log4j.core.appender.db.AbstractDatabaseManager;
import org.apache.logging.log4j.core.appender.db.ColumnMapping;
-import org.apache.logging.log4j.plugins.convert.TypeConverters;
import org.apache.logging.log4j.core.net.SocketAddress;
import org.apache.logging.log4j.jdbc.convert.DateTypeConverter;
import org.apache.logging.log4j.spi.ThreadContextMap;
@@ -39,6 +32,12 @@ import org.apache.logging.log4j.spi.ThreadContextStack;
import org.apache.logging.log4j.util.ReadOnlyStringMap;
import org.apache.logging.log4j.util.Strings;
+import java.io.Serializable;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
/**
* Manager for a Cassandra appender instance.
*/
@@ -99,8 +98,7 @@ public class CassandraManager extends AbstractDatabaseManager {
} else if (Date.class.isAssignableFrom(columnMapping.getType())) {
values[i] = DateTypeConverter.fromMillis(event.getTimeMillis(), columnMapping.getType().asSubclass(Date.class));
} else {
- values[i] = TypeConverters.convert(columnMapping.getLayout().toSerializable(event),
- columnMapping.getType(), null);
+ values[i] = columnMapping.getTypeConverter().convert(columnMapping.getLayout().toSerializable(event), null);
}
}
final BoundStatement boundStatement = preparedStatement.bind(values);
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConvertersTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConvertersTest.java
index 6e5e62f..0416d32 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConvertersTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConvertersTest.java
@@ -17,6 +17,17 @@
package org.apache.logging.log4j.core.config.plugins.convert;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.appender.rolling.action.Duration;
+import org.apache.logging.log4j.core.layout.GelfLayout;
+import org.apache.logging.log4j.core.net.Facility;
+import org.apache.logging.log4j.plugins.di.DI;
+import org.apache.logging.log4j.plugins.di.Injector;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
import java.io.File;
import java.math.BigDecimal;
import java.math.BigInteger;
@@ -33,17 +44,8 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.UUID;
-import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.core.Filter;
-import org.apache.logging.log4j.core.appender.rolling.action.Duration;
-import org.apache.logging.log4j.core.layout.GelfLayout;
-import org.apache.logging.log4j.core.net.Facility;
-import org.apache.logging.log4j.plugins.convert.TypeConverters;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
/**
* Tests {@link CoreTypeConverters}.
@@ -216,7 +218,9 @@ public class TypeConvertersTest {
@Test
public void testConvert() throws Exception {
- final Object actual = TypeConverters.convert(value, clazz, defaultValue);
+ final Injector injector = DI.createInjector();
+ injector.init();
+ final Object actual = injector.getTypeConverter(clazz).convert(value, defaultValue);
final String assertionMessage = "\nGiven: " + value + "\nDefault: " + defaultValue;
if (expected != null && expected instanceof char[]) {
assertArrayEquals(assertionMessage, (char[]) expected, (char[]) actual);
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/plugins/convert/CoreTypeConvertersTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/plugins/convert/CoreTypeConvertersTest.java
index 117ceea..1f13210 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/plugins/convert/CoreTypeConvertersTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/plugins/convert/CoreTypeConvertersTest.java
@@ -17,29 +17,37 @@
package org.apache.logging.log4j.core.plugins.convert;
import org.apache.logging.log4j.plugins.convert.TypeConverter;
-import org.apache.logging.log4j.plugins.convert.TypeConverterRegistry;
+import org.apache.logging.log4j.plugins.di.DI;
+import org.apache.logging.log4j.plugins.di.Injector;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class CoreTypeConvertersTest {
+ private final Injector injector = DI.createInjector();
+
+ @BeforeEach
+ void setUp() {
+ injector.init();
+ }
+
@Test
public void testFindNullConverter() {
- assertThrows(NullPointerException.class,
- () -> TypeConverterRegistry.getInstance().findCompatibleConverter(null));
+ assertThrows(NullPointerException.class, () -> injector.getTypeConverter(null));
}
@Test
public void testFindBooleanConverter() throws Exception {
- final TypeConverter<?> converter = TypeConverterRegistry.getInstance().findCompatibleConverter(Boolean.class);
+ final TypeConverter<?> converter = injector.getTypeConverter(Boolean.class);
assertNotNull(converter);
assertTrue((Boolean) converter.convert("TRUE"));
}
@Test
public void testFindPrimitiveBooleanConverter() throws Exception {
- final TypeConverter<?> converter = TypeConverterRegistry.getInstance().findCompatibleConverter(Boolean.TYPE);
+ final TypeConverter<?> converter = injector.getTypeConverter(Boolean.TYPE);
assertNotNull(converter);
assertTrue((Boolean) converter.convert("tRUe"));
}
@@ -48,7 +56,7 @@ public class CoreTypeConvertersTest {
@Test
public void testFindCharSequenceConverterUsingStringConverter() throws Exception {
final TypeConverter<CharSequence> converter = (TypeConverter<CharSequence>)
- TypeConverterRegistry.getInstance().findCompatibleConverter(CharSequence.class);
+ injector.getTypeConverter(CharSequence.class);
assertNotNull(converter);
final CharSequence expected = "This is a test sequence of characters";
final CharSequence actual = converter.convert(expected.toString());
@@ -59,7 +67,7 @@ public class CoreTypeConvertersTest {
@Test
public void testFindNumberConverter() throws Exception {
final TypeConverter<Number> numberTypeConverter = (TypeConverter<Number>)
- TypeConverterRegistry.getInstance().findCompatibleConverter(Number.class);
+ injector.getTypeConverter(Number.class);
assertNotNull(numberTypeConverter);
// TODO: is there a specific converter this should return?
}
@@ -71,8 +79,7 @@ public class CoreTypeConvertersTest {
@SuppressWarnings("unchecked")
@Test
public void testFindEnumConverter() throws Exception {
- final TypeConverter<Foo> fooTypeConverter = (TypeConverter<Foo>)
- TypeConverterRegistry.getInstance().findCompatibleConverter(Foo.class);
+ final TypeConverter<Foo> fooTypeConverter = (TypeConverter<Foo>) injector.getTypeConverter(Foo.class);
assertNotNull(fooTypeConverter);
assertEquals(Foo.I, fooTypeConverter.convert("i"));
assertEquals(Foo.PITY, fooTypeConverter.convert("pity"));
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/ColumnMapping.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/ColumnMapping.java
index 740ebc8..a58e4e2 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/ColumnMapping.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/ColumnMapping.java
@@ -22,10 +22,13 @@ import org.apache.logging.log4j.core.StringLayout;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.apache.logging.log4j.plugins.Inject;
import org.apache.logging.log4j.plugins.Plugin;
import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
import org.apache.logging.log4j.plugins.PluginElement;
import org.apache.logging.log4j.plugins.PluginFactory;
+import org.apache.logging.log4j.plugins.convert.TypeConverter;
+import org.apache.logging.log4j.plugins.di.Injector;
import org.apache.logging.log4j.plugins.validation.constraints.Required;
import org.apache.logging.log4j.spi.ThreadContextMap;
import org.apache.logging.log4j.spi.ThreadContextStack;
@@ -34,6 +37,7 @@ import org.apache.logging.log4j.util.ReadOnlyStringMap;
import java.util.Date;
import java.util.Locale;
+import java.util.function.Supplier;
/**
* A configuration element for specifying a database column name mapping.
@@ -74,6 +78,8 @@ public class ColumnMapping {
@Required(message = "No conversion type provided")
private Class<?> type = String.class;
+ private Injector injector;
+
@Override
public ColumnMapping build() {
if (pattern != null) {
@@ -96,7 +102,7 @@ public class ColumnMapping {
LOGGER.error("Only one of 'literal' or 'parameter' can be set on the column mapping {}", this);
return null;
}
- return new ColumnMapping(name, source, layout, literal, parameter, type);
+ return new ColumnMapping(name, source, layout, literal, parameter, type, () -> injector.getTypeConverter(type));
}
public Builder setConfiguration(final Configuration configuration) {
@@ -181,6 +187,12 @@ public class ColumnMapping {
return this;
}
+ @Inject
+ public Builder setInjector(final Injector injector) {
+ this.injector = injector;
+ return this;
+ }
+
@Override
public String toString() {
return "Builder [name=" + name + ", source=" + source + ", literal=" + literal + ", parameter=" + parameter
@@ -206,8 +218,11 @@ public class ColumnMapping {
private final String parameter;
private final String source;
private final Class<?> type;
+ private final Supplier<TypeConverter<?>> typeConverter;
- private ColumnMapping(final String name, final String source, final StringLayout layout, final String literalValue, final String parameter, final Class<?> type) {
+ private ColumnMapping(
+ final String name, final String source, final StringLayout layout, final String literalValue,
+ final String parameter, final Class<?> type, final Supplier<TypeConverter<?>> typeConverter) {
this.name = name;
this.nameKey = toKey(name);
this.source = source;
@@ -215,6 +230,7 @@ public class ColumnMapping {
this.literalValue = literalValue;
this.parameter = parameter;
this.type = type;
+ this.typeConverter = typeConverter;
}
public StringLayout getLayout() {
@@ -245,6 +261,10 @@ public class ColumnMapping {
return type;
}
+ public TypeConverter<?> getTypeConverter() {
+ return typeConverter.get();
+ }
+
@Override
public String toString() {
return "ColumnMapping [name=" + name + ", source=" + source + ", literalValue=" + literalValue + ", parameter="
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/CoreTypeConverters.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/CoreTypeConverters.java
index 352f347..dcf1804 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/CoreTypeConverters.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/CoreTypeConverters.java
@@ -22,7 +22,6 @@ import org.apache.logging.log4j.core.appender.rolling.action.Duration;
import org.apache.logging.log4j.core.util.CronExpression;
import org.apache.logging.log4j.plugins.Plugin;
import org.apache.logging.log4j.plugins.convert.TypeConverter;
-import org.apache.logging.log4j.plugins.convert.TypeConverters;
import org.apache.logging.log4j.util.LoaderUtil;
import java.io.File;
@@ -55,7 +54,7 @@ public final class CoreTypeConverters {
/**
* Parses a {@link String} into a {@link BigDecimal}.
*/
- @Plugin(name = "BigDecimal", category = TypeConverters.CATEGORY)
+ @Plugin(name = "BigDecimal", category = TypeConverter.CATEGORY)
public static class BigDecimalConverter implements TypeConverter<BigDecimal> {
@Override
public BigDecimal convert(final String s) {
@@ -66,7 +65,7 @@ public final class CoreTypeConverters {
/**
* Parses a {@link String} into a {@link BigInteger}.
*/
- @Plugin(name = "BigInteger", category = TypeConverters.CATEGORY)
+ @Plugin(name = "BigInteger", category = TypeConverter.CATEGORY)
public static class BigIntegerConverter implements TypeConverter<BigInteger> {
@Override
public BigInteger convert(final String s) {
@@ -84,7 +83,7 @@ public final class CoreTypeConverters {
* <li>String using {@link Charset#defaultCharset()} [TODO Should this be UTF-8 instead?]</li>
* </ul>
*/
- @Plugin(name = "ByteArray", category = TypeConverters.CATEGORY)
+ @Plugin(name = "ByteArray", category = TypeConverter.CATEGORY)
public static class ByteArrayConverter implements TypeConverter<byte[]> {
private static final String PREFIX_0x = "0x";
@@ -111,7 +110,7 @@ public final class CoreTypeConverters {
/**
* Converts a {@link String} into a {@code char[]}.
*/
- @Plugin(name = "CharacterArray", category = TypeConverters.CATEGORY)
+ @Plugin(name = "CharacterArray", category = TypeConverter.CATEGORY)
public static class CharArrayConverter implements TypeConverter<char[]> {
@Override
public char[] convert(final String s) {
@@ -122,7 +121,7 @@ public final class CoreTypeConverters {
/**
* Converts a {@link String} into a {@link Charset}.
*/
- @Plugin(name = "Charset", category = TypeConverters.CATEGORY)
+ @Plugin(name = "Charset", category = TypeConverter.CATEGORY)
public static class CharsetConverter implements TypeConverter<Charset> {
@Override
public Charset convert(final String s) {
@@ -133,7 +132,7 @@ public final class CoreTypeConverters {
/**
* Converts a {@link String} into a {@link Class}.
*/
- @Plugin(name = "Class", category = TypeConverters.CATEGORY)
+ @Plugin(name = "Class", category = TypeConverter.CATEGORY)
public static class ClassConverter implements TypeConverter<Class<?>> {
@Override
public Class<?> convert(final String s) throws ClassNotFoundException {
@@ -163,7 +162,7 @@ public final class CoreTypeConverters {
}
}
- @Plugin(name = "CronExpression", category = TypeConverters.CATEGORY)
+ @Plugin(name = "CronExpression", category = TypeConverter.CATEGORY)
public static class CronExpressionConverter implements TypeConverter<CronExpression> {
@Override
public CronExpression convert(final String s) throws Exception {
@@ -175,7 +174,7 @@ public final class CoreTypeConverters {
* Converts a {@link String} into a {@link Duration}.
* @since 2.5
*/
- @Plugin(name = "Duration", category = TypeConverters.CATEGORY)
+ @Plugin(name = "Duration", category = TypeConverter.CATEGORY)
public static class DurationConverter implements TypeConverter<Duration> {
@Override
public Duration convert(final String s) {
@@ -186,7 +185,7 @@ public final class CoreTypeConverters {
/**
* Converts a {@link String} into a {@link File}.
*/
- @Plugin(name = "File", category = TypeConverters.CATEGORY)
+ @Plugin(name = "File", category = TypeConverter.CATEGORY)
public static class FileConverter implements TypeConverter<File> {
@Override
public File convert(final String s) {
@@ -197,7 +196,7 @@ public final class CoreTypeConverters {
/**
* Converts a {@link String} into an {@link InetAddress}.
*/
- @Plugin(name = "InetAddress", category = TypeConverters.CATEGORY)
+ @Plugin(name = "InetAddress", category = TypeConverter.CATEGORY)
public static class InetAddressConverter implements TypeConverter<InetAddress> {
@Override
public InetAddress convert(final String s) throws Exception {
@@ -208,7 +207,7 @@ public final class CoreTypeConverters {
/**
* Converts a {@link String} into a Log4j {@link Level}. Returns {@code null} for invalid level names.
*/
- @Plugin(name = "Level", category = TypeConverters.CATEGORY)
+ @Plugin(name = "Level", category = TypeConverter.CATEGORY)
public static class LevelConverter implements TypeConverter<Level> {
@Override
public Level convert(final String s) {
@@ -220,7 +219,7 @@ public final class CoreTypeConverters {
* Converts a {@link String} into a {@link Path}.
* @since 2.8
*/
- @Plugin(name = "Path", category = TypeConverters.CATEGORY)
+ @Plugin(name = "Path", category = TypeConverter.CATEGORY)
public static class PathConverter implements TypeConverter<Path> {
@Override
public Path convert(final String s) throws Exception {
@@ -231,7 +230,7 @@ public final class CoreTypeConverters {
/**
* Converts a {@link String} into a {@link Pattern}.
*/
- @Plugin(name = "Pattern", category = TypeConverters.CATEGORY)
+ @Plugin(name = "Pattern", category = TypeConverter.CATEGORY)
public static class PatternConverter implements TypeConverter<Pattern> {
@Override
public Pattern convert(final String s) {
@@ -242,7 +241,7 @@ public final class CoreTypeConverters {
/**
* Converts a {@link String} into a {@link Provider}.
*/
- @Plugin(name = "SecurityProvider", category = TypeConverters.CATEGORY)
+ @Plugin(name = "SecurityProvider", category = TypeConverter.CATEGORY)
public static class SecurityProviderConverter implements TypeConverter<Provider> {
@Override
public Provider convert(final String s) {
@@ -253,7 +252,7 @@ public final class CoreTypeConverters {
/**
* Converts a {@link String} into a {@link URI}.
*/
- @Plugin(name = "URI", category = TypeConverters.CATEGORY)
+ @Plugin(name = "URI", category = TypeConverter.CATEGORY)
public static class UriConverter implements TypeConverter<URI> {
@Override
public URI convert(final String s) throws URISyntaxException {
@@ -264,7 +263,7 @@ public final class CoreTypeConverters {
/**
* Converts a {@link String} into a {@link URL}.
*/
- @Plugin(name = "URL", category = TypeConverters.CATEGORY)
+ @Plugin(name = "URL", category = TypeConverter.CATEGORY)
public static class UrlConverter implements TypeConverter<URL> {
@Override
public URL convert(final String s) throws MalformedURLException {
@@ -276,7 +275,7 @@ public final class CoreTypeConverters {
* Converts a {@link String} into a {@link UUID}.
* @since 2.8
*/
- @Plugin(name = "UUID", category = TypeConverters.CATEGORY)
+ @Plugin(name = "UUID", category = TypeConverter.CATEGORY)
public static class UuidConverter implements TypeConverter<UUID> {
@Override
public UUID convert(final String s) throws Exception {
@@ -284,7 +283,7 @@ public final class CoreTypeConverters {
}
}
- @Plugin(name = "ZoneId", category = TypeConverters.CATEGORY)
+ @Plugin(name = "ZoneId", category = TypeConverter.CATEGORY)
public static class ZoneIdConverter implements TypeConverter<ZoneId> {
@Override
public ZoneId convert(final String s) throws Exception {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visit/PluginAttributeVisitor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visit/PluginAttributeVisitor.java
index 798a400..4e138a8 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visit/PluginAttributeVisitor.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visit/PluginAttributeVisitor.java
@@ -21,7 +21,8 @@ import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.plugins.Inject;
import org.apache.logging.log4j.plugins.Named;
import org.apache.logging.log4j.plugins.Node;
-import org.apache.logging.log4j.plugins.convert.TypeConverters;
+import org.apache.logging.log4j.plugins.convert.TypeConverter;
+import org.apache.logging.log4j.plugins.di.Injector;
import org.apache.logging.log4j.plugins.di.Keys;
import org.apache.logging.log4j.plugins.name.AnnotatedElementAliasesProvider;
import org.apache.logging.log4j.plugins.name.AnnotatedElementNameProvider;
@@ -60,10 +61,14 @@ public class PluginAttributeVisitor implements NodeVisitor {
);
private final Function<String, String> stringSubstitutionStrategy;
+ private final Injector injector;
@Inject
- public PluginAttributeVisitor(@Named(Keys.SUBSTITUTOR_NAME) final Function<String, String> stringSubstitutionStrategy) {
+ public PluginAttributeVisitor(
+ @Named(Keys.SUBSTITUTOR_NAME) final Function<String, String> stringSubstitutionStrategy,
+ final Injector injector) {
this.stringSubstitutionStrategy = stringSubstitutionStrategy;
+ this.injector = injector;
}
@Override
@@ -71,10 +76,11 @@ public class PluginAttributeVisitor implements NodeVisitor {
final String name = AnnotatedElementNameProvider.getName(field);
final Collection<String> aliases = AnnotatedElementAliasesProvider.getAliases(field);
final Type targetType = field.getGenericType();
+ final TypeConverter<?> converter = injector.getTypeConverter(targetType);
final PluginAttribute annotation = field.getAnnotation(PluginAttribute.class);
final boolean sensitive = annotation.sensitive();
final Object value = node.removeMatchingAttribute(name, aliases)
- .map(stringSubstitutionStrategy.andThen(s -> TypeConverters.convert(s, targetType, null, sensitive)))
+ .map(stringSubstitutionStrategy.andThen(s -> (Object) converter.convert(s, null, sensitive)))
.orElseGet(() -> getDefaultValue(targetType, annotation));
StringBuilders.appendKeyDqValueWithJoiner(debugLog, name, sensitive ? "(***)" : value, ", ");
return value;
@@ -85,10 +91,11 @@ public class PluginAttributeVisitor implements NodeVisitor {
final String name = AnnotatedElementNameProvider.getName(parameter);
final Collection<String> aliases = AnnotatedElementAliasesProvider.getAliases(parameter);
final Type targetType = parameter.getParameterizedType();
+ final TypeConverter<?> converter = injector.getTypeConverter(targetType);
final PluginAttribute annotation = parameter.getAnnotation(PluginAttribute.class);
final boolean sensitive = annotation.sensitive();
final Object value = node.removeMatchingAttribute(name, aliases)
- .map(stringSubstitutionStrategy.andThen(s -> TypeConverters.convert(s, targetType, null, sensitive)))
+ .map(stringSubstitutionStrategy.andThen(s -> (Object) converter.convert(s, null, sensitive)))
.orElseGet(() -> getDefaultValue(targetType, annotation));
StringBuilders.appendKeyDqValueWithJoiner(debugLog, name, sensitive ? "(***)" : value, ", ");
return value;
@@ -99,7 +106,8 @@ public class PluginAttributeVisitor implements NodeVisitor {
if (extractor != null) {
return extractor.apply(annotation);
}
+ final TypeConverter<?> converter = injector.getTypeConverter(targetType);
final var value = stringSubstitutionStrategy.apply(annotation.defaultString());
- return Strings.isEmpty(value) ? null : TypeConverters.convert(value, targetType, null, false);
+ return Strings.isEmpty(value) ? null : converter.convert(value, null);
}
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visit/PluginBuilderAttributeVisitor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visit/PluginBuilderAttributeVisitor.java
index 9d6fe54..658b5f1 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visit/PluginBuilderAttributeVisitor.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visit/PluginBuilderAttributeVisitor.java
@@ -20,6 +20,7 @@ package org.apache.logging.log4j.core.config.plugins.visit;
import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
import org.apache.logging.log4j.plugins.Inject;
import org.apache.logging.log4j.plugins.Named;
+import org.apache.logging.log4j.plugins.di.Injector;
import org.apache.logging.log4j.plugins.di.Keys;
import java.lang.reflect.AnnotatedElement;
@@ -27,8 +28,10 @@ import java.util.function.Function;
public class PluginBuilderAttributeVisitor extends org.apache.logging.log4j.plugins.visit.PluginBuilderAttributeVisitor {
@Inject
- public PluginBuilderAttributeVisitor(@Named(Keys.SUBSTITUTOR_NAME) final Function<String, String> stringSubstitutionStrategy) {
- super(stringSubstitutionStrategy);
+ public PluginBuilderAttributeVisitor(
+ @Named(Keys.SUBSTITUTOR_NAME) final Function<String, String> stringSubstitutionStrategy,
+ final Injector injector) {
+ super(stringSubstitutionStrategy, injector);
}
@SuppressWarnings("deprecation")
diff --git a/log4j-couchdb/src/main/java/org/apache/logging/log4j/couchdb/CouchDbProvider.java b/log4j-couchdb/src/main/java/org/apache/logging/log4j/couchdb/CouchDbProvider.java
index 179096c..ad79830 100644
--- a/log4j-couchdb/src/main/java/org/apache/logging/log4j/couchdb/CouchDbProvider.java
+++ b/log4j-couchdb/src/main/java/org/apache/logging/log4j/couchdb/CouchDbProvider.java
@@ -16,14 +16,14 @@
*/
package org.apache.logging.log4j.couchdb;
-import java.lang.reflect.Method;
-
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.appender.nosql.NoSqlProvider;
import org.apache.logging.log4j.plugins.Plugin;
import org.apache.logging.log4j.plugins.PluginAttribute;
import org.apache.logging.log4j.plugins.PluginFactory;
-import org.apache.logging.log4j.plugins.convert.TypeConverters;
+import org.apache.logging.log4j.plugins.convert.TypeConverter;
+import org.apache.logging.log4j.plugins.di.Injector;
+import org.apache.logging.log4j.plugins.util.TypeUtil;
import org.apache.logging.log4j.plugins.validation.constraints.ValidHost;
import org.apache.logging.log4j.plugins.validation.constraints.ValidPort;
import org.apache.logging.log4j.status.StatusLogger;
@@ -32,6 +32,8 @@ import org.apache.logging.log4j.util.Strings;
import org.lightcouch.CouchDbClient;
import org.lightcouch.CouchDbProperties;
+import java.lang.reflect.Method;
+
/**
* The Apache CouchDB implementation of {@link NoSqlProvider}.
*/
@@ -89,7 +91,8 @@ public final class CouchDbProvider implements NoSqlProvider<CouchDbConnection> {
@PluginAttribute final String username,
@PluginAttribute(sensitive = true) final String password,
@PluginAttribute final String factoryClassName,
- @PluginAttribute final String factoryMethodName) {
+ @PluginAttribute final String factoryMethodName,
+ final Injector injector) {
CouchDbClient client;
String description;
if (Strings.isNotEmpty(factoryClassName) && Strings.isNotEmpty(factoryMethodName)) {
@@ -139,7 +142,8 @@ public final class CouchDbProvider implements NoSqlProvider<CouchDbConnection> {
LOGGER.warn("No protocol specified, using default port [http].");
}
- final int portInt = TypeConverters.convert(port, int.class, protocol.equals("https") ? HTTPS : HTTP);
+ final TypeConverter<Integer> converter = TypeUtil.cast(injector.getTypeConverter(Integer.class));
+ final int portInt = converter.convert(port, protocol.equals("https") ? HTTPS : HTTP);
if (Strings.isEmpty(username) || Strings.isEmpty(password)) {
LOGGER.error("You must provide a username and password for the CouchDB provider.");
diff --git a/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/JdbcDatabaseManager.java b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/JdbcDatabaseManager.java
index 4e9239d..4477cf9 100644
--- a/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/JdbcDatabaseManager.java
+++ b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/JdbcDatabaseManager.java
@@ -16,6 +16,24 @@
*/
package org.apache.logging.log4j.jdbc.appender;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.StringLayout;
+import org.apache.logging.log4j.core.appender.AppenderLoggingException;
+import org.apache.logging.log4j.core.appender.ManagerFactory;
+import org.apache.logging.log4j.core.appender.db.AbstractDatabaseManager;
+import org.apache.logging.log4j.core.appender.db.ColumnMapping;
+import org.apache.logging.log4j.core.appender.db.DbAppenderLoggingException;
+import org.apache.logging.log4j.core.util.Closer;
+import org.apache.logging.log4j.core.util.Log4jThread;
+import org.apache.logging.log4j.jdbc.convert.DateTypeConverter;
+import org.apache.logging.log4j.message.MapMessage;
+import org.apache.logging.log4j.spi.ThreadContextMap;
+import org.apache.logging.log4j.spi.ThreadContextStack;
+import org.apache.logging.log4j.util.IndexedReadOnlyStringMap;
+import org.apache.logging.log4j.util.ReadOnlyStringMap;
+import org.apache.logging.log4j.util.Strings;
+
import java.io.Serializable;
import java.io.StringReader;
import java.sql.Clob;
@@ -38,25 +56,6 @@ import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
-import org.apache.logging.log4j.core.Layout;
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.StringLayout;
-import org.apache.logging.log4j.core.appender.AppenderLoggingException;
-import org.apache.logging.log4j.core.appender.ManagerFactory;
-import org.apache.logging.log4j.core.appender.db.AbstractDatabaseManager;
-import org.apache.logging.log4j.core.appender.db.ColumnMapping;
-import org.apache.logging.log4j.core.appender.db.DbAppenderLoggingException;
-import org.apache.logging.log4j.core.util.Closer;
-import org.apache.logging.log4j.core.util.Log4jThread;
-import org.apache.logging.log4j.jdbc.convert.DateTypeConverter;
-import org.apache.logging.log4j.message.MapMessage;
-import org.apache.logging.log4j.plugins.convert.TypeConverters;
-import org.apache.logging.log4j.spi.ThreadContextMap;
-import org.apache.logging.log4j.spi.ThreadContextStack;
-import org.apache.logging.log4j.util.IndexedReadOnlyStringMap;
-import org.apache.logging.log4j.util.ReadOnlyStringMap;
-import org.apache.logging.log4j.util.Strings;
-
/**
* An {@link AbstractDatabaseManager} implementation for relational databases accessed via JDBC.
*/
@@ -759,8 +758,7 @@ public final class JdbcDatabaseManager extends AbstractDatabaseManager {
} else if (NClob.class.isAssignableFrom(mapping.getType())) {
this.statement.setNClob(j++, new StringReader(layout.toSerializable(event)));
} else {
- final Object value = TypeConverters.convert(layout.toSerializable(event), mapping.getType(),
- null);
+ final Object value = mapping.getTypeConverter().convert(layout.toSerializable(event), null);
setStatementObject(j++, mapping.getNameKey(), value);
}
}
diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactoryConverter.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactoryConverter.java
index 1de8039..546928f 100644
--- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactoryConverter.java
+++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactoryConverter.java
@@ -18,12 +18,11 @@ package org.apache.logging.log4j.layout.template.json.util;
import org.apache.logging.log4j.plugins.Plugin;
import org.apache.logging.log4j.plugins.convert.TypeConverter;
-import org.apache.logging.log4j.plugins.convert.TypeConverters;
/**
* The default string (i.e., recycler factory spec) to {@link RecyclerFactory} type converter.
*/
-@Plugin(name = "RecyclerFactoryConverter", category = TypeConverters.CATEGORY)
+@Plugin(name = "RecyclerFactoryConverter", category = TypeConverter.CATEGORY)
public final class RecyclerFactoryConverter implements TypeConverter<RecyclerFactory> {
@Override
diff --git a/log4j-layout-template-json/src/test/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactoriesTest.java b/log4j-layout-template-json/src/test/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactoriesTest.java
index 23bfe05..1a9d235 100644
--- a/log4j-layout-template-json/src/test/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactoriesTest.java
+++ b/log4j-layout-template-json/src/test/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactoriesTest.java
@@ -16,12 +16,13 @@
*/
package org.apache.logging.log4j.layout.template.json.util;
-import org.apache.logging.log4j.plugins.convert.TypeConverter;
-import org.apache.logging.log4j.plugins.convert.TypeConverterRegistry;
+import org.apache.logging.log4j.core.test.appender.ListAppender;
import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
import org.apache.logging.log4j.core.test.junit.Named;
import org.apache.logging.log4j.layout.template.json.JsonTemplateLayout;
-import org.apache.logging.log4j.core.test.appender.ListAppender;
+import org.apache.logging.log4j.plugins.convert.TypeConverter;
+import org.apache.logging.log4j.plugins.di.DI;
+import org.apache.logging.log4j.plugins.di.Injector;
import org.assertj.core.api.Assertions;
import org.jctools.queues.MpmcArrayQueue;
import org.junit.jupiter.api.Test;
@@ -35,10 +36,10 @@ class RecyclerFactoriesTest {
@Test
void test_RecyclerFactoryConverter() throws Exception {
+ final Injector injector = DI.createInjector();
+ injector.init();
// Check if the type converter is registered.
- final TypeConverter<?> converter = TypeConverterRegistry
- .getInstance()
- .findCompatibleConverter(RecyclerFactory.class);
+ final TypeConverter<?> converter = injector.getTypeConverter(RecyclerFactory.class);
Assertions.assertThat(converter).isNotNull();
// Check dummy recycler factory.
diff --git a/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDb3Provider.java b/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDb3Provider.java
index 52e05b1..2a5f364 100644
--- a/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDb3Provider.java
+++ b/log4j-mongodb3/src/main/java/org/apache/logging/log4j/mongodb3/MongoDb3Provider.java
@@ -16,17 +16,23 @@
*/
package org.apache.logging.log4j.mongodb3;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-
+import com.mongodb.MongoClient;
+import com.mongodb.MongoClientOptions;
+import com.mongodb.MongoCredential;
+import com.mongodb.ServerAddress;
+import com.mongodb.WriteConcern;
+import com.mongodb.client.MongoDatabase;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.Core;
import org.apache.logging.log4j.core.appender.nosql.NoSqlProvider;
import org.apache.logging.log4j.core.filter.AbstractFilterable;
+import org.apache.logging.log4j.plugins.Inject;
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.convert.TypeConverters;
+import org.apache.logging.log4j.plugins.convert.TypeConverter;
+import org.apache.logging.log4j.plugins.di.Injector;
+import org.apache.logging.log4j.plugins.util.TypeUtil;
import org.apache.logging.log4j.plugins.validation.constraints.Required;
import org.apache.logging.log4j.plugins.validation.constraints.ValidHost;
import org.apache.logging.log4j.plugins.validation.constraints.ValidPort;
@@ -36,12 +42,8 @@ import org.apache.logging.log4j.util.Strings;
import org.bson.codecs.configuration.CodecRegistries;
import org.bson.codecs.configuration.CodecRegistry;
-import com.mongodb.MongoClient;
-import com.mongodb.MongoClientOptions;
-import com.mongodb.MongoCredential;
-import com.mongodb.ServerAddress;
-import com.mongodb.WriteConcern;
-import com.mongodb.client.MongoDatabase;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
/**
* The MongoDB implementation of {@link NoSqlProvider} using the MongoDB driver version 3 API.
@@ -125,6 +127,8 @@ public final class MongoDb3Provider implements NoSqlProvider<MongoDb3Connection>
@PluginBuilderAttribute
private String writeConcernConstantClassName;
+ private Injector injector;
+
@SuppressWarnings("resource")
@Override
public MongoDb3Provider build() {
@@ -180,7 +184,8 @@ public final class MongoDb3Provider implements NoSqlProvider<MongoDb3Connection>
mongoCredential = MongoCredential.createCredential(userName, databaseName, password.toCharArray());
}
try {
- final int portInt = TypeConverters.convert(port, int.class, DEFAULT_PORT);
+ final TypeConverter<Integer> converter = TypeUtil.cast(injector.getTypeConverter(Integer.class));
+ final int portInt = converter.convert(port, DEFAULT_PORT);
description += ", server=" + server + ", port=" + portInt;
final WriteConcern writeConcern = toWriteConcern(writeConcernConstant, writeConcernConstantClassName);
// @formatter:off
@@ -286,6 +291,12 @@ public final class MongoDb3Provider implements NoSqlProvider<MongoDb3Connection>
this.writeConcernConstantClassName = writeConcernConstantClassName;
return asBuilder();
}
+
+ @Inject
+ public B setInjector(final Injector injector) {
+ this.injector = injector;
+ return asBuilder();
+ }
}
private static final int DEFAULT_COLLECTION_SIZE = 536870912;
diff --git a/log4j-plugins-test/src/test/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistryTest.java b/log4j-plugins-test/src/test/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistryTest.java
index bf4303b..3b68ffa 100644
--- a/log4j-plugins-test/src/test/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistryTest.java
+++ b/log4j-plugins-test/src/test/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistryTest.java
@@ -18,6 +18,8 @@
package org.apache.logging.log4j.plugins.convert;
import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.di.DI;
+import org.apache.logging.log4j.plugins.di.Injector;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
@@ -31,7 +33,7 @@ class TypeConverterRegistryTest {
}
- @Plugin(name = "CustomTestClass1Converter1", category = TypeConverters.CATEGORY)
+ @Plugin(name = "CustomTestClass1Converter1", category = TypeConverter.CATEGORY)
public static final class CustomTestClass1Converter1
implements TypeConverter<CustomTestClass1> {
@@ -43,7 +45,7 @@ class TypeConverterRegistryTest {
}
@SuppressWarnings("ComparableType")
- @Plugin(name = "CustomTestClass1Converter2", category = TypeConverters.CATEGORY)
+ @Plugin(name = "CustomTestClass1Converter2", category = TypeConverter.CATEGORY)
public static final class CustomTestClass1Converter2
implements TypeConverter<CustomTestClass1>, Comparable<TypeConverter<?>> {
@@ -61,9 +63,9 @@ class TypeConverterRegistryTest {
@Test
public void testMultipleComparableConverters() {
- final TypeConverter<?> converter = TypeConverterRegistry
- .getInstance()
- .findCompatibleConverter(CustomTestClass1.class);
+ final Injector injector = DI.createInjector();
+ injector.init();
+ final TypeConverter<?> converter = injector.getTypeConverter(CustomTestClass1.class);
assertThat(converter, instanceOf(CustomTestClass1Converter2.class));
}
@@ -73,7 +75,7 @@ class TypeConverterRegistryTest {
}
- @Plugin(name = "CustomTestClass2Converter1", category = TypeConverters.CATEGORY)
+ @Plugin(name = "CustomTestClass2Converter1", category = TypeConverter.CATEGORY)
public static final class CustomTestClass2Converter1
implements TypeConverter<CustomTestClass2> {
@@ -84,7 +86,7 @@ class TypeConverterRegistryTest {
}
- @Plugin(name = "CustomTestClass2Converter2", category = TypeConverters.CATEGORY)
+ @Plugin(name = "CustomTestClass2Converter2", category = TypeConverter.CATEGORY)
public static final class CustomTestClass2Converter2
implements TypeConverter<CustomTestClass2> {
@@ -97,9 +99,9 @@ class TypeConverterRegistryTest {
@Test
public void testMultipleIncomparableConverters() {
- final TypeConverter<?> converter = TypeConverterRegistry
- .getInstance()
- .findCompatibleConverter(CustomTestClass2.class);
+ final Injector injector = DI.createInjector();
+ injector.init();
+ final TypeConverter<?> converter = injector.getTypeConverter(CustomTestClass2.class);
assertThat(converter, instanceOf(CustomTestClass2Converter1.class));
}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverter.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverter.java
index 45e8a16..403ab57 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverter.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverter.java
@@ -17,16 +17,25 @@
package org.apache.logging.log4j.plugins.convert;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.util.TypeUtil;
+import org.apache.logging.log4j.status.StatusLogger;
+
/**
* Interface for doing automatic String conversion to a specific type.
*
* @param <T> Converts Strings into the given type {@code T}.
- * @since 2.1 Moved to the {@code convert} package.
+ * @since 3.0.0 Moved to {@code log4j-plugins}.
*/
@FunctionalInterface
public interface TypeConverter<T> {
/**
+ * The {@link Plugin#category() Plugin Category} to use for {@link TypeConverter} plugins.
+ */
+ String CATEGORY = "TypeConverter";
+
+ /**
* Converts a String to a given type.
*
* @param s the String to convert. Cannot be {@code null}.
@@ -34,4 +43,31 @@ public interface TypeConverter<T> {
* @throws Exception thrown when a conversion error occurs
*/
T convert(String s) throws Exception;
+
+ default T convert(final String string, final Object defaultValue) {
+ return convert(string, defaultValue, false);
+ }
+
+ default T convert(final String string, final Object defaultValue, final boolean sensitive) {
+ if (string != null) {
+ try {
+ return convert(string);
+ } catch (final Exception e) {
+ StatusLogger.getLogger().warn("Unable to convert string [{}]. Using default value [{}].",
+ sensitive ? "-redacted-" : string, defaultValue, e);
+ }
+ }
+ if (defaultValue == null) {
+ return null;
+ }
+ if (!(defaultValue instanceof String)) {
+ return TypeUtil.cast(defaultValue);
+ }
+ try {
+ return convert((String) defaultValue);
+ } catch (final Exception e) {
+ StatusLogger.getLogger().debug("Unable to parse default value [{}].", defaultValue, e);
+ return null;
+ }
+ }
}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistry.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistry.java
deleted file mode 100644
index 412265c..0000000
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistry.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * 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.plugins.convert;
-
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.plugins.util.PluginType;
-import org.apache.logging.log4j.plugins.util.PluginUtil;
-import org.apache.logging.log4j.plugins.util.TypeUtil;
-import org.apache.logging.log4j.status.StatusLogger;
-import org.apache.logging.log4j.util.LazyValue;
-import org.apache.logging.log4j.util.ReflectionUtil;
-
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.util.Collection;
-import java.util.Map;
-import java.util.Objects;
-import java.util.UnknownFormatConversionException;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.function.Supplier;
-
-/**
- * Registry for {@link TypeConverter} plugins.
- *
- * @since 2.1
- */
-public class TypeConverterRegistry {
-
- private static final Logger LOGGER = StatusLogger.getLogger();
- private static final Supplier<TypeConverterRegistry> INSTANCE = new LazyValue<>(TypeConverterRegistry::new);
-
- private final ConcurrentMap<Type, TypeConverter<?>> registry = new ConcurrentHashMap<>();
-
- /**
- * Gets the singleton instance of the TypeConverterRegistry.
- *
- * @return the singleton instance.
- */
- public static TypeConverterRegistry getInstance() {
- return INSTANCE.get();
- }
-
- /**
- * Finds a {@link TypeConverter} for the given {@link Type}, falling back to an assignment-compatible TypeConverter
- * if none exist for the given type. That is, if the given Type does not have a TypeConverter, but another Type
- * which can be assigned to the given Type <em>does</em> have a TypeConverter, then that TypeConverter will be
- * used and registered.
- *
- * @param type the Type to find a TypeConverter for (must not be {@code null}).
- * @return a TypeConverter for the given Type.
- * @throws UnknownFormatConversionException if no TypeConverter can be found for the given type.
- */
- public TypeConverter<?> findCompatibleConverter(final Type type) {
- Objects.requireNonNull(type, "No type was provided");
- final TypeConverter<?> primary = registry.get(type);
- // cached type converters
- if (primary != null) {
- return primary;
- }
- // dynamic enum support
- if (type instanceof Class<?>) {
- final Class<?> clazz = (Class<?>) type;
- if (clazz.isEnum()) {
- @SuppressWarnings({"unchecked","rawtypes"})
- final EnumConverter<? extends Enum> converter = new EnumConverter(clazz.asSubclass(Enum.class));
- synchronized (INSTANCE) {
- return registerConverter(type, converter);
- }
- }
- }
- // look for compatible converters
- for (final Map.Entry<Type, TypeConverter<?>> entry : registry.entrySet()) {
- final Type key = entry.getKey();
- if (TypeUtil.isAssignable(type, key)) {
- LOGGER.debug("Found compatible TypeConverter<{}> for type [{}].", key, type);
- final TypeConverter<?> value = entry.getValue();
- synchronized (INSTANCE) {
- return registerConverter(type, value);
- }
- }
- }
- throw new UnknownFormatConversionException(type.toString());
- }
-
- private TypeConverterRegistry() {
- LOGGER.trace("TypeConverterRegistry initializing.");
- loadKnownTypeConverters(PluginUtil.collectPluginsByCategory(TypeConverters.CATEGORY).values());
- registerPrimitiveTypes();
- }
-
- private void loadKnownTypeConverters(final Collection<PluginType<?>> knownTypes) {
- for (final PluginType<?> knownType : knownTypes) {
- final Class<?> clazz = knownType.getPluginClass();
- if (TypeConverter.class.isAssignableFrom(clazz)) {
- @SuppressWarnings("rawtypes") final Class<? extends TypeConverter> pluginClass =
- clazz.asSubclass(TypeConverter.class);
- final Type conversionType = getTypeConverterSupportedType(pluginClass);
- final TypeConverter<?> converter = ReflectionUtil.instantiate(pluginClass);
- registerConverter(conversionType, converter);
- }
- }
- }
-
- /**
- * Attempts to register the given converter and returns the effective
- * converter associated with the given type.
- * <p>
- * Registration will fail if there already exists a converter for the given
- * type and neither the existing, nor the provided converter extends from {@link Comparable}.
- */
- private TypeConverter<?> registerConverter(
- final Type conversionType,
- final TypeConverter<?> converter) {
- final TypeConverter<?> conflictingConverter = registry.get(conversionType);
- if (conflictingConverter != null) {
- final boolean overridable;
- if (converter instanceof Comparable) {
- @SuppressWarnings("unchecked")
- final Comparable<TypeConverter<?>> comparableConverter =
- (Comparable<TypeConverter<?>>) converter;
- overridable = comparableConverter.compareTo(conflictingConverter) < 0;
- } else if (conflictingConverter instanceof Comparable) {
- @SuppressWarnings("unchecked")
- final Comparable<TypeConverter<?>> comparableConflictingConverter =
- (Comparable<TypeConverter<?>>) conflictingConverter;
- overridable = comparableConflictingConverter.compareTo(converter) > 0;
- } else {
- overridable = false;
- }
- if (overridable) {
- LOGGER.debug(
- "Replacing TypeConverter [{}] for type [{}] with [{}] after comparison.",
- conflictingConverter, conversionType, converter);
- registry.put(conversionType, converter);
- return converter;
- } else {
- LOGGER.warn(
- "Ignoring TypeConverter [{}] for type [{}] that conflicts with [{}], since they are not comparable.",
- converter, conversionType, conflictingConverter);
- return conflictingConverter;
- }
- } else {
- registry.put(conversionType, converter);
- return converter;
- }
- }
-
- private static Type getTypeConverterSupportedType(@SuppressWarnings("rawtypes") final Class<? extends TypeConverter> typeConverterClass) {
- for (final Type type : typeConverterClass.getGenericInterfaces()) {
- if (type instanceof ParameterizedType) {
- final ParameterizedType pType = (ParameterizedType) type;
- if (TypeConverter.class.equals(pType.getRawType())) {
- // TypeConverter<T> has only one type argument (T), so return that
- return pType.getActualTypeArguments()[0];
- }
- }
- }
- return Void.TYPE;
- }
-
- private void registerPrimitiveTypes() {
- registerConverter(Boolean.class, Boolean::valueOf);
- registerTypeAlias(Boolean.class, Boolean.TYPE);
- registerConverter(Byte.class, Byte::valueOf);
- registerTypeAlias(Byte.class, Byte.TYPE);
- registerConverter(Character.class, s -> {
- if (s.length() != 1) {
- throw new IllegalArgumentException("Character string must be of length 1: " + s);
- }
- return s.toCharArray()[0];
- });
- registerTypeAlias(Character.class, Character.TYPE);
- registerConverter(Double.class, Double::valueOf);
- registerTypeAlias(Double.class, Double.TYPE);
- registerConverter(Float.class, Float::valueOf);
- registerTypeAlias(Float.class, Float.TYPE);
- registerConverter(Integer.class, Integer::valueOf);
- registerTypeAlias(Integer.class, Integer.TYPE);
- registerConverter(Long.class, Long::valueOf);
- registerTypeAlias(Long.class, Long.TYPE);
- registerConverter(Short.class, Short::valueOf);
- registerTypeAlias(Short.class, Short.TYPE);
- registerConverter(String.class, s -> s);
- }
-
- private void registerTypeAlias(final Type knownType, final Type aliasType) {
- TypeConverter<?> converter = registry.get(knownType);
- if (converter != null) {
- registry.putIfAbsent(aliasType, converter);
- } else {
- LOGGER.error("Cannot locate converter for {}", knownType);
- }
- }
-
-}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverters.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverters.java
deleted file mode 100644
index 0ce0717..0000000
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverters.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * 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.plugins.convert;
-
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.util.TypeUtil;
-import org.apache.logging.log4j.status.StatusLogger;
-
-import java.lang.reflect.Type;
-
-/**
- * Collection of basic TypeConverter implementations. May be used to register additional TypeConverters or find
- * registered TypeConverters.
- *
- * @since 2.1 Moved to the {@code convert} package.
- */
-public final class TypeConverters {
-
- /**
- * The {@link Plugin#category() Plugin Category} to use for {@link TypeConverter} plugins.
- *
- * @since 2.1
- */
- public static final String CATEGORY = "TypeConverter";
-
- /**
- * Converts a String to a given class if a TypeConverter is available for that class. Falls back to the provided
- * default value if the conversion is unsuccessful. However, if the default value is <em>also</em> invalid, then
- * {@code null} is returned (along with a nasty status log message).
- *
- * @param s
- * the string to convert
- * @param clazz
- * the class to try to convert the string to
- * @param defaultValue
- * the fallback object to use if the conversion is unsuccessful
- * @param <T> The type of the clazz parameter.
- * @return the converted object which may be {@code null} if the string is invalid for the given type
- * @throws NullPointerException
- * if {@code clazz} is {@code null}
- * @throws IllegalArgumentException
- * if no TypeConverter exists for the given class
- */
- public static <T> T convert(final String s, final Class<? extends T> clazz, final Object defaultValue) {
- return convert(s, clazz, defaultValue, false);
- }
-
- public static <T> T convert(final String s, final Type targetType, final Object defaultValue, final boolean sensitive) {
- final TypeConverter<T> converter =
- TypeUtil.cast(TypeConverterRegistry.getInstance().findCompatibleConverter(targetType));
- if (s == null) {
- return parseDefaultValue(converter, defaultValue);
- }
- try {
- return converter.convert(s);
- } catch (final Exception e) {
- LOGGER.warn("Error while converting string [{}] to type [{}]. Using default value [{}].",
- sensitive ? "-redacted-" : s, targetType, defaultValue, e);
- return parseDefaultValue(converter, defaultValue);
- }
- }
-
- private static <T> T parseDefaultValue(final TypeConverter<T> converter, final Object defaultValue) {
- if (defaultValue == null) {
- return null;
- }
- if (!(defaultValue instanceof String)) {
- return TypeUtil.cast(defaultValue);
- }
- try {
- return converter.convert((String) defaultValue);
- } catch (final Exception e) {
- LOGGER.debug("Can't parse default value [{}] for type [{}].", defaultValue, converter.getClass(), e);
- return null;
- }
- }
-
- private static final Logger LOGGER = StatusLogger.getLogger();
-
-}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/DefaultInjector.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/DefaultInjector.java
index 1937234..6d62cce 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/DefaultInjector.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/DefaultInjector.java
@@ -25,6 +25,7 @@ import org.apache.logging.log4j.plugins.Node;
import org.apache.logging.log4j.plugins.QualifierType;
import org.apache.logging.log4j.plugins.ScopeType;
import org.apache.logging.log4j.plugins.Singleton;
+import org.apache.logging.log4j.plugins.convert.TypeConverter;
import org.apache.logging.log4j.plugins.name.AnnotatedElementAliasesProvider;
import org.apache.logging.log4j.plugins.name.AnnotatedElementNameProvider;
import org.apache.logging.log4j.plugins.util.AnnotationUtil;
@@ -36,6 +37,7 @@ import org.apache.logging.log4j.plugins.validation.ConstraintValidationException
import org.apache.logging.log4j.plugins.validation.ConstraintValidator;
import org.apache.logging.log4j.plugins.visit.NodeVisitor;
import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.EnglishEnums;
import org.apache.logging.log4j.util.LazyValue;
import org.apache.logging.log4j.util.ServiceRegistry;
import org.apache.logging.log4j.util.StringBuilders;
@@ -63,6 +65,7 @@ import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.Set;
+import java.util.UnknownFormatConversionException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@@ -73,6 +76,7 @@ class DefaultInjector implements Injector {
private final BindingMap bindingMap;
private final Map<Class<? extends Annotation>, Scope> scopes = new ConcurrentHashMap<>();
+ private final Map<Type, TypeConverter<?>> typeConverters = new ConcurrentHashMap<>();
private ReflectionAccessor accessor = object -> object.setAccessible(true);
DefaultInjector() {
@@ -84,6 +88,7 @@ class DefaultInjector implements Injector {
DefaultInjector(final DefaultInjector original) {
bindingMap = new BindingMap(original.bindingMap);
scopes.putAll(original.scopes);
+ typeConverters.putAll(original.typeConverters);
accessor = original.accessor;
}
@@ -112,6 +117,40 @@ class DefaultInjector implements Injector {
}
@Override
+ public TypeConverter<?> getTypeConverter(final Type type) {
+ if (typeConverters.isEmpty()) {
+ synchronized (typeConverters) {
+ if (typeConverters.isEmpty()) {
+ LOGGER.trace("Initializing type converters");
+ initializeTypeConverters();
+ }
+ }
+ }
+ final TypeConverter<?> primary = typeConverters.get(type);
+ // cached type converters
+ if (primary != null) {
+ return primary;
+ }
+ // dynamic enum support
+ if (type instanceof Class<?>) {
+ final Class<?> clazz = (Class<?>) type;
+ if (clazz.isEnum()) {
+ return registerTypeConverter(type, s -> EnglishEnums.valueOf(clazz.asSubclass(Enum.class), s));
+ }
+ }
+ // look for compatible converters
+ for (final Map.Entry<Type, TypeConverter<?>> entry : typeConverters.entrySet()) {
+ final Type key = entry.getKey();
+ if (TypeUtil.isAssignable(type, key)) {
+ LOGGER.debug("Found compatible TypeConverter<{}> for type [{}].", key, type);
+ final TypeConverter<?> value = entry.getValue();
+ return registerTypeConverter(type, value);
+ }
+ }
+ throw new UnknownFormatConversionException(type.toString());
+ }
+
+ @Override
public void injectMembers(final Object instance) {
injectMembers(Key.forClass(instance.getClass()), null, instance, Set.of(), null);
}
@@ -253,6 +292,83 @@ class DefaultInjector implements Injector {
}
}
+ private void initializeTypeConverters() {
+ final PluginManager manager = getInstance(new @Named(TypeConverter.CATEGORY) Key<>() {});
+ manager.collectPlugins();
+ for (final PluginType<?> knownType : manager.getPlugins().values()) {
+ final Class<?> pluginClass = knownType.getPluginClass();
+ final Type type = getTypeConverterSupportedType(pluginClass);
+ final TypeConverter<?> converter = getInstance(pluginClass.asSubclass(TypeConverter.class));
+ registerTypeConverter(type, converter);
+ }
+ registerTypeConverter(Boolean.class, Boolean::valueOf);
+ registerTypeAlias(Boolean.class, Boolean.TYPE);
+ registerTypeConverter(Byte.class, Byte::valueOf);
+ registerTypeAlias(Byte.class, Byte.TYPE);
+ registerTypeConverter(Character.class, s -> {
+ if (s.length() != 1) {
+ throw new IllegalArgumentException("Character string must be of length 1: " + s);
+ }
+ return s.toCharArray()[0];
+ });
+ registerTypeAlias(Character.class, Character.TYPE);
+ registerTypeConverter(Double.class, Double::valueOf);
+ registerTypeAlias(Double.class, Double.TYPE);
+ registerTypeConverter(Float.class, Float::valueOf);
+ registerTypeAlias(Float.class, Float.TYPE);
+ registerTypeConverter(Integer.class, Integer::valueOf);
+ registerTypeAlias(Integer.class, Integer.TYPE);
+ registerTypeConverter(Long.class, Long::valueOf);
+ registerTypeAlias(Long.class, Long.TYPE);
+ registerTypeConverter(Short.class, Short::valueOf);
+ registerTypeAlias(Short.class, Short.TYPE);
+ registerTypeConverter(String.class, s -> s);
+ }
+
+ private TypeConverter<?> registerTypeConverter(final Type type, final TypeConverter<?> converter) {
+ final TypeConverter<?> conflictingConverter = typeConverters.get(type);
+ if (conflictingConverter != null) {
+ final boolean overridable;
+ if (converter instanceof Comparable) {
+ @SuppressWarnings("unchecked")
+ final Comparable<TypeConverter<?>> comparableConverter =
+ (Comparable<TypeConverter<?>>) converter;
+ overridable = comparableConverter.compareTo(conflictingConverter) < 0;
+ } else if (conflictingConverter instanceof Comparable) {
+ @SuppressWarnings("unchecked")
+ final Comparable<TypeConverter<?>> comparableConflictingConverter =
+ (Comparable<TypeConverter<?>>) conflictingConverter;
+ overridable = comparableConflictingConverter.compareTo(converter) > 0;
+ } else {
+ overridable = false;
+ }
+ if (overridable) {
+ LOGGER.debug(
+ "Replacing TypeConverter [{}] for type [{}] with [{}] after comparison.",
+ conflictingConverter, type, converter);
+ typeConverters.put(type, converter);
+ return converter;
+ } else {
+ LOGGER.warn(
+ "Ignoring TypeConverter [{}] for type [{}] that conflicts with [{}], since they are not comparable.",
+ converter, type, conflictingConverter);
+ return conflictingConverter;
+ }
+ } else {
+ typeConverters.put(type, converter);
+ return converter;
+ }
+ }
+
+ private void registerTypeAlias(final Type knownType, final Type aliasType) {
+ final TypeConverter<?> converter = typeConverters.get(knownType);
+ if (converter != null) {
+ typeConverters.put(aliasType, converter);
+ } else {
+ LOGGER.error("Cannot locate type converter for {}", knownType);
+ }
+ }
+
private void injectMembers(
final Key<?> key, final Node node, final Object instance, final Set<Key<?>> chain, final StringBuilder debugLog) {
injectFields(key.getRawType(), node, instance, debugLog);
@@ -495,6 +611,18 @@ class DefaultInjector implements Injector {
((ConstraintValidator) validator).initialize(annotation);
}
+ private static Type getTypeConverterSupportedType(final Class<?> clazz) {
+ for (final Type type : clazz.getGenericInterfaces()) {
+ if (type instanceof ParameterizedType) {
+ final ParameterizedType parameterizedType = (ParameterizedType) type;
+ if (parameterizedType.getRawType() == TypeConverter.class) {
+ return parameterizedType.getActualTypeArguments()[0];
+ }
+ }
+ }
+ return Void.TYPE;
+ }
+
private static void verifyAttributesConsumed(final Node node) {
final Map<String, String> attrs = node.getAttributes();
if (!attrs.isEmpty()) {
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Injector.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Injector.java
index b51d845..24a0ee9 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Injector.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/di/Injector.java
@@ -19,8 +19,10 @@ package org.apache.logging.log4j.plugins.di;
import org.apache.logging.log4j.plugins.FactoryType;
import org.apache.logging.log4j.plugins.Node;
+import org.apache.logging.log4j.plugins.convert.TypeConverter;
import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
import java.util.function.Supplier;
/**
@@ -87,6 +89,15 @@ public interface Injector {
}
/**
+ * Gets a TypeConverter for the provided type.
+ *
+ * @param type type to get a converter for
+ * @return a TypeConverter for the provided type
+ * @throws java.util.UnknownFormatConversionException if no converter can be found for the provided type
+ */
+ TypeConverter<?> getTypeConverter(final Type type);
+
+ /**
* Injects dependencies into the members of the provided instance. Injectable fields are set, then injectable methods are
* invoked (first those with parameters, then those without parameters).
*
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidPortValidator.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidPortValidator.java
index 27e97f0..a65fecc 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidPortValidator.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidPortValidator.java
@@ -17,9 +17,12 @@
package org.apache.logging.log4j.plugins.validation.validators;
import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.plugins.Inject;
+import org.apache.logging.log4j.plugins.convert.TypeConverter;
+import org.apache.logging.log4j.plugins.di.Injector;
+import org.apache.logging.log4j.plugins.util.TypeUtil;
import org.apache.logging.log4j.plugins.validation.ConstraintValidator;
import org.apache.logging.log4j.plugins.validation.constraints.ValidPort;
-import org.apache.logging.log4j.plugins.convert.TypeConverters;
import org.apache.logging.log4j.status.StatusLogger;
/**
@@ -31,8 +34,14 @@ public class ValidPortValidator implements ConstraintValidator<ValidPort> {
private static final Logger LOGGER = StatusLogger.getLogger();
+ private final TypeConverter<Integer> converter;
private ValidPort annotation;
+ @Inject
+ public ValidPortValidator(final Injector injector) {
+ converter = TypeUtil.cast(injector.getTypeConverter(Integer.class));
+ }
+
@Override
public void initialize(final ValidPort annotation) {
this.annotation = annotation;
@@ -41,9 +50,9 @@ public class ValidPortValidator implements ConstraintValidator<ValidPort> {
@Override
public boolean isValid(final String name, final Object value) {
if (value instanceof CharSequence) {
- return isValid(name, TypeConverters.convert(value.toString(), Integer.class, -1));
+ return isValid(name, converter.convert(value.toString(), -1));
}
- if (!Integer.class.isInstance(value)) {
+ if (!(value instanceof Integer)) {
LOGGER.error(annotation.message());
return false;
}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visit/PluginAttributeVisitor.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visit/PluginAttributeVisitor.java
index 58cae4f..600f684 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visit/PluginAttributeVisitor.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visit/PluginAttributeVisitor.java
@@ -21,7 +21,8 @@ import org.apache.logging.log4j.plugins.Inject;
import org.apache.logging.log4j.plugins.Named;
import org.apache.logging.log4j.plugins.Node;
import org.apache.logging.log4j.plugins.PluginAttribute;
-import org.apache.logging.log4j.plugins.convert.TypeConverters;
+import org.apache.logging.log4j.plugins.convert.TypeConverter;
+import org.apache.logging.log4j.plugins.di.Injector;
import org.apache.logging.log4j.plugins.di.Keys;
import org.apache.logging.log4j.plugins.name.AnnotatedElementAliasesProvider;
import org.apache.logging.log4j.plugins.name.AnnotatedElementNameProvider;
@@ -59,10 +60,14 @@ public class PluginAttributeVisitor implements NodeVisitor {
);
private final Function<String, String> stringSubstitutionStrategy;
+ private final Injector injector;
@Inject
- public PluginAttributeVisitor(@Named(Keys.SUBSTITUTOR_NAME) final Function<String, String> stringSubstitutionStrategy) {
+ public PluginAttributeVisitor(
+ @Named(Keys.SUBSTITUTOR_NAME) final Function<String, String> stringSubstitutionStrategy,
+ final Injector injector) {
this.stringSubstitutionStrategy = stringSubstitutionStrategy;
+ this.injector = injector;
}
@Override
@@ -72,8 +77,9 @@ public class PluginAttributeVisitor implements NodeVisitor {
final PluginAttribute annotation = field.getAnnotation(PluginAttribute.class);
final boolean sensitive = annotation.sensitive();
final Type targetType = field.getGenericType();
+ final TypeConverter<?> converter = injector.getTypeConverter(targetType);
final Object value = node.removeMatchingAttribute(name, aliases)
- .map(stringSubstitutionStrategy.andThen(s -> TypeConverters.convert(s, targetType, null, sensitive)))
+ .map(stringSubstitutionStrategy.andThen(s -> (Object) converter.convert(s, null, sensitive)))
.orElseGet(() -> getDefaultValue(targetType, annotation));
StringBuilders.appendKeyDqValueWithJoiner(debugLog, name, sensitive ? "(***)" : value, ", ");
return value;
@@ -84,10 +90,11 @@ public class PluginAttributeVisitor implements NodeVisitor {
final String name = AnnotatedElementNameProvider.getName(parameter);
final Collection<String> aliases = AnnotatedElementAliasesProvider.getAliases(parameter);
final Type targetType = parameter.getParameterizedType();
+ final TypeConverter<?> converter = injector.getTypeConverter(targetType);
final PluginAttribute annotation = parameter.getAnnotation(PluginAttribute.class);
final boolean sensitive = annotation.sensitive();
final Object value = node.removeMatchingAttribute(name, aliases)
- .map(stringSubstitutionStrategy.andThen(s -> TypeConverters.convert(s, targetType, null, sensitive)))
+ .map(stringSubstitutionStrategy.andThen(s -> (Object) converter.convert(s, null, sensitive)))
.orElseGet(() -> getDefaultValue(targetType, annotation));
StringBuilders.appendKeyDqValueWithJoiner(debugLog, name, sensitive ? "(***)" : value, ", ");
return value;
@@ -98,7 +105,8 @@ public class PluginAttributeVisitor implements NodeVisitor {
if (extractor != null) {
return extractor.apply(annotation);
}
+ final TypeConverter<?> converter = injector.getTypeConverter(targetType);
final var value = stringSubstitutionStrategy.apply(annotation.defaultString());
- return Strings.isEmpty(value) ? null : TypeConverters.convert(value, targetType, null, false);
+ return Strings.isEmpty(value) ? null : converter.convert(value, null);
}
}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visit/PluginBuilderAttributeVisitor.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visit/PluginBuilderAttributeVisitor.java
index 9a381f2..19f0c3e 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visit/PluginBuilderAttributeVisitor.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visit/PluginBuilderAttributeVisitor.java
@@ -21,7 +21,8 @@ import org.apache.logging.log4j.plugins.Inject;
import org.apache.logging.log4j.plugins.Named;
import org.apache.logging.log4j.plugins.Node;
import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.plugins.convert.TypeConverters;
+import org.apache.logging.log4j.plugins.convert.TypeConverter;
+import org.apache.logging.log4j.plugins.di.Injector;
import org.apache.logging.log4j.plugins.di.Keys;
import org.apache.logging.log4j.plugins.name.AnnotatedElementAliasesProvider;
import org.apache.logging.log4j.plugins.name.AnnotatedElementNameProvider;
@@ -36,10 +37,14 @@ import java.util.function.Function;
public class PluginBuilderAttributeVisitor implements NodeVisitor {
private final Function<String, String> stringSubstitutionStrategy;
+ private final Injector injector;
@Inject
- public PluginBuilderAttributeVisitor(@Named(Keys.SUBSTITUTOR_NAME) final Function<String, String> stringSubstitutionStrategy) {
+ public PluginBuilderAttributeVisitor(
+ @Named(Keys.SUBSTITUTOR_NAME) final Function<String, String> stringSubstitutionStrategy,
+ final Injector injector) {
this.stringSubstitutionStrategy = stringSubstitutionStrategy;
+ this.injector = injector;
}
protected boolean isSensitive(final AnnotatedElement element) {
@@ -51,9 +56,10 @@ public class PluginBuilderAttributeVisitor implements NodeVisitor {
final String name = AnnotatedElementNameProvider.getName(field);
final Collection<String> aliases = AnnotatedElementAliasesProvider.getAliases(field);
final Type targetType = field.getGenericType();
+ final TypeConverter<?> converter = injector.getTypeConverter(targetType);
final boolean sensitive = isSensitive(field);
final Object value = node.removeMatchingAttribute(name, aliases)
- .map(stringSubstitutionStrategy.andThen(s -> TypeConverters.convert(s, targetType, null, sensitive)))
+ .map(stringSubstitutionStrategy.andThen(s -> converter.convert(s, null, sensitive)))
.orElse(null);
StringBuilders.appendKeyDqValueWithJoiner(debugLog, name, sensitive ? "(***)" : value, ", ");
return value;
@@ -64,9 +70,10 @@ public class PluginBuilderAttributeVisitor implements NodeVisitor {
final String name = AnnotatedElementNameProvider.getName(parameter);
final Collection<String> aliases = AnnotatedElementAliasesProvider.getAliases(parameter);
final Type targetType = parameter.getParameterizedType();
+ final TypeConverter<?> converter = injector.getTypeConverter(targetType);
final boolean sensitive = isSensitive(parameter);
final Object value = node.removeMatchingAttribute(name, aliases)
- .map(stringSubstitutionStrategy.andThen(s -> TypeConverters.convert(s, targetType, null, sensitive)))
+ .map(stringSubstitutionStrategy.andThen(s -> converter.convert(s, null, sensitive)))
.orElse(null);
StringBuilders.appendKeyDqValueWithJoiner(debugLog, name, sensitive ? "(***)" : value, ", ");
return value;
diff --git a/src/site/asciidoc/manual/json-template-layout.adoc.vm b/src/site/asciidoc/manual/json-template-layout.adoc.vm
index 8e86a8c..9e1b10e 100644
--- a/src/site/asciidoc/manual/json-template-layout.adoc.vm
+++ b/src/site/asciidoc/manual/json-template-layout.adoc.vm
@@ -1788,9 +1788,8 @@ package com.acme.logging.log4j.layout.template.json;
import org.apache.logging.log4j.plugins.Plugin;
import org.apache.logging.log4j.plugins.convert.TypeConverter;
-import org.apache.logging.log4j.plugins.convert.TypeConverters;
-@Plugin(name = "AcmeRecyclerFactoryConverter", category = TypeConverters.CATEGORY)
+@Plugin(name = "AcmeRecyclerFactoryConverter", category = TypeConverter.CATEGORY)
public final class AcmeRecyclerFactoryConverter
implements TypeConverter<RecyclerFactory>, Comparable<TypeConverter<?>> {