{"id":15043707,"url":"https://github.com/kh-bd/interp4j","last_synced_at":"2025-04-10T00:42:28.121Z","repository":{"id":37941138,"uuid":"401788607","full_name":"kh-bd/interp4j","owner":"kh-bd","description":"String interpolation library for Java","archived":false,"fork":false,"pushed_at":"2024-05-27T08:26:17.000Z","size":367,"stargazers_count":10,"open_issues_count":5,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-10T00:41:53.544Z","etag":null,"topics":["java","library"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kh-bd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-08-31T17:27:49.000Z","updated_at":"2024-11-13T19:51:49.000Z","dependencies_parsed_at":"2024-05-22T21:25:09.244Z","dependency_job_id":"b0c22413-e708-4e3d-90c0-2e5ef5b3d86e","html_url":"https://github.com/kh-bd/interp4j","commit_stats":null,"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kh-bd%2Finterp4j","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kh-bd%2Finterp4j/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kh-bd%2Finterp4j/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kh-bd%2Finterp4j/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kh-bd","download_url":"https://codeload.github.com/kh-bd/interp4j/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248137998,"owners_count":21053775,"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":["java","library"],"created_at":"2024-09-24T20:49:28.124Z","updated_at":"2025-04-10T00:42:28.097Z","avatar_url":"https://github.com/kh-bd.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Interp4j is a string interpolation library for Java\n\n[![CI latest](https://github.com/kh-bd/interp4j/actions/workflows/main-tests.yml/badge.svg)](https://github.com/kh-bd/interp4j/actions/workflows/main-tests.yml)\n\n## Why do we need it?\n\nTo understand why we need string interpolation and how to use it, consider following example:\nWe have to implement a function, which can build a short person descriptor.\n\nStringBuilder implementation:\n\n```java\nclass Greeter {\n    public String describe(Person person) {\n        StringBuilder builder = new StringBuilder();\n        builder.append(\"Hello! My name is \");\n        builder.append(person.getName());\n        builder.append(\". I'm \");\n        builder.append(person.getAge());\n        return builder.toString();\n    }\n}\n```\n\nA lot of code to implement such simple thing. May be `String.format` can help us.\n\n```java\nclass Greeter {\n    public String describe(Person person) {\n        String template = \"Hello! My name is %s. I'm %d\";\n        return String.format(template, person.getName(), person.getAge());\n    }\n}\n\n```\n\nBetter, but we can do even better. String interpolation can help us to write such code in a nicer and shorter way.\n\n```java\nclass Greeter {\n    public String describe(Person person) {\n        return s(\"Hello! My name is ${person.getName()}. I'm ${person.getAge()}\");\n    }\n}\n```\n\n## How to use it?\n\nFirst, you need to add `interp4j-core` dependency to your project. For example, if you use maven, add the following\nconfiguration to your `pom.xml` file:\n\n```xml\n\n\u003cdependency\u003e\n    \u003cgroupId\u003edev.khbd.interp4j\u003c/groupId\u003e\n    \u003cartifactId\u003einterp4j-core\u003c/artifactId\u003e\n    \u003cscope\u003ecompile\u003c/scope\u003e\n    \u003cversion\u003eLATEST\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nNow, you can use function from `Interpolations` class in your code. These function are entry point to interpolations.\n\nSecond, you need to configure your build tool to run interpolation process before source files compilation.\n\n### `s` interpolator\n\n`s` interpolator is simple. Write down a text and inject any java expression into in `${...}`. If an expression is\na java identifier curly braces can be omitted. For example, `s(\"Hello, ${person.name}\")` or `s(\"Hello, $name\")`.\n\n### `fmt` interpolator\n\n`fmt` interpolator is a replacement for `String.format`. The usage is quite the same as `s` interpolator, but\nbefore each expression valid specifier must be provided. For example, `fmt(\"Hello, %20.4s${person.name}\")`.\nAll features of `String.format` are supported, but there are several syntactic rules:\n\n- before each expression part a valid specifier must be present\n- numeric or implicit indexing are not supported. So `fmt(\"%1$s${person.name}\")` or `fmt(\"%1$s${person.name}, %\u003cd${person.age}\")` are not valid.\n- after specifiers `$$` and `%n` no code is allowed\n\n## Versions\n\nWe are going to support separate version for each LTS release as long as that release is supported.\nIn the following table, you can find the latest interp4j version for each supported java version.\n\n| Java\u003cbr/\u003e version | Latest release                                                                                                                                                                                           |\n|-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `1.8`             | [![Maven jdk1.8](https://img.shields.io/maven-central/v/dev.khbd.interp4j/interp4j?color=brightgreen\u0026versionSuffix=_jre1.8)](https://mvnrepository.com/artifact/dev.khbd.interp4j/interp4j/2.0.0_jre1.8) |\n| `11`              | [![Maven jdk11](https://img.shields.io/maven-central/v/dev.khbd.interp4j/interp4j?color=brightgreen\u0026versionSuffix=_jre11)](https://mvnrepository.com/artifact/dev.khbd.interp4j/interp4j/2.0.0_jre11)    |\n| `17`              | [![Maven jdk17](https://img.shields.io/maven-central/v/dev.khbd.interp4j/interp4j?color=brightgreen\u0026versionSuffix=_jre17)](https://mvnrepository.com/artifact/dev.khbd.interp4j/interp4j/2.0.0_jre17)    |\n| `21`              | [![Maven jdk21](https://img.shields.io/maven-central/v/dev.khbd.interp4j/interp4j?color=brightgreen\u0026versionSuffix=_jre21)](https://mvnrepository.com/artifact/dev.khbd.interp4j/interp4j/2.0.0_jre21)    |\n\n## Maven support\n\nTo interpolate strings in maven-based projects you have to configure compiler to enable interp4j compiler plugin during\ncompilation. Add the following configuration to your `pom.xml` file and that's it.\n\n```xml\n\n\u003cplugin\u003e\n    \u003cgroupId\u003eorg.apache.maven.plugins\u003c/groupId\u003e\n    \u003cartifactId\u003emaven-compiler-plugin\u003c/artifactId\u003e\n    \u003cconfiguration\u003e\n        \u003ccompilerArgs\u003e\n            \u003c!-- enable interp4j compiler plugin --\u003e\n            \u003carg\u003e-Xplugin:interp4j\u003c/arg\u003e\n        \u003c/compilerArgs\u003e\n        \u003cannotationProcessorPaths\u003e\n            \u003cpath\u003e\n                \u003cgroupId\u003edev.khbd.interp4j\u003c/groupId\u003e\n                \u003cartifactId\u003einterp4j-processor\u003c/artifactId\u003e\n                \u003cversion\u003eLATEST\u003c/version\u003e\n            \u003c/path\u003e\n        \u003c/annotationProcessorPaths\u003e\n    \u003c/configuration\u003e\n\u003c/plugin\u003e\n```\n\nCompiler plugin uses internal jdk api to interpolate string literals and\nthis api is [strongly encapsulated by default](https://openjdk.org/jeps/403) in jdk 17.\nTo relax it at compile time configuration should be changed accordingly.\n\n```xml\n\n\u003cplugin\u003e\n    \u003cgroupId\u003eorg.apache.maven.plugins\u003c/groupId\u003e\n    \u003cartifactId\u003emaven-compiler-plugin\u003c/artifactId\u003e\n    \u003cconfiguration\u003e\n        \u003cfork\u003etrue\u003c/fork\u003e\n        \u003ccompilerArgs\u003e\n            \u003c!-- enable interp4j compiler plugin --\u003e\n            \u003carg\u003e-Xplugin:interp4j\u003c/arg\u003e\n            \u003carg\u003e-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED\u003c/arg\u003e\n            \u003carg\u003e-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED\u003c/arg\u003e\n            \u003carg\u003e-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED\u003c/arg\u003e\n            \u003carg\u003e-J--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED\u003c/arg\u003e\n        \u003c/compilerArgs\u003e\n        \u003cannotationProcessorPaths\u003e\n            \u003cpath\u003e\n                \u003cgroupId\u003edev.khbd.interp4j\u003c/groupId\u003e\n                \u003cartifactId\u003einterp4j-processor\u003c/artifactId\u003e\n                \u003cversion\u003eLATEST\u003c/version\u003e\n            \u003c/path\u003e\n        \u003c/annotationProcessorPaths\u003e\n    \u003c/configuration\u003e\n\u003c/plugin\u003e\n```\n\nAdditional exports are needed only for compiling process, resulted code will not be dependent on internal jdk api.\n\n## Gradle support\n\nTo interpolate strings in gradle-based projects you have to configure compiler to enable interp4j compiler plugin during\ncompilation. Add the following configuration to your `build.gradle` file and that's it.\n\n```groovy\ndependencies {\n    compileOnly group: 'dev.khbd.interp4j', name: 'interp4j-core', version: interp4j_version\n    annotationProcessor group: 'dev.khbd.interp4j', name: 'interp4j-processor', version: interp4j_version\n}\n\ntask.withType(JavaCompile) {\n    options.fork = true\n    options.compilerArgs.add('-Xplugin:interp4j')\n}\n```\n\nIf you use jdk 17 or higher additional options are required to allow compiler plugin\nto use internal jdk api.\n\n```groovy\ndependencies {\n    compileOnly group: 'dev.khbd.interp4j', name: 'interp4j-core', version: interp4j_version\n    annotationProcessor group: 'dev.khbd.interp4j', name: 'interp4j-processor', version: interp4j_version\n}\n\ntask.withType(JavaCompile) {\n    options.fork = true\n    options.compilerArgs.add('-Xplugin:interp4j')\n    options.forkOptions.jvmArgs.addAll([\n            '--add-exports', 'jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED',\n            '--add-exports', 'jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED',\n            '--add-exports', 'jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED',\n            '--add-exports', 'jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED'\n    ])\n}\n```\n\nAdditional exports are needed only for compiling process, resulted code will not be dependent on internal jdk api.\n\n## Intellij support\n\nTo support `interp4j` by intellij, install\n[interp4j-intellij-plugin](https://github.com/kh-bd/interp4j-intellij-plugin).\n\n## How to look at modified source code?\n\nTo look at modified source code after interpolation, set flag `prettyPrint.after.interpolation` to `true`. For example,\nfor maven-based projects it can look like that:\n\n```xml\n\n\u003cplugin\u003e\n    \u003cartifactId\u003emaven-compiler-plugin\u003c/artifactId\u003e\n    \u003cconfiguration\u003e\n        \u003ccompilerArgs\u003e\n            \u003carg\u003e-Xplugin:interp4j prettyPrint.after.interpolation=true\u003c/arg\u003e\n        \u003c/compilerArgs\u003e\n        ...\n    \u003c/configuration\u003e\n\u003c/plugin\u003e\n```\n\nBy default, this feature is disabled.\n\n## Benchmarks\n\nAll benchmarks were run on:\n\n- Machine: MacBook Pro 2023\n- Processor: Apple M2 Max\n- Memory: 32 GB LPDDR5\n\nSee latest benchmark\nresult [here](https://jmh.morethan.io/?source=https://raw.githubusercontent.com/kh-bd/interp4j/main/readme/beanchmark/jmh_v1.1.0_j21.json)\n.\n\nAs you can see, compile time interpolation is about 10 times faster then `String.format`\nand at the same time as fast as manual string concatenation. Benchmarks source code can\nbe found in `interp4j-benchmark` module.\n\n### Run benchmarks on your own machine\n\nTo run benchmarks do several steps:\n\n- pull project to your machine\n- run from root directory `mvn package -Pbenchmark`\n- go to `interp4j-benchmark/target` directory. `interp4j-benchmark-${version}-jar-with-dependencies.jar` should be\n  generated\n- run\n  command `java -cp ./interp4j-benchmark-${version}-jar-with-dependencies.jar dev.khbd.interp4j.benchmark.BenchmarkRunner -rf json`\n- `jmh-result.json` report should be generated\n- view it through [jmh visualizer](https://jmh.morethan.io/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkh-bd%2Finterp4j","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkh-bd%2Finterp4j","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkh-bd%2Finterp4j/lists"}