{"id":13428877,"url":"https://github.com/ufoscout/properlty","last_synced_at":"2025-03-18T03:32:30.349Z","repository":{"id":57729279,"uuid":"97034221","full_name":"ufoscout/properlty","owner":"ufoscout","description":"Simple Kotlin and Java configuration library with recursive placeholders resolution and zero magic!","archived":false,"fork":false,"pushed_at":"2019-01-24T16:24:23.000Z","size":140,"stargazers_count":26,"open_issues_count":1,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-28T06:55:10.519Z","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":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ufoscout.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-07-12T17:20:09.000Z","updated_at":"2023-07-05T12:58:41.000Z","dependencies_parsed_at":"2022-09-11T01:12:48.092Z","dependency_job_id":null,"html_url":"https://github.com/ufoscout/properlty","commit_stats":null,"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ufoscout%2Fproperlty","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ufoscout%2Fproperlty/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ufoscout%2Fproperlty/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ufoscout%2Fproperlty/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ufoscout","download_url":"https://codeload.github.com/ufoscout/properlty/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243902180,"owners_count":20366256,"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:07.568Z","updated_at":"2025-03-18T03:32:29.984Z","avatar_url":"https://github.com/ufoscout.png","language":"Java","funding_links":[],"categories":["Libraries"],"sub_categories":[],"readme":"# Properlty - Simple configuration library with placeholders resolution and no magic!\n\nProperlty provides a simple way to configure an application from multiple sources — built in resources, system\nproperties, property files, environment variables, and whatever else you like.\n\nSome features:\n\n- Recursive placeholders resolution\n- Only 30Kb and no external dependencies\n- Java and Kotlin versions\n\n\nGetting Started\n---------------\n\n1. To get started, add Properlty dependency to your project.\n \nFor Kotlin:\n```xml\n    \u003cdependency\u003e\n        \u003cgroupId\u003ecom.ufoscout.properlty\u003c/groupId\u003e\n        \u003cartifactId\u003eproperlty-kotlin\u003c/artifactId\u003e\n        \u003cversion\u003e1.8.1\u003c/version\u003e\n    \u003c/dependency\u003e\n```\n\nFor Java:\n```xml\n    \u003cdependency\u003e\n        \u003cgroupId\u003ecom.ufoscout.properlty\u003c/groupId\u003e\n        \u003cartifactId\u003eproperlty\u003c/artifactId\u003e\n        \u003cversion\u003e1.9.0\u003c/version\u003e\n    \u003c/dependency\u003e\n```\n\n**_WARN: use one OR the other. Do not import both the dependencies!_**\n\n2. Define some properties. You can use placeholders, for example, in `config.properties`:\n\n```properties\n    server.port=9090\n    server.host=127.0.0.1\n    server.url=http://${server.host}:${server.port}/\n```\n    \n3. Build a Properlty object that loads properties:\n\nKotlin:\n```kotlin\n    val properlty = Properlty.builder()\n            .add(\"classpath:config.properties\") // loads from the classpath\n            .build()\n```\n    \nJava:\n```java\n    final Properlty properlty = Properlty.builder()\n            .add(\"classpath:config.properties\")  // loads from the classpath\n            .build();\n```\n\n4. Look up properties by key:\n\nKotlin:\n```kotlin\n    val port: Int = properlty.getInt(\"server.port\", 8080); // returns 9090\n    val serverUrl = properlty[\"server.url\"] // returns http://127.0.0.1:9090/\n    val defaultVal = properlty[\"unknownKey\", \"defaultValue\"] // returns defaultValue\n```\n\nJava:\n```java\n    int port = properlty.getInt(\"server.port\", 8080); // returns 9090\n    \n    // the Java API uses Optional for methods that could not produce a valid result.\n    // In this case the Optional contains the Strind 'http://127.0.0.1:9090/' \n    Optional\u003cString\u003e serverUrl = properlty.get(\"server.url\") \n    String defaultVal = properlty.get(\"unknownKey\", \"defaultValue\") // returns defaultValue\n```\n\n(All examples are in Kotlin from now on; btw, Java code is exactly the same)\n\nReaders\n-------\nIn Properlty a \"reader\" is whatever source of properties. \nBy default, Properlty offers readers to load properties from:\n\n* Java property files in the file system and in the classpath\n* Java system properties\n* Environment variables\n* Programmatically typed properties\n\nCustom properties readers can be created implementing the `com.ufoscout.properlty.reader.Reader` interface. \n\n\nPlaceholders resolution\n-----------------------\nProperlty is able to resolve placeholders recursively. For example:\n\nfileOne.properties:\n```properties\n    server.url=http://${${environment}.server.host}:${server.port}\n    server.port=8080\n```\n\nfileTwo.properties:\n```properties\n    environment=PROD\n    PROD.server.host=10.10.10.10\n    DEV.server.host=127.0.0.1\n```\n\n```kotlin\n    val properlty = Properlty.builder()\n            .add(\"./fileOne.properties\") // loads from the file system\n            .add(\"./fileTwo.properties\") // loads from the file system\n            .build()\n            \n    println(properlty[\"server.url\"]) // this prints 'http://10.10.10.10:8080'\n```\n\nBy default `${` and `}` delimiters are used. Custom delimiters can be easily defined:\n\n```kotlin\n    val properlty = Properlty.builder()\n            .delimiters(\"%(\", \")\") // using %( and ) as delimiters\n            .add( bla bla bla)\n```\n\nDefault Values\n--------------\nPlaceholders can have default values which are used if the key is not otherwise provided. Example:\n\nconfig.properties:\n```properties\n# the default value \"8080\" is used if 'PORT_NUMBER' is not provided\nserver.port=${PORT_NUMBER:8080}\n    \n# default is 127.0.0.1\nserver.ip=${IP:127.0.0.1}\n\nserver.url=${server.ip}/${server.port}\n```\n\nThe default separator for the default value is \":\". A custom value can be set through the 'defaultValueSeparator()' method of Properlty.builder().\n\n\nCase Sensitive settings\n-----------------------\nBy default keys and placeholders are case sensitive.\nThe default behavior can be modified with the caseSensitive() builder method:\n\n```properties\n    server.PORT=9090\n    server.host=127.0.0.1\n    server.url=http://${SerVeR.host}:${SERVER.port}/\n```\n\nKotlin:\n```kotlin\n    val properlty = Properlty.builder()\n            .caseSensitive(false)\n            .add(\"classpath:config.properties\") // loads from the classpath\n            .build()\n    val serverUrl = properlty[\"server.url\"] // returns http://127.0.0.1:9090/\n```\n\nCase insensitive can simplify key overriding through environment variables.\n\n\nReaders priority -\u003e Last one wins\n---------------------------------\nProperties defined in later readers will override properties defined earlier readers, in case of overlapping keys. \nHence, make sure that the most specific readers are the last ones in the given list of locations.\n\nFor example:\n\nfileOne.properties:\n```properties\n    server.url=urlFromOne\n```\n\nfileTwo.properties:\n```properties\n    server.url=urlFromTwo\n```\n\n```kotlin\n    val properlty = Properlty.builder()\n            .add(\"classpath:fileOne.properties\") // loads from the classpath\n            .add(\"file:./fileTwo.properties\") // loads from the file system\n            .add(SystemPropertiesReader()) // loads the Java system properties\n            .build()\n    \n    // this prints 'urlFromTwo'\n    println(properlty[\"server.url\"])\n```\n\nBTW, due to the fact that we used `SystemPropertiesReader()` as last reader, if the \"server.url\" system property is specified at runtime, it will override the other values.\n\nIn addition, it is possible to specify a custom priority:\n\n```kotlin\n    val properlty = Properlty.builder()\n\n            // load the properties from the file system and specify their priority\n            .add(resourcePath = \"file:./fileTwo.properties\", priority = Default.HIGHEST_PRIORITY)\n            \n            .add(\"classpath:fileOne.properties\") // loads from the classpath\n            .add(SystemPropertiesReader()) // loads the Java system properties            \n            .build()\n            \n    // this prints 'urlFromTwo'\n    println(properlty[\"server.url\"]) \n```\n\nThe default priority is 100. The highest priority is 0. \nAs usual, when more readers have the same priority, the last one wins in case of overlapping keys. \n\n\nReal life example\n-----------------\nA typical real life configuration would look like:\n\n```kotlin\n    val properlty = Properlty.builder()\n\n            // case insensitive behavior simplifies matching of environment variables, especially in Linux systems\n            .caseSensitive(false)\n\n            // load a resource from the classpath\n            .add(\"classpath:default.properties\")\n            \n             // load a file from the file system\n            .add(\"file:./config/config.properties\")\n            \n            // Add a not mandatory reader, resource not found exceptions are ignored.\n            // Here I am adding properties present only during testing.\n            .add(resourcePath = \"classpath:test.properties\", ignoreNotFound = true)\n\n             // load the Environment variables and convert their keys\n             // from JAVA_HOME=XXX to JAVA.HOME=XXX\n             // This could be desired to override default properties\n            .add(EnvironmentVariablesReader().replace(\"_\", \".\"))\n            \n             // Load the Java system properties. They override the Environment variables.\n            .add(SystemPropertiesReader())\n            \n            // build the properlty object \n            .build()\n```\n\nProperlty API\n-------------\nProperlty has a straightforward API that hopefully does not need detailed documentation.\n\nSome examples:\n\n```kotlin\n    val properlty = Properlty.builder()\n            .add(\"classpath:test.properties\")\n            .build()\n\n    // get a String. \"defaultValue\" is returned if the key is not found\n    val aString = properlty[\"key\", \"defaultValue\"]\n\n    // get an array from the comma separated tokens of the property value\n    val anArray = properlty.getArray(\"key\", \",\")\n\n    // get an Enum\n    val anEnum = properlty.getEnum\u003cNeedSomebodyToLoveEnum\u003e(\"key\")\n\n    // get a Long\n    val aLong = properlty.getLong(\"key\")\n\n    // get a Long or default value\n    val anotherLong = properlty.getLong(\"key\", 10L)\n    \n    // get a BigDecimal\n    val aBigDecimal = properlty.getBigDecimal(\"key\")\n    \n    // or get a BigDecimal by applying a transformation function to the returned String value\n    val anotherBigDecimal = properlty[\"key\", { BigDecimal(it) }]\n\n    // get a list of BigDecimal. The property value is split in tokens using the default list \n    // separator (a comma) then the transformation function is applied to each token\n    val aListOfBigDecimals = properlty.getList(\"key\") {BigDecimal(it)} \n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fufoscout%2Fproperlty","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fufoscout%2Fproperlty","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fufoscout%2Fproperlty/lists"}