diff --git a/archaius2-core/src/main/java/com/netflix/archaius/DefaultDecoder.java b/archaius2-core/src/main/java/com/netflix/archaius/DefaultDecoder.java index 48abb741..f4bbb4b0 100644 --- a/archaius2-core/src/main/java/com/netflix/archaius/DefaultDecoder.java +++ b/archaius2-core/src/main/java/com/netflix/archaius/DefaultDecoder.java @@ -36,11 +36,11 @@ @Singleton public class DefaultDecoder implements Decoder, TypeConverter.Registry { - private final Map cache = new ConcurrentHashMap<>(); + private final Map> cache = new ConcurrentHashMap<>(); private final List factories = new ArrayList<>(); - public static DefaultDecoder INSTANCE = new DefaultDecoder(); + public static final DefaultDecoder INSTANCE = new DefaultDecoder(); private DefaultDecoder() { factories.add(DefaultTypeConverterFactory.INSTANCE); @@ -60,7 +60,7 @@ public T decode(Type type, String encoded) { if (encoded == null) { return null; } - return (T)getOrCreateConverter(type).convert(encoded); + return (T) getOrCreateConverter(type).convert(encoded); } catch (Exception e) { throw new ParseException("Error decoding type `" + type.getTypeName() + "`", e); } @@ -78,7 +78,10 @@ private TypeConverter getOrCreateConverter(Type type) { if (converter == null) { throw new RuntimeException("No converter found for type '" + type + "'"); } - cache.put(type, converter); + TypeConverter existing = cache.putIfAbsent(type, converter); + if (existing != null) { + converter = existing; + } } return converter; } @@ -106,7 +109,8 @@ private static TypeConverter findValueOfTypeConverter(Type type) { return null; } - Class cls = (Class)type; + @SuppressWarnings("unchecked") + Class cls = (Class) type; // Next look a valueOf(String) static method Method method; @@ -114,19 +118,19 @@ private static TypeConverter findValueOfTypeConverter(Type type) { method = cls.getMethod("valueOf", String.class); return value -> { try { - return (T)method.invoke(null, value); + return (T) method.invoke(null, value); } catch (Exception e) { throw new ParseException("Error converting value '" + value + "' to '" + type.getTypeName() + "'", e); } }; } catch (NoSuchMethodException e1) { // Next look for a T(String) constructor - Constructor c; + Constructor c; try { c = cls.getConstructor(String.class); return value -> { try { - return (T)c.newInstance(value); + return (T) c.newInstance(value); } catch (Exception e) { throw new ParseException("Error converting value", e); } diff --git a/archaius2-core/src/main/java/com/netflix/archaius/converters/DefaultTypeConverterFactory.java b/archaius2-core/src/main/java/com/netflix/archaius/converters/DefaultTypeConverterFactory.java index e08d9d1f..17522beb 100644 --- a/archaius2-core/src/main/java/com/netflix/archaius/converters/DefaultTypeConverterFactory.java +++ b/archaius2-core/src/main/java/com/netflix/archaius/converters/DefaultTypeConverterFactory.java @@ -8,6 +8,7 @@ import java.lang.reflect.Type; import java.math.BigDecimal; import java.math.BigInteger; +import java.net.URI; import java.time.Duration; import java.time.Instant; import java.time.LocalDate; @@ -22,6 +23,7 @@ import java.util.Currency; import java.util.Date; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -76,6 +78,8 @@ private DefaultTypeConverterFactory() { converters.put(Instant.class, v -> Instant.from(OffsetDateTime.parse(v))); converters.put(Date.class, v -> new Date(Long.parseLong(v))); converters.put(Currency.class, Currency::getInstance); + converters.put(URI.class, URI::create); + converters.put(Locale.class, Locale::forLanguageTag); converters.put(BitSet.class, v -> { try { diff --git a/archaius2-core/src/test/java/com/netflix/archaius/DefaultDecoderTest.java b/archaius2-core/src/test/java/com/netflix/archaius/DefaultDecoderTest.java index 346e3952..7e4144a6 100644 --- a/archaius2-core/src/test/java/com/netflix/archaius/DefaultDecoderTest.java +++ b/archaius2-core/src/test/java/com/netflix/archaius/DefaultDecoderTest.java @@ -18,6 +18,7 @@ import java.math.BigDecimal; import java.math.BigInteger; +import java.net.URI; import java.time.Duration; import java.time.Instant; import java.time.LocalDate; @@ -30,6 +31,7 @@ import java.util.BitSet; import java.util.Currency; import java.util.Date; +import java.util.Locale; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; @@ -84,5 +86,7 @@ public void testJavaMiscellaneous() throws DecoderException { Assert.assertEquals(Currency.getInstance("USD"), decoder.decode(Currency.class, "USD")); Assert.assertEquals(BitSet.valueOf(Hex.decodeHex("DEADBEEF00DEADBEEF")), decoder.decode(BitSet.class, "DEADBEEF00DEADBEEF")); Assert.assertEquals("testString", decoder.decode(String.class, "testString")); + Assert.assertEquals(URI.create("https://netflix.com"), decoder.decode(URI.class, "https://netflix.com")); + Assert.assertEquals(Locale.ENGLISH, decoder.decode(Locale.class, "en")); } }