Skip to content

Commit 6b61445

Browse files
author
Roman Janusz
authored
Merge pull request #432 from mhawryluk/conditional-bean-includes
Conditional beans include support in commons-spring
2 parents 7635485 + 5b9b974 commit 6b61445

File tree

6 files changed

+105
-9
lines changed

6 files changed

+105
-9
lines changed

commons-spring/src/main/scala/com/avsystem/commons/spring/HoconBeanDefinitionReader.scala

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
package com.avsystem.commons
22
package spring
33

4-
import java.{util => ju}
5-
64
import com.avsystem.commons.spring.AttrNames._
7-
import scala.annotation.nowarn
85
import com.typesafe.config._
96
import org.springframework.beans.factory.annotation.Qualifier
107
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder
@@ -13,9 +10,13 @@ import org.springframework.beans.factory.support._
1310
import org.springframework.beans.{MutablePropertyValues, PropertyValue}
1411
import org.springframework.core.io.Resource
1512

13+
import java.{util => ju}
14+
import scala.annotation.nowarn
15+
1616
class HoconBeanDefinitionReader(registry: BeanDefinitionRegistry)
1717
extends AbstractBeanDefinitionReader(registry) {
1818

19+
import com.avsystem.commons.spring.HoconBeanDefinitionReader.Keys._
1920
import com.typesafe.config.ConfigValueType._
2021

2122
private implicit class ConfigValueExtensions(value: ConfigValue) {
@@ -344,9 +345,22 @@ class HoconBeanDefinitionReader(registry: BeanDefinitionRegistry)
344345
}
345346
}
346347

347-
def loadBeanDefinitions(config: Config): Int = {
348-
val beans = if (config.hasPath("beans")) config.getObject("beans") else ConfigFactory.empty.root
349-
val aliases = if (config.hasPath("aliases")) config.getObject("aliases") else ConfigFactory.empty.root
348+
private def readConditionals(config: Config): Config = {
349+
if (!config.hasPath(Conditionals)) config
350+
else config.getList(Conditionals).asScala.foldLeft(config.withoutPath(Conditionals)) { (currentConfig, conditionalObject) =>
351+
val props = getProps(conditionalObject.as[ConfigObject])
352+
353+
if (props(Condition).as[Boolean])
354+
readConditionals(props(Config).as[Config]).withFallback(currentConfig)
355+
else
356+
currentConfig
357+
}
358+
}
359+
360+
def loadBeanDefinitions(resourceConfig: Config): Int = {
361+
val config = readConditionals(resourceConfig)
362+
val beans = if (config.hasPath(Beans)) config.getObject(Beans) else ConfigFactory.empty.root
363+
val aliases = if (config.hasPath(Aliases)) config.getObject(Aliases) else ConfigFactory.empty.root
350364
val result = readBeans(beans)
351365
readAliases(aliases)
352366
result
@@ -355,3 +369,12 @@ class HoconBeanDefinitionReader(registry: BeanDefinitionRegistry)
355369
def loadBeanDefinitions(resource: Resource): Int =
356370
loadBeanDefinitions(ConfigFactory.parseURL(resource.getURL).resolve)
357371
}
372+
object HoconBeanDefinitionReader {
373+
object Keys {
374+
final val Conditionals = "conditionals"
375+
final val Condition = "condition"
376+
final val Config = "config"
377+
final val Beans = "beans"
378+
final val Aliases = "aliases"
379+
}
380+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
beans {
2+
beanFromConditional = {
3+
%class = com.avsystem.commons.spring.ConditionalTestBean, %construct = true
4+
int = 100
5+
}
6+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
featureFlag.enabled = false
2+
3+
beans.beanFromConditional = null
4+
5+
conditionals = [
6+
{condition: ${featureFlag.enabled}, config: {include "conditionalInclude.conf"}},
7+
]
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
featureFlag.enabled = true
2+
3+
beans.beanFromConditional = null
4+
5+
conditionals = [
6+
{condition: ${featureFlag.enabled}, config: {include "conditionalInclude.conf"}},
7+
]
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
featureFlag.enabled = true
2+
3+
beans {
4+
testBean {
5+
%class = com.avsystem.commons.spring.TestBean
6+
}
7+
}
8+
9+
conditionals = [
10+
{condition: ${featureFlag.enabled}, config: {beans.testBean.int = 0}},
11+
{condition: ${featureFlag.enabled}, config: {beans.testBean.int = 1}},
12+
{
13+
condition: ${featureFlag.enabled}, config: {
14+
conditionals = [
15+
{condition: true, config: {beans.testBean.int = 2}}
16+
]
17+
}
18+
},
19+
{condition: false, config: {beans.testBean.int = 3}},
20+
]

commons-spring/src/test/scala/com/avsystem/commons/spring/HoconBeanDefinitionReaderTest.scala

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
package com.avsystem.commons
22
package spring
33

4-
import java.{util => ju}
5-
64
import com.typesafe.config.{Config, ConfigFactory}
5+
import org.scalatest.BeforeAndAfterEach
76
import org.scalatest.funsuite.AnyFunSuite
87
import org.springframework.beans.factory.support.DefaultListableBeanFactory
98
import org.springframework.context.support.GenericApplicationContext
109
import org.springframework.core.StandardReflectionParameterNameDiscoverer
1110

11+
import java.{util => ju}
1212
import scala.beans.BeanProperty
1313

1414
class TestBean(val constrInt: Int = 1, val constrString: String = "constrDefault") {
@@ -25,7 +25,17 @@ object TestBean {
2525
new TestBean(theInt, theString)
2626
}
2727

28-
class HoconBeanDefinitionReaderTest extends AnyFunSuite {
28+
class ConditionalTestBean(int: Int) {
29+
30+
import ConditionalTestBean.initializedCount
31+
32+
initializedCount += 1
33+
}
34+
object ConditionalTestBean {
35+
var initializedCount = 0
36+
}
37+
38+
class HoconBeanDefinitionReaderTest extends AnyFunSuite with BeforeAndAfterEach {
2939
def createContext(resource: String): GenericApplicationContext = {
3040
val beanFactory = new DefaultListableBeanFactory
3141
beanFactory.setParameterNameDiscoverer(new StandardReflectionParameterNameDiscoverer)
@@ -40,6 +50,10 @@ class HoconBeanDefinitionReaderTest extends AnyFunSuite {
4050
ctx
4151
}
4252

53+
override def beforeEach(): Unit = {
54+
ConditionalTestBean.initializedCount = 0
55+
}
56+
4357
test("hocon bean definition reader should work") {
4458
val ctx = createContext("testBean.conf")
4559

@@ -82,4 +96,23 @@ class HoconBeanDefinitionReaderTest extends AnyFunSuite {
8296
assert(testBeanFMDefAll.constrInt == -1)
8397
assert(testBeanFMDefAll.constrString == "factoryDefault")
8498
}
99+
100+
test("file should be included with true condition") {
101+
val ctx = createContext("conditionalsEnabled.conf")
102+
val testBean = ctx.getBean("beanFromConditional", classOf[ConditionalTestBean])
103+
assert(testBean != null)
104+
assertResult(1)(ConditionalTestBean.initializedCount)
105+
}
106+
107+
test("file should not be included with false condition") {
108+
val ctx = createContext("conditionalsDisabled.conf")
109+
assert(!ctx.containsBean("beanFromConditional"))
110+
assertResult(0)(ConditionalTestBean.initializedCount)
111+
}
112+
113+
test("hocon bean definition with nested conditionals should work") {
114+
val ctx = createContext("conditionalsNested.conf")
115+
val testBean = ctx.getBean("testBean", classOf[TestBean])
116+
assert(testBean.int == 2)
117+
}
85118
}

0 commit comments

Comments
 (0)