{"id":13428855,"url":"https://github.com/mariomac/kaconf","last_synced_at":"2025-06-13T17:34:11.837Z","repository":{"id":50496441,"uuid":"73965224","full_name":"mariomac/kaconf","owner":"mariomac","description":"KickAss Configuration. An annotation-based configuration system for Java and Kotlin","archived":false,"fork":false,"pushed_at":"2022-07-29T15:30:15.000Z","size":207,"stargazers_count":60,"open_issues_count":0,"forks_count":5,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-03T06:12:43.035Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mariomac.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-11-16T22:02:45.000Z","updated_at":"2024-08-18T10:28:22.000Z","dependencies_parsed_at":"2022-08-01T00:07:56.445Z","dependency_job_id":null,"html_url":"https://github.com/mariomac/kaconf","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mariomac%2Fkaconf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mariomac%2Fkaconf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mariomac%2Fkaconf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mariomac%2Fkaconf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mariomac","download_url":"https://codeload.github.com/mariomac/kaconf/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250643424,"owners_count":21464172,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T01:01:06.947Z","updated_at":"2025-04-24T14:31:44.182Z","avatar_url":"https://github.com/mariomac.png","language":"Java","funding_links":[],"categories":["Libraries","Projects","项目"],"sub_categories":["Configuration","配置"],"readme":"# KAConf [![Awesome Kotlin Badge](https://kotlin.link/awesome-kotlin.svg)](https://github.com/KotlinBy/awesome-kotlin)\n\n[2016-2022 Mario Macías](http://github.com/mariomac)\n\n_KickAss_ Configuration v0.9.1 is an Annotation-based configuration system\ninspired in the wonderful [Spring Boot](http://spring.io).\n\nIts strong points are:\n\n* Easy to use, integrate and extend\n* Tiny footprint: a single, ~13KB JAR with no third-party dependencies\n* Born from own's necessity, with no over-engineered use cases\n\nMaven Coordinates\n```XML\n\u003cdependency\u003e\n    \u003cgroupId\u003einfo.macias\u003c/groupId\u003e\n    \u003cartifactId\u003ekaconf\u003c/artifactId\u003e\n    \u003cversion\u003e0.9.1\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n[Change log](CHANGELOG.md)\n\n* [About KAConf](#about-kaconf)\n* [Quick demonstration of usage](#quick-demonstration-of-usage)\n* [Building and using a `Configurator` object](#building-and-using-a-configurator-object)\n* [Default Configurator behaviour](#default-configurator-behaviour)\n* [Mixing naming conventions into a property](#mixing-naming-conventions-into-a-property)\n* [Inherited fields](#inherited-fields)\n* [Adding custom Property Sources](#adding-custom-property-sources)\n* [`Static final` fields](#static-final-fields)\n* [Kotlin basic types support](#kotlin-basic-types-support)\n* [Next steps](#next-steps)\n\n\n### Quick demonstration of usage\n\n* The `@Property` annotation allows you to define any field that recevies\n  its value from a configuration source, whatever its visibility is.\n\n```Java\npublic class DbManager {\n    @Property(\"db.username\")\n    private String user;\n\n    @Property(\"db.password\")\n    private String password;\n\n    // ...\n}\n```\n\n* You can define multiple property names, from lower to higher priority:\n\n```java\n@Property({\"db.user\", \"DB_USER\"})\npublic String user;\n\n@Property({\"db.user\", \"DB_PASSWORD\"})\nprotected String password;\n```\n\n* **ONLY IF YOUR JVM VERSION IS 11 OR LOWER**, you can define `final` and `static` fields, with default values.\n  Properties that are both `final static` require to use the `KA.def`\n  or `KA.a[Type]` helper methods.\n  * If you try to set a final field in Java 12 or higher, a `ConfigurationException` will be thrown.\n  \n```Java\nimport static info.macias.kaconf.KA.*;\n\npublic class Constants {\n    @Property(\"timeout\")\n    public static final long TIMEOUT_MS = def(1000); // default=1000\n\n    @Property(\"security.enabled\")\n    public static final boolean SECURITY_ENABLED = aBoolean();\n}\n```\n\n* The `Configurator.configure` method will automatically set the values\n  from its configuration sources. You can build a `Configurator` object\n  with multiple sources and different priorities.\n\n```Java\npublic class SomeController {\n    private DbManager dbm;\n\n    public void start() {\n        Configurator conf = new ConfiguratorBuilder()\n            .addSource(System.getenv()) // most priority\n            .addSource(System.getProperties())\n            .addSource(JavaUtilPropertySource.from(\"app.properties\"))\n            .addSource(JavaUtilPropertySource.from( // least priority\n                getClass().getResourceAsStream(\"defaults.properties\")\n            )).build();\n\n        conf.configure(Constants.class);\n        conf.configure(dbm);\n    }\n}\n```\n    \n* It's easy to hardcode configuration for testing purposes.\n   \n```Java\npublic class TestSuite {\n\n    DbManager dbm = new DbManager();\n\n    public void setUp() {\n\n        Map\u003cString,String\u003e customProperties = new HashMap\u003c\u003e();\n        customProperties.put(\"db.username\",\"admin\");\n        customProperties.put(\"db.password\",\"1234\");\n        customProperties.put(\"security.enabled\", \"false\");\n\n        Configurator conf = new ConfiguratorBuilder()\n            .addSource(customProperties)\n            .addSource(new JavaUtilPropertySource(\n                getClass().getResourceAsStream(\"defaults.properties\")\n            )).build():\n\n        conf.configure(Constants.class);                    \n        conf.configure(dbm);\n    }\n}     \n```\n\n## Building and using a `Configurator` object\n\nThe `ConfiguratorBuilder` class allows building a `Configurator` object.\nThe `ConfiguratorBuilder.addSource` method sets the different sources of\nproperties (`PropertySource` interface). The `PropertySource` with most\npriority is the first instance passed as argument to the `addSource`\nmethod, and the `PropertySource` with least preference is the object passed\nto the last `addSource` invocation.\n\nExample of usage:\n\n```Java\nConfigurator conf = new ConfiguratorBuilder()\n    .addSource(System.getenv()) // most priority\n    .addSource(System.getProperties())\n    .addSource(JavaUtilPropertySource.from(\"app.properties\"))\n    .addSource(JavaUtilPropertySource.from( // least priority\n        getClass().getResourceAsStream(\"defaults.properties\")\n    )).build():\n```\n\nThe `addSource` method accepts the next types as argument:\n\n* `java.util.Map\u003cString,?\u003e`\n* `java.util.Properties`\n* Any implementing class of the `PropertySource` interface. KAConf bundles\n  two helper implementations:\n    - `JavaUtilPropertySource`\n    - `MapPropertySource` \n    \nOnce a `Configurator` object is built, you can pass the configurable object\n(if object/class properties must be set) or class (if only static fields are\nwilling to be set).\n\n```Java\nconf.configure(object);\nconf.configure(Constants.class);\n```\n\n## Default Configurator behaviour\n\nGiven the next example properties:\n\n        some.value=1234\n        some.other.value=yes\n\n* *Numbers*: any property that parses into a number is valid. If not,\n  the `Configurator.configure` will throw a `ConfiguratorException`:\n   \n```Java\n@Property(\"some.value\")\nprivate int someValue;       // correct\n\n@Property(\"some.other.value\")\nprivate int someOtherValue;  // throws ConfiguratorException\n```\n\n  If the property to look is not on the properties sources, the value\n  will remain as 0, or as the default one.\n  \n```Java\n@Property(\"value.not.found\")\nprivate int value1;           // will be 0\n\n@Property(\"value.not.found\")\nprivate int value2 = def(1000); // will be 1000 (default)\n\n//default valid for non-final \u0026 static primitive fields\n@Property(\"value.not.found\")\nprivate int value3 = 1000;    // will be 1000 (default)\n```\n\n* *Strings*: any property is valid. If the property is not found, the\n  value will be `null` or the default one.\n  \n```Java\n@Property(\"some.value\")\nprivate String someValue;        // value -\u003e \"1234\"\n\n@Property(\"some.other.value\")\nprivate String someOtherValue;   // value -\u003e \"yes\"\n\n@Property(\"value.not.found\")\nprivate String value1;           // value -\u003e null\n\n@Property(\"value.not.found\")\nprivate String value2 = def(\"\"); // value -\u003e empty, non-null String\n\n//default valid for non-final \u0026 static primitive fields\n@Property(\"value.not.found\")\nprivate String value3 = \"\";      // value -\u003e empty, non-null String\n```\n\n* *Booleans*: any property whose string value exists and is `true`, `1`\n  or `yes` will be set as `true`. Otherwise will be `false`.\n\n```Java\n@Property(\"some.value\")\nprivate boolean someValue;       // value -\u003e false\n\n@Property(\"some.other.value\")\nprivate boolean someOtherValue;  // value -\u003e true\n\n@Property(\"value.not.found\")\nprivate boolean value1;          // value -\u003e null\n```\n\n* *Chars*: the value of the property will be the first character of a string.\n  Any non-found property will set the value to '\\0' or the default one.\n        \n* *Boxed primitive types*: boxed primitive types will behave as their\n  unboxed equivalents, but properties that are not found will get the\n  `null` default value.\n  \n```Java\n@Property(\"some.value\")\nprivate Integer intValue;     // value --\u003e 1234\n\n@Property(\"not.found.value\")\nprivate Integer nullableInt;  // value --\u003e null\n```\n\n## Mixing naming conventions into a property\n\nWhen you use multiple configuration sources (e.g. environment variables and Java properties),\ndifferent naming conventions may apply for the same property.\n\nYou can set multiple names for each property, and KAConf will indistinctly use both (in\nthe same priority as the order in the property array).\n\n```java\npublic class Animal {\n    @Property({\"ANIMAL_NAME\", \"animal.name\"})\n    private final String name;\n}\n```\n\n## Inherited fields\n\nKAConf allows setting properties that are annotated in the superclass of the\nconfigurable object or class. For example:\n\n```Java\npublic class Animal {\n    @Property(\"animal.name\")\n    private final String name;\n}\npublic class Dog extends Animal {\n    @Property(\"animal.species\")\n    private final String species;\n}\n\npublic class PetShop {\n    Configurator conf = ...\n    public Animal buy() {\n        Dog puppy = new Dog();\n        conf.configure(puppy);\n        return puppy;\n    }\n}\n```\n\n## Adding custom Property Sources\n\nAdding new Property Sources is simple. Usually is enough to extending the\n`AbstractPropertySource` class and implementing only two abstract methods:\n\n    protected String get(String name);\n    \nWhich returns the string value of the property named according to the `name`\nargument.\n\n    boolean isAvailable();\n\nWhich returns `true` if the properties have been successfully read from the\nsource (e.g. a file or DB).\n\n### PropertySources failing to load\n\nAny implementation of `PropertySource` is expected to fail silently (e.g. if\nit tries to read the values from a file that is not accessible), and then\nreturn `false` in the `isAvailable` method.\n\n## `Static final` fields\n\n**NOTE**: this functonality won't work if you run Kaconf in a JVM version higher than 11. It will\nthrow a `ConfigurationException`. \n\nBecause of the way the Java compiler inlines the `static final` fields of\nprimitive types, it is\nnecessary to assign the result of any method call to the declaration of the\nfield. The `KA` class provides some simple functions to allow that. For example:\n\n```Java\n@Property(\"some.property\")\npublic static final int SOME_PROPERTY = KA.def(1234) // default value\n\n@Property(\"other.property\")\nprotected static final byte OTHER_PROPERTY = KA.aByte(); //defaults to 0\n```\n\n## Kotlin basic types support\n\nAs my favourite programming language, [Kotlin](https://kotlinlang.org/) is a first-class citizen in KAConf, and\nit is fully supported out of the box.\n\n```Kotlin\nclass KonfigurableClass {\n    @Property(\"publicint\")\n    var publicint = KA.def(321)\n\n    @Property(\"someChar\")\n    var someChar = KA.def('a')\n\n    companion object {\n        @Property(\"finalstaticint\")\n        val finalstaticint: Int = 0\n    }\n}\n\nobject KonfigurableObject {\n    @Property(\"aboolean\")\n    var aboolean = KA.aBoolean()\n\n    @Property(\"anint\")\n    var anint: Int? = null\n}\n```\n\nOther JVM languages (Scala, Groovy, Ceylon...) have not been tested. ¿Maybe you\ncan test them for me and tell us the results? :wink:\n\n## Next steps\n\nThere are still some potential improvements of interest in KAConf.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmariomac%2Fkaconf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmariomac%2Fkaconf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmariomac%2Fkaconf/lists"}