config proxy basic implementation
Project: http://git-wip-us.apache.org/repos/asf/deltaspike/repo Commit: http://git-wip-us.apache.org/repos/asf/deltaspike/commit/b81d4987 Tree: http://git-wip-us.apache.org/repos/asf/deltaspike/tree/b81d4987 Diff: http://git-wip-us.apache.org/repos/asf/deltaspike/diff/b81d4987 Branch: refs/heads/master Commit: b81d4987f218ee2fc37835787c80bd8db7f5c468 Parents: 3f8252e Author: rmannibucau <rmannibu...@apache.org> Authored: Mon Nov 7 12:33:36 2016 +0100 Committer: rmannibucau <rmannibu...@apache.org> Committed: Mon Nov 7 12:33:36 2016 +0100 ---------------------------------------------------------------------- .../core/api/config/Configuration.java | 50 ++++++ .../spi/config/BaseConfigPropertyProducer.java | 13 +- .../impl/config/ConfigurationExtension.java | 38 ++++- .../config/ProxyConfigurationLifecycle.java | 157 +++++++++++++++++++ .../core/api/config/injectable/ConfigBean.java | 83 ++++++++++ .../InjectableConfigPropertyTest.java | 67 +++++--- 6 files changed, 383 insertions(+), 25 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/deltaspike/blob/b81d4987/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/config/Configuration.java ---------------------------------------------------------------------- diff --git a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/config/Configuration.java b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/config/Configuration.java new file mode 100644 index 0000000..5c3e33d --- /dev/null +++ b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/config/Configuration.java @@ -0,0 +1,50 @@ +/* + * 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.deltaspike.core.api.config; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.util.concurrent.TimeUnit; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import static java.util.concurrent.TimeUnit.SECONDS; + +/** + * Marker to let DeltaSpike pick this interface and create a proxy getting values + * from the configuration. + * + * The underlying Bean should be normal-scoped. + */ +@Target(TYPE) +@Retention(RUNTIME) +@Documented +public @interface Configuration +{ + /** + * @return the duration while the value is not reloaded. + */ + long cacheFor() default -1; + + /** + * @return the duration unit for {@see cacheFor()}. + */ + TimeUnit cacheUnit() default SECONDS; +} http://git-wip-us.apache.org/repos/asf/deltaspike/blob/b81d4987/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/spi/config/BaseConfigPropertyProducer.java ---------------------------------------------------------------------- diff --git a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/spi/config/BaseConfigPropertyProducer.java b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/spi/config/BaseConfigPropertyProducer.java index 7cae68d..48517dc 100644 --- a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/spi/config/BaseConfigPropertyProducer.java +++ b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/spi/config/BaseConfigPropertyProducer.java @@ -165,6 +165,17 @@ public abstract class BaseConfigPropertyProducer final Class<? extends ConfigResolver.Converter> converterType, final String parameterizedBy, final boolean projectStageAware, final boolean evaluate) { + final ConfigResolver.TypedResolver<T> resolver = asResolver( + key, stringDefault, ipCls, converterType, parameterizedBy, projectStageAware, evaluate); + return resolver.getValue(); + } + + public <T> ConfigResolver.TypedResolver<T> asResolver(final String key, final String stringDefault, + final Type ipCls, + final Class<? extends ConfigResolver.Converter> converterType, + final String parameterizedBy, + final boolean projectStageAware, final boolean evaluate) + { final ConfigResolver.UntypedResolver<String> untypedResolver = ConfigResolver.resolve(key); final ConfigResolver.TypedResolver<T> resolver = (ConfigResolver.Converter.class == converterType ? @@ -179,6 +190,6 @@ public abstract class BaseConfigPropertyProducer { resolver.parameterizedBy(parameterizedBy); } - return resolver.evaluateVariables(evaluate).getValue(); + return resolver.evaluateVariables(evaluate); } } http://git-wip-us.apache.org/repos/asf/deltaspike/blob/b81d4987/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/config/ConfigurationExtension.java ---------------------------------------------------------------------- diff --git a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/config/ConfigurationExtension.java b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/config/ConfigurationExtension.java index 65e3f2a..e1c43d2 100644 --- a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/config/ConfigurationExtension.java +++ b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/config/ConfigurationExtension.java @@ -45,10 +45,13 @@ import java.util.concurrent.ConcurrentHashMap; import org.apache.deltaspike.core.api.config.ConfigProperty; import org.apache.deltaspike.core.api.config.ConfigResolver; +import org.apache.deltaspike.core.api.config.Configuration; import org.apache.deltaspike.core.api.config.Filter; import org.apache.deltaspike.core.api.config.PropertyFileConfig; import org.apache.deltaspike.core.api.config.Source; import org.apache.deltaspike.core.api.exclude.Exclude; +import org.apache.deltaspike.core.api.literal.AnyLiteral; +import org.apache.deltaspike.core.api.literal.DefaultLiteral; import org.apache.deltaspike.core.api.provider.BeanProvider; import org.apache.deltaspike.core.spi.activation.Deactivatable; import org.apache.deltaspike.core.spi.config.BaseConfigPropertyProducer; @@ -58,6 +61,7 @@ import org.apache.deltaspike.core.spi.config.ConfigValidator; import org.apache.deltaspike.core.util.ClassDeactivationUtils; import org.apache.deltaspike.core.util.ClassUtils; import org.apache.deltaspike.core.util.ServiceUtils; +import org.apache.deltaspike.core.util.bean.BeanBuilder; /** * This extension handles {@link org.apache.deltaspike.core.api.config.PropertyFileConfig}s @@ -91,6 +95,7 @@ public class ConfigurationExtension implements Extension, Deactivatable private final List<Bean<? extends ConfigSource>> cdiSources = new ArrayList<Bean<? extends ConfigSource>>(); private final List<Bean<? extends ConfigFilter>> cdiFilters = new ArrayList<Bean<? extends ConfigFilter>>(); + private final List<Class<?>> dynamicConfigurationBeanClasses = new ArrayList<Class<?>>(); @SuppressWarnings("UnusedDeclaration") protected void init(@Observes BeforeBeanDiscovery beforeBeanDiscovery) @@ -127,9 +132,24 @@ public class ConfigurationExtension implements Extension, Deactivatable propertyFileConfigClasses.add(pcsClass); } + public void findDynamicConfigurationBeans(@Observes ProcessAnnotatedType<?> pat) + { + if (!pat.getAnnotatedType().isAnnotationPresent(Configuration.class)) + { + return; + } + final Class<?> javaClass = pat.getAnnotatedType().getJavaClass(); + if (!javaClass.isInterface()) + { + return; + } + dynamicConfigurationBeanClasses.add(javaClass); + } + public void findSources(@Observes ProcessBean<? extends ConfigSource> source) { - if (!source.getAnnotated().isAnnotationPresent(Source.class)) { + if (!source.getAnnotated().isAnnotationPresent(Source.class)) + { return; } cdiSources.add(source.getBean()); @@ -137,7 +157,8 @@ public class ConfigurationExtension implements Extension, Deactivatable public void findFilters(@Observes ProcessBean<? extends ConfigFilter> filter) { - if (!filter.getAnnotated().isAnnotationPresent(Filter.class)) { + if (!filter.getAnnotated().isAnnotationPresent(Filter.class)) + { return; } cdiFilters.add(filter.getBean()); @@ -162,12 +183,23 @@ public class ConfigurationExtension implements Extension, Deactivatable } } - public void addDynamicBean(@Observes AfterBeanDiscovery afterBeanDiscovery, BeanManager bm) + public void addDynamicBeans(@Observes AfterBeanDiscovery afterBeanDiscovery, BeanManager bm) { if (dynamicProducer != null && !dynamicConfigTypes.isEmpty()) { afterBeanDiscovery.addBean(new DynamicBean(dynamicProducer, dynamicConfigTypes)); } + for (final Class<?> proxyType : dynamicConfigurationBeanClasses) + { + afterBeanDiscovery.addBean(new BeanBuilder(null) + .types(proxyType, Object.class) + .qualifiers(new DefaultLiteral(), new AnyLiteral()) + .beanLifecycle(new ProxyConfigurationLifecycle(proxyType)) + .scope(ApplicationScoped.class) + .passivationCapable(true) + .beanClass(proxyType) + .create()); + } } @SuppressWarnings("UnusedDeclaration") http://git-wip-us.apache.org/repos/asf/deltaspike/blob/b81d4987/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/config/ProxyConfigurationLifecycle.java ---------------------------------------------------------------------- diff --git a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/config/ProxyConfigurationLifecycle.java b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/config/ProxyConfigurationLifecycle.java new file mode 100644 index 0000000..645e227 --- /dev/null +++ b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/config/ProxyConfigurationLifecycle.java @@ -0,0 +1,157 @@ +/* + * 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.deltaspike.core.impl.config; + +import org.apache.deltaspike.core.api.config.ConfigProperty; +import org.apache.deltaspike.core.api.config.ConfigResolver; +import org.apache.deltaspike.core.api.config.Configuration; +import org.apache.deltaspike.core.spi.config.BaseConfigPropertyProducer; +import org.apache.deltaspike.core.util.metadata.builder.ContextualLifecycle; + +import javax.enterprise.context.spi.CreationalContext; +import javax.enterprise.inject.spi.Bean; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +class ProxyConfigurationLifecycle implements ContextualLifecycle +{ + private Class<?>[] api; + + ProxyConfigurationLifecycle(final Class<?> proxyType) + { + this.api = new Class<?>[]{proxyType}; + } + + @Override + public Object create(final Bean bean, final CreationalContext creationalContext) + { + // TODO: support partialbean binding? can make sense for virtual properties + would integrate with jcache + // we'd need to add @PartialBeanBinding on a bean created from ConfigurationHandler + // detection can just be a loadClass of this API + // for now: waiting for user request for it + + final Configuration configuration = api[0].getAnnotation(Configuration.class); + final long cacheFor = configuration.cacheFor(); + return Proxy.newProxyInstance( + Thread.currentThread().getContextClassLoader(), api, + new ConfigurationHandler(cacheFor <= 0 ? -1 : configuration.cacheUnit().toMillis(cacheFor))); + } + + @Override + public void destroy(final Bean bean, final Object instance, final CreationalContext creationalContext) + { + // no-op + } + + private static final class ConfigurationHandler implements InvocationHandler + { + private final BaseConfigPropertyProducer delegate = new BaseConfigPropertyProducer() + { + }; + + private final ConcurrentMap<Method, ConfigResolver.TypedResolver<?>> resolvers = + new ConcurrentHashMap<Method, ConfigResolver.TypedResolver<?>>(); + private final long cacheMs; + + private ConfigurationHandler(final long cacheMs) + { + this.cacheMs = cacheMs; + } + + @Override + public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable + { + if (Object.class == method.getDeclaringClass()) + { + try + { + return method.invoke(this, args); + } + catch (final InvocationTargetException ite) + { + throw ite.getCause(); + } + } + + ConfigResolver.TypedResolver<?> typedResolver = resolvers.get(method); + if (typedResolver == null) + { + final ConfigProperty annotation = method.getAnnotation(ConfigProperty.class); + if (annotation == null) + { + throw new UnsupportedOperationException( + method + " doesn't have @ConfigProperty and therefore is illegal"); + } + + // handle primitive bridge there (cdi doesnt support primitives but no reason our proxies don't) + Class<?> returnType = method.getReturnType(); + if (int.class == returnType) + { + returnType = Integer.class; + } + else if (long.class == returnType) + { + returnType = Long.class; + } + else if (boolean.class == returnType) + { + returnType = Boolean.class; + } + else if (short.class == returnType) + { + returnType = Short.class; + } + else if (byte.class == returnType) + { + returnType = Byte.class; + } + else if (float.class == returnType) + { + returnType = Float.class; + } + else if (double.class == returnType) + { + returnType = Double.class; + } + + typedResolver = delegate.asResolver( + annotation.name(), annotation.defaultValue(), returnType, + annotation.converter(), annotation.parameterizedBy(), + annotation.projectStageAware(), annotation.evaluateVariables()); + if (cacheMs > 0) + { + typedResolver.cacheFor(MILLISECONDS, cacheMs); + } + + final ConfigResolver.TypedResolver<?> existing = resolvers.putIfAbsent(method, typedResolver); + if (existing != null) + { + typedResolver = existing; + } + } + return typedResolver.getValue(); + } + } +} http://git-wip-us.apache.org/repos/asf/deltaspike/blob/b81d4987/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/api/config/injectable/ConfigBean.java ---------------------------------------------------------------------- diff --git a/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/api/config/injectable/ConfigBean.java b/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/api/config/injectable/ConfigBean.java new file mode 100644 index 0000000..40bcb45 --- /dev/null +++ b/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/api/config/injectable/ConfigBean.java @@ -0,0 +1,83 @@ +/* + * 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.deltaspike.test.core.api.config.injectable; + +import org.apache.deltaspike.core.api.config.ConfigProperty; +import org.apache.deltaspike.core.api.config.Configuration; + +import java.net.URL; +import java.util.List; + +@Configuration +public interface ConfigBean +{ + @ConfigProperty(name = "configProperty1") + int intProperty1(); + + @ConfigProperty(name = "configProperty1", defaultValue = "myDefaultValue") + String stringProperty3Filled(); + + @ConfigProperty(name = "nonexistingProperty", defaultValue = "myDefaultValue") + String stringProperty3Defaulted(); + + @ConfigProperty(name = "nonexistingProperty", defaultValue = "42") + Integer intProperty4Defaulted(); + + @ConfigProperty(name = "configProperty1") + Boolean booleanPropertyNull(); + + @ConfigProperty(name = "configProperty1", defaultValue = "false") + boolean booleanPropertyFalse(); + + @ConfigProperty(name = "configPropertyTrue1") + Boolean booleanPropertyTrue1(); + + @ConfigProperty(name = "configPropertyTrue2") + Boolean booleanPropertyTrue2(); + + @ConfigProperty(name = "configPropertyTrue3") + Boolean booleanPropertyTrue3(); + + @ConfigProperty(name = "configPropertyTrue4") + Boolean booleanPropertyTrue4(); + + @ConfigProperty(name = "configPropertyTrue5") + Boolean booleanPropertyTrue5(); + + @ConfigProperty(name = "configPropertyTrue6") + Boolean booleanPropertyTrue6(); + + @ConfigProperty(name = "configPropertyTrue7") + Boolean booleanPropertyTrue7(); + + @ConfigProperty(name = "configPropertyTrue8") + Boolean booleanPropertyTrue8(); + + @ConfigProperty(name = "testDbConfig") + String dbConfig(); + + @ConfigProperty(name = "urlList", converter = SettingsBean.UrlList.class, defaultValue = "http://localhost,http://127.0.0.1") + List<URL> urlList(); + + @ConfigProperty(name = "urlListFromProperties", converter = SettingsBean.UrlList.class) + List<URL> urlListFromProperties(); + + @ConfigProperty(name = "custom-source.test") + String customSourceValue(); +} http://git-wip-us.apache.org/repos/asf/deltaspike/blob/b81d4987/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/api/config/injectable/InjectableConfigPropertyTest.java ---------------------------------------------------------------------- diff --git a/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/api/config/injectable/InjectableConfigPropertyTest.java b/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/api/config/injectable/InjectableConfigPropertyTest.java index aea89ed..bb1e573 100644 --- a/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/api/config/injectable/InjectableConfigPropertyTest.java +++ b/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/api/config/injectable/InjectableConfigPropertyTest.java @@ -31,7 +31,6 @@ import org.jboss.shrinkwrap.api.ShrinkWrap; import org.jboss.shrinkwrap.api.asset.EmptyAsset; import org.jboss.shrinkwrap.api.spec.JavaArchive; import org.jboss.shrinkwrap.api.spec.WebArchive; -import org.junit.Assert; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -41,6 +40,7 @@ import org.apache.deltaspike.test.core.api.config.injectable.numberconfig.Number import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; @RunWith(Arquillian.class) @@ -73,41 +73,41 @@ public class InjectableConfigPropertyTest { SettingsBean settingsBean = BeanProvider.getContextualReference(SettingsBean.class, false); - Assert.assertEquals(14, settingsBean.getProperty1()); - Assert.assertEquals(7L, settingsBean.getProperty2()); - Assert.assertEquals(-7L, settingsBean.getInverseProperty2()); + assertEquals(14, settingsBean.getProperty1()); + assertEquals(7L, settingsBean.getProperty2()); + assertEquals(-7L, settingsBean.getInverseProperty2()); // also check the ones with defaultValue - Assert.assertEquals("14", settingsBean.getProperty3Filled()); - Assert.assertEquals("myDefaultValue", settingsBean.getProperty3Defaulted()); - Assert.assertEquals(42, settingsBean.getProperty4Defaulted()); + assertEquals("14", settingsBean.getProperty3Filled()); + assertEquals("myDefaultValue", settingsBean.getProperty3Defaulted()); + assertEquals(42, settingsBean.getProperty4Defaulted()); - Assert.assertEquals("some setting for prodDB", settingsBean.getDbConfig()); + assertEquals("some setting for prodDB", settingsBean.getDbConfig()); } @Test public void testBooleanPropertyInjection() { SettingsBean settingsBean = BeanProvider.getContextualReference(SettingsBean.class, false); - Assert.assertEquals(Boolean.FALSE, settingsBean.getBooleanPropertyFalse()); - - Assert.assertEquals(Boolean.TRUE, settingsBean.getBooleanPropertyTrue1()); - Assert.assertEquals(Boolean.TRUE, settingsBean.getBooleanPropertyTrue2()); - Assert.assertEquals(Boolean.TRUE, settingsBean.getBooleanPropertyTrue3()); - Assert.assertEquals(Boolean.TRUE, settingsBean.getBooleanPropertyTrue4()); - Assert.assertEquals(Boolean.TRUE, settingsBean.getBooleanPropertyTrue5()); - Assert.assertEquals(Boolean.TRUE, settingsBean.getBooleanPropertyTrue6()); - Assert.assertEquals(Boolean.TRUE, settingsBean.getBooleanPropertyTrue7()); - Assert.assertEquals(Boolean.TRUE, settingsBean.getBooleanPropertyTrue8()); + assertEquals(Boolean.FALSE, settingsBean.getBooleanPropertyFalse()); + + assertEquals(Boolean.TRUE, settingsBean.getBooleanPropertyTrue1()); + assertEquals(Boolean.TRUE, settingsBean.getBooleanPropertyTrue2()); + assertEquals(Boolean.TRUE, settingsBean.getBooleanPropertyTrue3()); + assertEquals(Boolean.TRUE, settingsBean.getBooleanPropertyTrue4()); + assertEquals(Boolean.TRUE, settingsBean.getBooleanPropertyTrue5()); + assertEquals(Boolean.TRUE, settingsBean.getBooleanPropertyTrue6()); + assertEquals(Boolean.TRUE, settingsBean.getBooleanPropertyTrue7()); + assertEquals(Boolean.TRUE, settingsBean.getBooleanPropertyTrue8()); } @Test public void testNmberConfigInjection() { NumberConfiguredBean numberBean = BeanProvider.getContextualReference(NumberConfiguredBean.class, false); - Assert.assertNull(numberBean.getPropertyNonexisting()); - Assert.assertEquals(Float.valueOf(123.45f), numberBean.getPropertyFromConfig()); - Assert.assertEquals(Float.valueOf(42.42f), numberBean.getPropertyNonexistingDefaulted()); + assertNull(numberBean.getPropertyNonexisting()); + assertEquals(Float.valueOf(123.45f), numberBean.getPropertyFromConfig()); + assertEquals(Float.valueOf(42.42f), numberBean.getPropertyNonexistingDefaulted()); } @Test @@ -124,4 +124,29 @@ public class InjectableConfigPropertyTest SettingsBean settingsBean = BeanProvider.getContextualReference(SettingsBean.class, false); assertEquals("value", settingsBean.getCustomSourceValue()); } + + @Test + public void proxy() throws MalformedURLException + { + ConfigBean settingsBean = BeanProvider.getContextualReference(ConfigBean.class); + + assertEquals(14, settingsBean.intProperty1()); + assertEquals("14", settingsBean.stringProperty3Filled()); + assertEquals("myDefaultValue", settingsBean.stringProperty3Defaulted()); + assertEquals(42, settingsBean.intProperty4Defaulted().intValue()); + + assertEquals("some setting for prodDB", settingsBean.dbConfig()); + assertEquals(Boolean.FALSE, settingsBean.booleanPropertyFalse()); + assertEquals(Boolean.TRUE, settingsBean.booleanPropertyTrue1()); + assertEquals(Boolean.TRUE, settingsBean.booleanPropertyTrue2()); + assertEquals(Boolean.TRUE, settingsBean.booleanPropertyTrue3()); + assertEquals(Boolean.TRUE, settingsBean.booleanPropertyTrue4()); + assertEquals(Boolean.TRUE, settingsBean.booleanPropertyTrue5()); + assertEquals(Boolean.TRUE, settingsBean.booleanPropertyTrue6()); + assertEquals(Boolean.TRUE, settingsBean.booleanPropertyTrue7()); + assertEquals(Boolean.TRUE, settingsBean.booleanPropertyTrue8()); + assertEquals(asList(new URL("http://localhost"), new URL("http://127.0.0.1")), settingsBean.urlList()); + assertEquals(singletonList(new URL("http://127.0.0.2")), settingsBean.urlListFromProperties()); + assertEquals("value", settingsBean.customSourceValue()); + } }