diff --git a/README.md b/README.md index a18032f78..e86758139 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,4 @@ * [`commons-mongo`](docs/TypedMongo.md) - MongoDB utilities for Scala & Java MongoDB drivers, integration with `GenCodec` * `commons-hocon` - Utilities for working with [HOCON](https://github.com/lightbend/config/blob/master/HOCON.md) * `HoconInput` - an `Input` implementation for `GenCodec` that can read Lightbend Config (`com.typesafe.config.Config`) - * An AST (`HTree`) and a lexer/parser for HOCON (`HLexer`, `HParser`) -* `commons-spring` (DEPRECATED) - Spring framework utilities: - * `HoconBeanDefinitionReader` - an utility that allows you to define Spring application context using - [HOCON](https://github.com/lightbend/config/blob/master/HOCON.md) format + * An AST (`HTree`) and a lexer/parser for HOCON (`HLexer`, `HParser`) \ No newline at end of file diff --git a/project/Commons.scala b/project/Commons.scala index 4d3b4697f..690d97a2d 100644 --- a/project/Commons.scala +++ b/project/Commons.scala @@ -30,7 +30,6 @@ object Commons extends ProjectGroup("commons") { val scalacheckVersion = "1.19.0" val jettyVersion = "12.1.7" val mongoVersion = "5.6.4" - val springVersion = "6.2.17" val typesafeConfigVersion = "1.4.6" val commonsIoVersion = "1.3.2" // test only val scalaLoggingVersion = "3.9.6" @@ -202,7 +201,6 @@ object Commons extends ProjectGroup("commons") { jetty, mongo, hocon, - spring, ) .settings(aggregateProjectSettings) @@ -307,16 +305,6 @@ object Commons extends ProjectGroup("commons") { ), ) - lazy val spring = mkSubProject - .dependsOn(hocon % CompileAndTest) - .settings( - jvmCommonSettings, - libraryDependencies ++= Seq( - "org.springframework" % "spring-context" % springVersion, - "com.google.code.findbugs" % "jsr305" % jsr305Version % Optional, - ), - ) - lazy val jetty = mkSubProject .dependsOn(core % CompileAndTest) .settings( diff --git a/spring/src/main/scala/com/avsystem/commons/spring/AttrNames.scala b/spring/src/main/scala/com/avsystem/commons/spring/AttrNames.scala deleted file mode 100644 index 84c77f2e8..000000000 --- a/spring/src/main/scala/com/avsystem/commons/spring/AttrNames.scala +++ /dev/null @@ -1,94 +0,0 @@ -package com.avsystem.commons -package spring - -import scala.annotation.nowarn -import org.springframework.beans.factory.support.AbstractBeanDefinition - -/** Created: 17-03-2014 Author: ghik - */ -@deprecated(spring.DeprecatedMessage, spring.DeprecatedSince) -object AttrNames { - final val AbstractAttr = "%abstract" - final val ArgTypesAttr = "%arg-types" - final val ArrayAttr = "%array" - final val AutowireAttr = "%autowire" - final val AutowireCandidateAttr = "%autowire-candidate" - final val ClassAttr = "%class" - final val ConstructAttr = "%construct" - final val ConstructorArgsAttr = "%constructor-args" - final val DependencyCheckAttr = "%dependency-check" - final val DependsOnAttr = "%depends-on" - final val DescriptionAttr = "%description" - final val DestroyMethodAttr = "%destroy-method" - final val EntriesAttr = "%entries" - final val FactoryBeanAttr = "%factory-bean" - final val FactoryMethodAttr = "%factory-method" - final val IdrefAttr = "%idref" - final val IndexAttr = "%index" - final val InitMethodAttr = "%init-method" - final val KeyAttr = "%key" - final val KeyTypeAttr = "%key-type" - final val LazyInitAttr = "%lazy-init" - final val ListAttr = "%list" - final val LookupMethodsAttr = "%lookup-methods" - final val MergeAttr = "%merge" - final val MetaAttr = "%meta" - final val NameAttr = "%name" - final val ParentAttr = "%parent" - final val PrimaryAttr = "%primary" - final val PropsAttr = "%props" - final val QualifiersAttr = "%qualifiers" - final val RefAttr = "%ref" - final val ReplacedMethodsAttr = "%replaced-methods" - final val ReplacerAttr = "%replacer" - final val ScopeAttr = "%scope" - final val SetAttr = "%set" - final val TypeAttr = "%type" - final val ValueAttr = "%value" - final val ValueTypeAttr = "%value-type" - final val ConfigAttr = "%config" - - final val BeanAttrs = Set( - AbstractAttr, - AutowireAttr, - AutowireCandidateAttr, - ClassAttr, - ConstructAttr, - ConstructorArgsAttr, - DependencyCheckAttr, - DependsOnAttr, - DescriptionAttr, - DestroyMethodAttr, - FactoryBeanAttr, - FactoryMethodAttr, - InitMethodAttr, - LazyInitAttr, - LookupMethodsAttr, - MetaAttr, - NameAttr, - ParentAttr, - PrimaryAttr, - QualifiersAttr, - ReplacedMethodsAttr, - ScopeAttr, - ) - - final val AutowireMapping = Map( - "no" -> AbstractBeanDefinition.AUTOWIRE_NO, - "byName" -> AbstractBeanDefinition.AUTOWIRE_BY_NAME, - "byType" -> AbstractBeanDefinition.AUTOWIRE_BY_TYPE, - "constructor" -> AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR, - "autodetect" -> AbstractBeanDefinition.AUTOWIRE_AUTODETECT: @nowarn, - ) - - final val ReverseAutowireMapping = AutowireMapping.map(_.swap) - - final val DependencyCheckMapping = Map( - "none" -> AbstractBeanDefinition.DEPENDENCY_CHECK_NONE, - "simple" -> AbstractBeanDefinition.DEPENDENCY_CHECK_SIMPLE, - "objects" -> AbstractBeanDefinition.DEPENDENCY_CHECK_OBJECTS, - "all" -> AbstractBeanDefinition.DEPENDENCY_CHECK_ALL, - ) - - final val ReverseDependencyCheckMapping = DependencyCheckMapping.map(_.swap) -} diff --git a/spring/src/main/scala/com/avsystem/commons/spring/HoconBeanDefinitionReader.scala b/spring/src/main/scala/com/avsystem/commons/spring/HoconBeanDefinitionReader.scala deleted file mode 100644 index 8e3a01794..000000000 --- a/spring/src/main/scala/com/avsystem/commons/spring/HoconBeanDefinitionReader.scala +++ /dev/null @@ -1,387 +0,0 @@ -package com.avsystem.commons -package spring - -import com.avsystem.commons.spring.AttrNames._ -import com.typesafe.config._ -import org.springframework.beans.factory.annotation.Qualifier -import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder -import org.springframework.beans.factory.config.{BeanDefinitionHolder, ConstructorArgumentValues, RuntimeBeanNameReference, RuntimeBeanReference} -import org.springframework.beans.factory.support._ -import org.springframework.beans.{MutablePropertyValues, PropertyValue} -import org.springframework.core.io.Resource - -import java.{util => ju} -import scala.annotation.nowarn - -@deprecated(spring.DeprecatedMessage, spring.DeprecatedSince) -class HoconBeanDefinitionReader(registry: BeanDefinitionRegistry) extends AbstractBeanDefinitionReader(registry) { - - import com.avsystem.commons.spring.HoconBeanDefinitionReader.Keys._ - import com.typesafe.config.ConfigValueType._ - - private implicit class ConfigValueExtensions(value: ConfigValue) { - def as[T: HoconType]: T = - implicitly[HoconType[T]].get(value) - } - - private val autowireMapping = AutowireMapping.withDefault { v => - throw new IllegalArgumentException(s"Invalid value $v for $AutowireAttr attribute") - } - - private val dependencyCheckMapping = DependencyCheckMapping.withDefault { v => - throw new IllegalArgumentException(s"Invalid value $v for $DependencyCheckAttr attribute") - } - - private def setup[T](t: T)(setupFunc: T => Any) = { - setupFunc(t) - t - } - - private def iterate(obj: ConfigObject)(attrFun: (String, ConfigValue) => Any)(propFun: (String, ConfigValue) => Any) = - obj.asScala.foreach { - case (key, _) if key.startsWith("_") => - case (key, value) if key.startsWith("%") => attrFun(key, value) - case (key, value) => propFun(key, value) - } - - private def validateObj( - required: Set[String] = Set.empty, - requiredAny: Set[String] = Set.empty, - allowed: Set[String] = Set.empty, - props: Boolean = false, - )( - obj: ConfigObject - ): Unit = { - require( - required.forall(obj.containsKey), - s"Attributes ${required.mkString(", ")} must be present in object at ${obj.origin.description}", - ) - require( - requiredAny.isEmpty || requiredAny.exists(obj.containsKey), - s"At least one of ${requiredAny.mkString(", ")} must be present in object at ${obj.origin.description}", - ) - val allAllowed = required ++ requiredAny ++ allowed - iterate(obj) { (key, value) => - if (!allAllowed.contains(key)) - badAttr(key, value) - } { (key, value) => - if (!props) - badProp(key, value) - } - } - - @nowarn("msg=deprecated") - private def getProps(obj: ConfigObject) = - obj.asScala.filterKeys(k => !k.startsWith("%") && !k.startsWith("_")) - - private def badAttr(key: String, value: ConfigValue) = - throw new IllegalArgumentException(s"Unexpected attribute $key at ${value.origin.description}") - - private def badProp(key: String, value: ConfigValue) = - throw new IllegalArgumentException(s"Unexpected property $key at ${value.origin.description}") - - private object BeanDefinition { - val BeanOnlyAttrs = BeanAttrs - MetaAttr - - def unapply(obj: ConfigObject) = - if (BeanOnlyAttrs.exists(obj.as[ConfigObject].keySet.contains)) Some(obj) else None - } - - private class ObjectWithAttributePresentExtractor(elementAttr: String) { - def unapply(obj: ConfigObject) = - if (obj.containsKey(elementAttr)) Some(obj) else None - } - - private object ListDefinition extends ObjectWithAttributePresentExtractor(ListAttr) - - private object ArrayDefinition extends ObjectWithAttributePresentExtractor(ArrayAttr) - - private object SetDefinition extends ObjectWithAttributePresentExtractor(SetAttr) - - private object PropertiesDefinition extends ObjectWithAttributePresentExtractor(PropsAttr) - - private object ValueDefinition extends ObjectWithAttributePresentExtractor(ValueAttr) - - private object BeanReference extends ObjectWithAttributePresentExtractor(RefAttr) - - private object BeanNameReference extends ObjectWithAttributePresentExtractor(IdrefAttr) - - private object RawConfig extends ObjectWithAttributePresentExtractor(ConfigAttr) - - private def read(value: ConfigValue): Any = value match { - case BeanDefinition(obj) => - val bd = readBean(obj) - obj.get(NameAttr).as[Option[String]] match { - case Some(name) => new BeanDefinitionHolder(bd, name) - case None => bd - } - case BeanReference(obj) => readRef(obj) - case BeanNameReference(obj) => readIdref(obj) - case ArrayDefinition(obj) => readArray(obj) - case ListDefinition(obj) => readList(obj) - case SetDefinition(obj) => readSet(obj) - case PropertiesDefinition(obj) => readProperties(obj) - case RawConfig(obj) => readRawConfig(obj) - case obj: ConfigObject => readMap(obj) - case list: ConfigList => readRawList(list) - case _ => value.unwrapped - } - - private def readRef(obj: ConfigObject) = { - validateObj(required = Set(RefAttr), allowed = Set(ParentAttr))(obj) - new RuntimeBeanReference(obj.get(RefAttr).as[String], obj.get(ParentAttr).as[Option[Boolean]].getOrElse(false)) - } - - private def readIdref(obj: ConfigObject) = { - validateObj(required = Set(IdrefAttr))(obj) - new RuntimeBeanNameReference(obj.get(IdrefAttr).as[String]) - } - - private def readList(obj: ConfigObject) = { - validateObj(required = Set(ListAttr), allowed = Set(MergeAttr, ValueTypeAttr))(obj) - setup(new ManagedList[Any]) { list => - list.addAll(obj.get(ListAttr).as[ConfigList].asScala.map(read).asJavaCollection) - list.setMergeEnabled(obj.get(MergeAttr).as[Option[Boolean]].getOrElse(false)) - list.setElementTypeName(obj.get(ValueTypeAttr).as[Option[String]].orNull) - } - } - - private def readArray(obj: ConfigObject) = { - validateObj(required = Set(ArrayAttr), allowed = Set(MergeAttr, ValueTypeAttr))(obj) - val elements = obj.get(ArrayAttr).as[ConfigList] - val valueType = obj.get(ValueTypeAttr).as[Option[String]].getOrElse("") - val result = new ManagedArray(valueType, elements.size) - result.addAll(elements.asScala.map(v => read(v).asInstanceOf[AnyRef]).asJavaCollection) - result.setMergeEnabled(obj.get(MergeAttr).as[Option[Boolean]].getOrElse(false)) - result - } - - private def readSet(obj: ConfigObject) = { - validateObj(required = Set(SetAttr), allowed = Set(MergeAttr, ValueTypeAttr))(obj) - setup(new ManagedSet[Any]) { set => - set.addAll(obj.get(SetAttr).as[ConfigList].asScala.map(read).asJavaCollection) - set.setMergeEnabled(obj.get(MergeAttr).as[Option[Boolean]].getOrElse(false)) - set.setElementTypeName(obj.get(ValueTypeAttr).as[Option[String]].orNull) - } - } - - private def readRawList(list: ConfigList) = - setup(new ManagedList[Any]) { ml => - ml.addAll(list.asScala.map(read).asJavaCollection) - } - - private def readMap(obj: ConfigObject) = { - validateObj(allowed = Set(MergeAttr, KeyTypeAttr, ValueTypeAttr, EntriesAttr), props = true)(obj) - setup(new ManagedMap[Any, Any]) { mm => - mm.setMergeEnabled(obj.get(MergeAttr).as[Option[Boolean]].getOrElse(false)) - mm.setKeyTypeName(obj.get(KeyTypeAttr).as[Option[String]].orNull) - mm.setValueTypeName(obj.get(ValueTypeAttr).as[Option[String]].orNull) - obj.get(EntriesAttr).as[Option[ConfigList]].getOrElse(ju.Collections.emptyList).asScala.foreach { - case obj: ConfigObject => - validateObj(required = Set(KeyAttr, ValueAttr))(obj) - mm.put(read(obj.get(KeyAttr)), read(obj.get(ValueAttr))) - case _ => - throw new IllegalArgumentException(s"Required an object at ${obj.origin.description}") - } - getProps(obj).foreach { case (key, value) => - mm.put(key, read(value)) - } - } - } - - private def readProperties(obj: ConfigObject) = { - validateObj(required = Set(PropsAttr), allowed = Set(MergeAttr))(obj) - setup(new ManagedProperties) { mp => - mp.setMergeEnabled(obj.get(MergeAttr).as[Option[Boolean]].getOrElse(false)) - obj.get(PropsAttr).as[Option[Config]].getOrElse(ConfigFactory.empty).entrySet.asScala.foreach { - case entry if Set(STRING, NUMBER, BOOLEAN).contains(entry.getValue.valueType) => - mp.setProperty(entry.getKey, entry.getValue.unwrapped.toString) - case entry => throw new IllegalArgumentException(s"Bad prop definition at ${entry.getValue.origin.description}") - } - } - } - - private def readRawConfig(obj: ConfigObject) = { - validateObj(required = Set(ConfigAttr))(obj) - obj.get(ConfigAttr).as[Config] - } - - private def readBean(obj: ConfigObject) = { - val bd = new GenericBeanDefinition - val cargs = new ConstructorArgumentValues - val propertyValues = new MutablePropertyValues - bd.setConstructorArgumentValues(cargs) - bd.setPropertyValues(propertyValues) - bd.setResourceDescription(obj.origin.description) - - def addConstructorArg(idxAndValue: (Option[Int], ValueHolder)) = idxAndValue match { - case (Some(idx), valueHolder) => cargs.addIndexedArgumentValue(idx, valueHolder) - case (None, valueHolder) => cargs.addGenericArgumentValue(valueHolder) - } - - obj.get(AbstractAttr).as[Option[Boolean]].foreach(bd.setAbstract) - obj.get(AutowireCandidateAttr).as[Option[Boolean]].foreach(bd.setAutowireCandidate) - obj.get(AutowireAttr).as[Option[String]].map(autowireMapping).foreach(bd.setAutowireMode) - obj.get(ClassAttr).as[Option[String]].foreach(bd.setBeanClassName) - readConstructorArgs(obj.get(ConstructorArgsAttr)).foreach(addConstructorArg) - obj.get(DependencyCheckAttr).as[Option[String]].map(dependencyCheckMapping).foreach(bd.setDependencyCheck) - obj.get(DescriptionAttr).as[Option[String]].foreach(bd.setDescription) - obj.get(DestroyMethodAttr).as[Option[String]].foreach(bd.setDestroyMethodName) - obj.get(DependsOnAttr).as[Option[ju.List[String]]].map(_.asScala.toArray).foreach(bd.setDependsOn(_: _*)) - obj.get(FactoryBeanAttr).as[Option[String]].foreach(bd.setFactoryBeanName) - obj.get(FactoryMethodAttr).as[Option[String]].foreach(bd.setFactoryMethodName) - obj.get(InitMethodAttr).as[Option[String]].foreach(bd.setInitMethodName) - bd.setLazyInit(obj.get(LazyInitAttr).as[Option[Boolean]].getOrElse(false)) - obj.get(LookupMethodsAttr).as[Option[ConfigObject]].foreach { obj => - validateObj(props = true)(obj) - getProps(obj).foreach { case (key, value) => - bd.getMethodOverrides.addOverride(new LookupOverride(key, value.as[String])) - } - } - obj.get(MetaAttr).as[Option[ConfigObject]].getOrElse(ConfigFactory.empty.root).asScala.foreach { - case (mkey, mvalue) => bd.setAttribute(mkey, mvalue.as[String]) - } - obj.get(ParentAttr).as[Option[String]].foreach(bd.setParentName) - obj.get(PrimaryAttr).as[Option[Boolean]].foreach(bd.setPrimary) - obj.get(QualifiersAttr).as[Option[ju.List[ConfigObject]]].getOrElse(ju.Collections.emptyList).asScala.foreach { obj => - bd.addQualifier(readQualifier(obj)) - } - obj.get(ReplacedMethodsAttr).as[Option[ju.List[ConfigObject]]].getOrElse(ju.Collections.emptyList).asScala.foreach { - obj => - bd.getMethodOverrides.addOverride(readReplacedMethod(obj)) - } - obj.get(ScopeAttr).as[Option[String]].foreach(bd.setScope) - - val construct = obj.get(ConstructAttr).as[Option[Boolean]].getOrElse(false) - getProps(obj).foreach { case (key, value) => - if (construct) { - addConstructorArg(readConstructorArg(value, forcedName = key)) - } else { - propertyValues.addPropertyValue(readPropertyValue(key, value)) - } - } - bd - } - - private def readQualifier(obj: ConfigObject) = { - validateObj(allowed = Set(TypeAttr, ValueAttr), props = true)(obj) - val acq = new AutowireCandidateQualifier(obj.get(TypeAttr).as[Option[String]].getOrElse(classOf[Qualifier].getName)) - obj.get(ValueAttr).as[Option[String]].foreach(acq.setAttribute(AutowireCandidateQualifier.VALUE_KEY, _)) - getProps(obj).foreach { case (key, value) => - acq.setAttribute(key, value.as[String]) - } - acq - } - - private def readReplacedMethod(obj: ConfigObject) = { - validateObj(required = Set(NameAttr, ReplacerAttr), allowed = Set(ArgTypesAttr))(obj) - val replaceOverride = new ReplaceOverride(obj.get(NameAttr).as[String], obj.get(ReplacerAttr).as[String]) - obj - .get(ArgTypesAttr) - .as[Option[ju.List[String]]] - .getOrElse(ju.Collections.emptyList) - .asScala - .foreach(replaceOverride.addTypeIdentifier) - replaceOverride - } - - private def readConstructorArgs(value: ConfigValue) = - value.as[Option[Either[ConfigList, ConfigObject]]] match { - case Some(Left(list)) => - list.iterator.asScala.zipWithIndex.map { case (configValue, idx) => - readConstructorArg(configValue, forcedIndex = idx) - } - case Some(Right(obj)) => - validateObj(props = true)(obj) - getProps(obj).iterator.map { case (name, configValue) => - readConstructorArg(configValue, forcedName = name) - } - case None => - Iterator.empty - } - - private def readConstructorArg( - value: ConfigValue, - forcedIndex: OptArg[Int] = OptArg.Empty, - forcedName: OptArg[String] = OptArg.Empty, - ) = value match { - case ValueDefinition(obj) => - validateObj(required = Set(ValueAttr), allowed = Set(IndexAttr, TypeAttr, NameAttr))(obj) - val vh = new ValueHolder(read(obj.get(ValueAttr))) - obj.get(TypeAttr).as[Option[String]].foreach(vh.setType) - (forcedName.toOption orElse obj.get(NameAttr).as[Option[String]]).foreach(vh.setName) - val indexOpt = forcedIndex.toOption orElse obj.get(IndexAttr).as[Option[Int]] - (indexOpt, vh) - case _ => - val vh = new ValueHolder(read(value)) - forcedName.foreach(vh.setName) - (forcedIndex.toOption, vh) - } - - private def readPropertyValue(name: String, value: ConfigValue) = value match { - case ValueDefinition(obj) => - validateObj(required = Set(ValueAttr), allowed = Set(MetaAttr))(obj) - val pv = new PropertyValue(name, read(obj.get(ValueAttr))) - obj.get(MetaAttr).as[Option[ConfigObject]].getOrElse(ConfigFactory.empty.root).asScala.foreach { - case (mkey, mvalue) => pv.setAttribute(mkey, mvalue.as[String]) - } - pv - case _ => - new PropertyValue(name, read(value)) - } - - private def readBeans(obj: ConfigObject) = { - validateObj(props = true)(obj) - val beanDefs = getProps(obj).iterator.flatMap { case (key, value) => - try { - value.as[Option[ConfigObject]].map(obj => (key, readBean(obj))) - } catch { - case e: Exception => - throw new RuntimeException(s"Could not read definition of bean $key at ${value.origin.description}", e) - } - }.toVector - beanDefs.foreach((registry.registerBeanDefinition _).tupled) - beanDefs.size - } - - private def readAliases(obj: ConfigObject): Unit = { - validateObj(props = true)(obj) - getProps(obj).foreach { case (key, value) => - value.as[Option[String]].foreach(registry.registerAlias(_, key)) - } - } - - private def readConditionals(config: Config): Config = - if (!config.hasPath(Conditionals)) config - else - config.getList(Conditionals).asScala.foldLeft(config.withoutPath(Conditionals)) { - (currentConfig, conditionalObject) => - val props = getProps(conditionalObject.as[ConfigObject]) - - if (props(Condition).as[Boolean]) - readConditionals(props(Config).as[Config]).withFallback(currentConfig) - else - currentConfig - } - - def loadBeanDefinitions(resourceConfig: Config): Int = { - val config = readConditionals(resourceConfig) - val beans = if (config.hasPath(Beans)) config.getObject(Beans) else ConfigFactory.empty.root - val aliases = if (config.hasPath(Aliases)) config.getObject(Aliases) else ConfigFactory.empty.root - val result = readBeans(beans) - readAliases(aliases) - result - } - - def loadBeanDefinitions(resource: Resource): Int = - loadBeanDefinitions(ConfigFactory.parseURL(resource.getURL).resolve) -} -object HoconBeanDefinitionReader { - object Keys { - final val Conditionals = "conditionals" - final val Condition = "condition" - final val Config = "config" - final val Beans = "beans" - final val Aliases = "aliases" - } -} diff --git a/spring/src/main/scala/com/avsystem/commons/spring/HoconType.scala b/spring/src/main/scala/com/avsystem/commons/spring/HoconType.scala deleted file mode 100644 index 46bc47a73..000000000 --- a/spring/src/main/scala/com/avsystem/commons/spring/HoconType.scala +++ /dev/null @@ -1,152 +0,0 @@ -package com.avsystem.commons -package spring - -import com.typesafe.config._ -import scala.annotation.nowarn - -@deprecated(spring.DeprecatedMessage, spring.DeprecatedSince) -trait HoconType[T] { - - protected def requireNonNull(value: ConfigValue): ConfigValue = { - require(value != null, s"No value found") - value - } - - protected def requireType(requiredType: ConfigValueType, value: ConfigValue): Unit = { - requireNonNull(value) - require( - value.valueType == requiredType, - s"Value at ${value.origin.description} has type, ${value.valueType}, required $requiredType", - ) - } - - def get(value: ConfigValue): T -} - -@nowarn("msg=deprecated") -object HoconType { - - import com.typesafe.config.ConfigValueType._ - - implicit object anyHoconType extends HoconType[Any] { - def get(value: ConfigValue) = - requireNonNull(value).unwrapped - } - - implicit object anyRefHoconType extends HoconType[AnyRef] { - def get(value: ConfigValue) = - requireNonNull(value).unwrapped - } - - implicit object nullHoconType extends HoconType[Null] { - def get(value: ConfigValue) = { - requireType(NULL, value) - null - } - } - - implicit object stringHoconType extends HoconType[String] { - def get(value: ConfigValue) = { - requireType(STRING, value) - value.unwrapped.asInstanceOf[String] - } - } - - implicit object booleanHoconType extends HoconType[Boolean] { - def get(value: ConfigValue) = { - requireType(BOOLEAN, value) - value.unwrapped.asInstanceOf[Boolean] - } - } - - implicit object numberHoconType extends HoconType[JNumber] { - def get(value: ConfigValue) = { - requireType(NUMBER, value) - value.unwrapped.asInstanceOf[JNumber] - } - } - - implicit object intHoconType extends HoconType[Int] { - def get(value: ConfigValue) = { - requireType(NUMBER, value) - value.unwrapped.asInstanceOf[JNumber].intValue - } - } - - implicit object longHoconType extends HoconType[Long] { - def get(value: ConfigValue) = { - requireType(NUMBER, value) - value.unwrapped.asInstanceOf[JNumber].longValue - } - } - - implicit object configHoconType extends HoconType[Config] { - def get(value: ConfigValue) = { - requireType(OBJECT, value) - value.asInstanceOf[ConfigObject].toConfig - } - } - - implicit object configValueHoconType extends HoconType[ConfigValue] { - def get(value: ConfigValue) = value - } - - implicit object configObjectHoconType extends HoconType[ConfigObject] { - def get(value: ConfigValue) = { - requireType(OBJECT, value) - value.asInstanceOf[ConfigObject] - } - } - - implicit object configListHoconType extends HoconType[ConfigList] { - def get(value: ConfigValue) = { - requireType(LIST, value) - value.asInstanceOf[ConfigList] - } - } - - implicit def listHoconType[T: HoconType]: HoconType[JList[T]] = new HoconType[JList[T]] { - def get(value: ConfigValue) = { - requireType(LIST, value) - val elementHoconType = implicitly[HoconType[T]] - value.asInstanceOf[ConfigList].asScala.map(elementHoconType.get).asJava - } - } - - implicit def mapHoconType[T: HoconType]: HoconType[JMap[String, T]] = new HoconType[JMap[String, T]] { - def get(value: ConfigValue) = { - requireType(OBJECT, value) - val elementHoconType = implicitly[HoconType[T]] - value - .asInstanceOf[ConfigObject] - .asScala - .map { case (k, v) => - (k, elementHoconType.get(v)) - } - .asJava - } - } - - implicit def optionHoconType[T: HoconType]: HoconType[Option[T]] = new HoconType[Option[T]] { - def get(value: ConfigValue): Option[T] = - if (value == null || value.valueType == NULL) None - else Some(implicitly[HoconType[T]].get(value)) - } - - implicit def eitherHoconType[A: HoconType, B: HoconType]: HoconType[Either[A, B]] = new HoconType[Either[A, B]] { - def get(value: ConfigValue): Either[A, B] = { - val leftTry = Try(implicitly[HoconType[A]].get(value)) - val rightTry = Try(implicitly[HoconType[B]].get(value)) - - (leftTry, rightTry) match { - case (Failure(left), Failure(right)) => - throw new IllegalArgumentException( - "Could not parse config value as one of two types:\n" + left.getMessage + "\n" + right.getMessage - ) - case (Success(left), _) => Left(left) - case (_, Success(right)) => Right(right) - } - } - } - -} diff --git a/spring/src/main/scala/com/avsystem/commons/spring/ScalaDefaultValuesInjector.scala b/spring/src/main/scala/com/avsystem/commons/spring/ScalaDefaultValuesInjector.scala deleted file mode 100644 index 65ed564b3..000000000 --- a/spring/src/main/scala/com/avsystem/commons/spring/ScalaDefaultValuesInjector.scala +++ /dev/null @@ -1,92 +0,0 @@ -package com.avsystem.commons -package spring - -import java.lang.reflect.{Constructor, Method, Modifier} -import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder -import org.springframework.beans.factory.config.{BeanDefinition, BeanDefinitionHolder, ConfigurableListableBeanFactory} -import org.springframework.beans.factory.support._ -import org.springframework.core.{ParameterNameDiscoverer, StandardReflectionParameterNameDiscoverer} - -import scala.annotation.tailrec -import scala.beans.BeanProperty -import scala.reflect.{ScalaLongSignature, ScalaSignature} - -@deprecated(spring.DeprecatedMessage, spring.DeprecatedSince) -class ScalaDefaultValuesInjector extends BeanDefinitionRegistryPostProcessor { - @BeanProperty var paramNameDiscoverer: ParameterNameDiscoverer = - new StandardReflectionParameterNameDiscoverer - - def classLoader: ClassLoader = - Thread.currentThread.getContextClassLoader.opt getOrElse getClass.getClassLoader - - def loadClass(name: String): Class[_] = Class.forName(name, false, classLoader) - - def postProcessBeanDefinitionRegistry(registry: BeanDefinitionRegistry): Unit = { - def traverse(value: Any): Unit = value match { - case bd: BeanDefinition => - bd.getConstructorArgumentValues.getGenericArgumentValues.asScala.foreach(traverse) - bd.getConstructorArgumentValues.getIndexedArgumentValues.values.asScala.foreach(traverse) - bd.getPropertyValues.getPropertyValueList.asScala.foreach(pv => traverse(pv.getValue)) - injectDefaultValues(bd) - case bdw: BeanDefinitionHolder => - traverse(bdw.getBeanDefinition) - case vh: ValueHolder => - traverse(vh.getValue) - case ml: ManagedList[_] => - ml.asScala.foreach(traverse) - case ms: ManagedSet[_] => - ms.asScala.foreach(traverse) - case mm: ManagedMap[_, _] => - mm.asScala.foreach { case (k, v) => - traverse(k) - traverse(v) - } - case _ => - } - - registry.getBeanDefinitionNames.foreach(n => traverse(registry.getBeanDefinition(n))) - } - - @tailrec - private def isScalaClass(cls: Class[_]): Boolean = cls.getEnclosingClass match { - case null => - cls.getAnnotation(classOf[ScalaSignature]) != null || cls.getAnnotation(classOf[ScalaLongSignature]) != null - case encls => isScalaClass(encls) - } - - private def injectDefaultValues(bd: BeanDefinition): Unit = - bd.getBeanClassName.opt.map(loadClass).recoverToOpt[ClassNotFoundException].flatten.filter(isScalaClass).foreach { - clazz => - val usingConstructor = bd.getFactoryMethodName == null - val factoryExecs = - if (usingConstructor) clazz.getConstructors.toVector - else clazz.getMethods.iterator.filter(_.getName == bd.getFactoryMethodName).toVector - val factorySymbolName = - if (usingConstructor) "$lessinit$greater" else bd.getFactoryMethodName - - if (factoryExecs.size == 1) { - val constrVals = bd.getConstructorArgumentValues - val factoryExec = factoryExecs.head - val paramNames = factoryExec match { - case c: Constructor[_] => paramNameDiscoverer.getParameterNames(c) - case m: Method => paramNameDiscoverer.getParameterNames(m) - } - (0 until factoryExec.getParameterCount).foreach { i => - def defaultValueMethod = clazz - .getMethod(s"$factorySymbolName$$default$$${i + 1}") - .recoverToOpt[NoSuchMethodException] - .filter(m => Modifier.isStatic(m.getModifiers)) - def specifiedNamed = paramNames != null && - constrVals.getGenericArgumentValues.asScala.exists(_.getName == paramNames(i)) - def specifiedIndexed = - constrVals.getIndexedArgumentValues.get(i) != null - if (!specifiedNamed && !specifiedIndexed) { - defaultValueMethod.foreach { dvm => - constrVals.addIndexedArgumentValue(i, dvm.invoke(null)) - } - } - } - } - } - -} diff --git a/spring/src/main/scala/com/avsystem/commons/spring/package.scala b/spring/src/main/scala/com/avsystem/commons/spring/package.scala deleted file mode 100644 index c0124b77b..000000000 --- a/spring/src/main/scala/com/avsystem/commons/spring/package.scala +++ /dev/null @@ -1,6 +0,0 @@ -package com.avsystem.commons - -package object spring { - private[spring] final val DeprecatedMessage = "spring module is deprecated and it is going to be removed" - private[spring] final val DeprecatedSince = "2.27.0" -} diff --git a/spring/src/test/resources/bean1.conf b/spring/src/test/resources/bean1.conf deleted file mode 100644 index 0faf22ed6..000000000 --- a/spring/src/test/resources/bean1.conf +++ /dev/null @@ -1,6 +0,0 @@ -beans { - someBean { - %class = hoconspring.TestBean - stuff = 50 - } -} diff --git a/spring/src/test/resources/bean2.conf b/spring/src/test/resources/bean2.conf deleted file mode 100644 index b07defd21..000000000 --- a/spring/src/test/resources/bean2.conf +++ /dev/null @@ -1,3 +0,0 @@ -beans { - someBean.dafuq = shietlol -} diff --git a/spring/src/test/resources/beans.conf b/spring/src/test/resources/beans.conf deleted file mode 100644 index bb5abfe61..000000000 --- a/spring/src/test/resources/beans.conf +++ /dev/null @@ -1,39 +0,0 @@ -beans { - someAbstractBean { - %abstract = true - - settings { - inherited = 32 - } - characters.%set = [a, g, o] - } - - someBean { - %class = com.example.SomeBeanClass - %parent = someAbstractBean - - someNumberProperty = 42 - someStringProperty = someStringValue - settings { - %merge = true - someSetting = 5 - anotherSetting = 20 - } - numbers = [1, 2, 3, 4, 5] - characters { - %merge = true - %set = [a, b, c, d] - } - nestedBean { - %class = com.example.SomeOtherBeanClass - - otherNestedBean.%ref = otherBean - } - } - - otherBean { - %class = com.example.YetAnotherBeanClass - - someRandomProperty = someRandomString - } -} diff --git a/spring/src/test/resources/beans.xml b/spring/src/test/resources/beans.xml deleted file mode 100644 index 8c12a0db4..000000000 --- a/spring/src/test/resources/beans.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - a - g - o - - - - - - - - - - - - - - - - - - 1 - 2 - 3 - 4 - 5 - - - - - - a - b - c - d - - - - - - - - - - - - - - - - diff --git a/spring/src/test/resources/conditionalInclude.conf b/spring/src/test/resources/conditionalInclude.conf deleted file mode 100644 index e58e6926f..000000000 --- a/spring/src/test/resources/conditionalInclude.conf +++ /dev/null @@ -1,6 +0,0 @@ -beans { - beanFromConditional = { - %class = com.avsystem.commons.spring.ConditionalTestBean, %construct = true - int = 100 - } -} \ No newline at end of file diff --git a/spring/src/test/resources/conditionalsDisabled.conf b/spring/src/test/resources/conditionalsDisabled.conf deleted file mode 100644 index b7ad168aa..000000000 --- a/spring/src/test/resources/conditionalsDisabled.conf +++ /dev/null @@ -1,7 +0,0 @@ -featureFlag.enabled = false - -beans.beanFromConditional = null - -conditionals = [ - {condition: ${featureFlag.enabled}, config: {include "conditionalInclude.conf"}}, -] diff --git a/spring/src/test/resources/conditionalsEnabled.conf b/spring/src/test/resources/conditionalsEnabled.conf deleted file mode 100644 index 956e192ff..000000000 --- a/spring/src/test/resources/conditionalsEnabled.conf +++ /dev/null @@ -1,7 +0,0 @@ -featureFlag.enabled = true - -beans.beanFromConditional = null - -conditionals = [ - {condition: ${featureFlag.enabled}, config: {include "conditionalInclude.conf"}}, -] diff --git a/spring/src/test/resources/conditionalsNested.conf b/spring/src/test/resources/conditionalsNested.conf deleted file mode 100644 index c925c0512..000000000 --- a/spring/src/test/resources/conditionalsNested.conf +++ /dev/null @@ -1,20 +0,0 @@ -featureFlag.enabled = true - -beans { - testBean { - %class = com.avsystem.commons.spring.TestBean - } -} - -conditionals = [ - {condition: ${featureFlag.enabled}, config: {beans.testBean.int = 0}}, - {condition: ${featureFlag.enabled}, config: {beans.testBean.int = 1}}, - { - condition: ${featureFlag.enabled}, config: { - conditionals = [ - {condition: true, config: {beans.testBean.int = 2}} - ] - } - }, - {condition: false, config: {beans.testBean.int = 3}}, -] \ No newline at end of file diff --git a/spring/src/test/resources/testBean.conf b/spring/src/test/resources/testBean.conf deleted file mode 100644 index 9fd47c634..000000000 --- a/spring/src/test/resources/testBean.conf +++ /dev/null @@ -1,58 +0,0 @@ -abstract { - testBean { - %class = com.avsystem.commons.spring.TestBean - } - constrTestBean = ${abstract.testBean} { - %construct = true - } - fmTestBean = ${abstract.constrTestBean} { - %factory-method = create - } -} - -beans { - testBean = ${abstract.testBean} { - %constructor-args = [42, lolzsy] - int = 5 - string = lol - strIntMap { - fuu = 42 - } - strList = [a, b] - strSet = [A, B] - nestedBean = ${abstract.testBean} { - %constructor-args { - constrString = wut - constrInt = 1 - } - int = 6 - nestedBean = ${abstract.constrTestBean} { - constrString = yes - constrInt = 2 - } - } - config.%config { - srsly = dafuq - } - } - - testBeanDefInt = ${abstract.constrTestBean} { - constrString = constrNonDefault - } - - testBeanDefString = ${abstract.constrTestBean} { - constrInt = 2 - } - - testBeanDefAll = ${abstract.constrTestBean} - - testBeanFMDefInt = ${abstract.fmTestBean} { - theString = factoryNonDefault - } - - testBeanFMDefString = ${abstract.fmTestBean} { - theInt = -2 - } - - testBeanFMDefAll = ${abstract.fmTestBean} -} diff --git a/spring/src/test/scala/com/avsystem/commons/spring/HoconBeanDefinitionReaderTest.scala b/spring/src/test/scala/com/avsystem/commons/spring/HoconBeanDefinitionReaderTest.scala deleted file mode 100644 index aa3c4ba3c..000000000 --- a/spring/src/test/scala/com/avsystem/commons/spring/HoconBeanDefinitionReaderTest.scala +++ /dev/null @@ -1,120 +0,0 @@ -package com.avsystem.commons -package spring - -import com.typesafe.config.{Config, ConfigFactory} -import org.scalatest.BeforeAndAfterEach -import org.scalatest.funsuite.AnyFunSuite -import org.springframework.beans.factory.support.DefaultListableBeanFactory -import org.springframework.context.support.GenericApplicationContext -import org.springframework.core.StandardReflectionParameterNameDiscoverer - -import java.util as ju -import scala.annotation.nowarn -import scala.beans.BeanProperty - -class TestBean(val constrInt: Int = 1, val constrString: String = "constrDefault") { - @BeanProperty var int: Int = _ - @BeanProperty var string: String = _ - @BeanProperty var strIntMap: ju.Map[String, Int] = _ - @BeanProperty var strList: ju.List[String] = _ - @BeanProperty var strSet: ju.Set[String] = _ - @BeanProperty var nestedBean: TestBean = _ - @BeanProperty var config: Config = _ -} -object TestBean { - def create(theInt: Int = -1, theString: String = "factoryDefault"): TestBean = - new TestBean(theInt, theString) -} - -class ConditionalTestBean(int: Int) { - - import ConditionalTestBean.initializedCount - - initializedCount += 1 -} -object ConditionalTestBean { - var initializedCount = 0 -} - -@nowarn("msg=deprecated") -class HoconBeanDefinitionReaderTest extends AnyFunSuite with BeforeAndAfterEach { - def createContext(resource: String): GenericApplicationContext = { - val beanFactory = new DefaultListableBeanFactory - beanFactory.setParameterNameDiscoverer(new StandardReflectionParameterNameDiscoverer) - - val ctx = new GenericApplicationContext(beanFactory) - ctx.addBeanFactoryPostProcessor(new ScalaDefaultValuesInjector) - - val rdr = new HoconBeanDefinitionReader(ctx) - rdr.loadBeanDefinitions(resource) - ctx.refresh() - - ctx - } - - override def beforeEach(): Unit = { - ConditionalTestBean.initializedCount = 0 - } - - test("hocon bean definition reader should work") { - val ctx = createContext("testBean.conf") - - val testBean = ctx.getBean("testBean", classOf[TestBean]) - assert(42 == testBean.constrInt) - assert("lolzsy" == testBean.constrString) - assert(5 == testBean.int) - assert("lol" == testBean.string) - assert(Map("fuu" -> 42).asJava == testBean.strIntMap) - assert(List("a", "b").asJava == testBean.strList) - assert(Set("A", "B").asJava == testBean.strSet) - assert(6 == testBean.nestedBean.int) - assert(1 == testBean.nestedBean.constrInt) - assert("wut" == testBean.nestedBean.constrString) - assert(2 == testBean.nestedBean.nestedBean.constrInt) - assert("yes" == testBean.nestedBean.nestedBean.constrString) - assert(ConfigFactory.parseString("srsly = dafuq") == testBean.config) - - val testBeanDefInt = ctx.getBean("testBeanDefInt", classOf[TestBean]) - assert(testBeanDefInt.constrInt == 1) - assert(testBeanDefInt.constrString == "constrNonDefault") - - val testBeanDefString = ctx.getBean("testBeanDefString", classOf[TestBean]) - assert(testBeanDefString.constrInt == 2) - assert(testBeanDefString.constrString == "constrDefault") - - val testBeanDefAll = ctx.getBean("testBeanDefAll", classOf[TestBean]) - assert(testBeanDefAll.constrInt == 1) - assert(testBeanDefAll.constrString == "constrDefault") - - val testBeanFMDefInt = ctx.getBean("testBeanFMDefInt", classOf[TestBean]) - assert(testBeanFMDefInt.constrInt == -1) - assert(testBeanFMDefInt.constrString == "factoryNonDefault") - - val testBeanFMDefString = ctx.getBean("testBeanFMDefString", classOf[TestBean]) - assert(testBeanFMDefString.constrInt == -2) - assert(testBeanFMDefString.constrString == "factoryDefault") - - val testBeanFMDefAll = ctx.getBean("testBeanFMDefAll", classOf[TestBean]) - assert(testBeanFMDefAll.constrInt == -1) - assert(testBeanFMDefAll.constrString == "factoryDefault") - } - - test("file should be included with true condition") { - val ctx = createContext("conditionalsEnabled.conf") - val testBean = ctx.getBean("beanFromConditional", classOf[ConditionalTestBean]) - assert(testBean != null) - assertResult(1)(ConditionalTestBean.initializedCount) - } - - test("file should not be included with false condition") { - val ctx = createContext("conditionalsDisabled.conf") - assert(!ctx.containsBean("beanFromConditional")) - assertResult(0)(ConditionalTestBean.initializedCount) - } - - test("hocon bean definition with nested conditionals should work") { - val ctx = createContext("conditionalsNested.conf") - val testBean = ctx.getBean("testBean", classOf[TestBean]) - assert(testBean.int == 2) - } -} diff --git a/spring/src/test/scala/com/avsystem/commons/spring/Playground.scala b/spring/src/test/scala/com/avsystem/commons/spring/Playground.scala deleted file mode 100644 index f6d639fa7..000000000 --- a/spring/src/test/scala/com/avsystem/commons/spring/Playground.scala +++ /dev/null @@ -1,17 +0,0 @@ -package com.avsystem.commons -package spring - -import com.typesafe.config.ConfigFactory - -object Playground { - def main(args: Array[String]): Unit = { - val conf = - """ - |a = {b += 1} - |a = ${a}{b += 2} - """.stripMargin - - println(ConfigFactory.parseString(conf).resolve().root().render()) - } - -} diff --git a/spring/src/test/scala/com/avsystem/commons/spring/XmlPlayground.scala b/spring/src/test/scala/com/avsystem/commons/spring/XmlPlayground.scala deleted file mode 100644 index 2e079bb68..000000000 --- a/spring/src/test/scala/com/avsystem/commons/spring/XmlPlayground.scala +++ /dev/null @@ -1,18 +0,0 @@ -package com.avsystem.commons -package spring - -import com.typesafe.config.ConfigFactory -import org.springframework.context.support.GenericApplicationContext - -import scala.annotation.nowarn - -@nowarn("msg=deprecated") -object XmlPlayground { - def main(args: Array[String]): Unit = { - val ctx = new GenericApplicationContext - val reader = new HoconBeanDefinitionReader(ctx) - reader.loadBeanDefinitions(ConfigFactory.load("bean2").withFallback(ConfigFactory.load("bean1")).resolve()) - - ctx.refresh() - } -}