{"id":24111450,"url":"https://github.com/nndi-oss/jdbi-utils","last_synced_at":"2026-05-10T05:40:28.710Z","repository":{"id":41895183,"uuid":"437943218","full_name":"nndi-oss/jdbi-utils","owner":"nndi-oss","description":"Utilities for JDBI 3","archived":false,"fork":false,"pushed_at":"2022-05-12T01:12:19.000Z","size":104,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-01-11T02:34:15.893Z","etag":null,"topics":["database","java","jdbi3","validation"],"latest_commit_sha":null,"homepage":null,"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/nndi-oss.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":"2021-12-13T16:22:22.000Z","updated_at":"2022-05-11T20:07:39.000Z","dependencies_parsed_at":"2022-08-11T20:31:19.904Z","dependency_job_id":null,"html_url":"https://github.com/nndi-oss/jdbi-utils","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nndi-oss%2Fjdbi-utils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nndi-oss%2Fjdbi-utils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nndi-oss%2Fjdbi-utils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nndi-oss%2Fjdbi-utils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nndi-oss","download_url":"https://codeload.github.com/nndi-oss/jdbi-utils/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241113676,"owners_count":19911933,"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":["database","java","jdbi3","validation"],"created_at":"2025-01-11T02:34:20.733Z","updated_at":"2026-05-10T05:40:28.680Z","avatar_url":"https://github.com/nndi-oss.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"Jdbi3 Utilities\n===============\n\nA set of utilities for working with [Jdbi 3](https://github.com/jdbi/jdbi)\n\n## jdbigen\n\nA command-line program to generate DAO classes from database tables complete with CRUD queries\n\n**Usage**\n\nGenerates DAOs as `interface` SqlObjects\n\n`$ jdbigen --package \"com.example\" --exclude schema_version \"postgres://user:password@localhost/database?sslmode=disable\"`\n\nGenerate DAOs as a regular `class` that uses `Jdbi.withHandle` \n\n`$ jdbigen --sqlhandle --package \"com.example\" --exclude schema_version \"postgres://user:password@localhost/database?sslmode=disable\"`\n\nMore information [here](jdbigen/README.md) \n\n## Customizers\n\n### Counter\n\u003cdetails\u003e\n\u003csummary\u003eUse the `CounterCustomizer` to automatically update a \"counter field\" in a table.\u003c/summary\u003e\n\nFor example if you wanted to update a user's post count after inserting a new Post\nyou would do something like this:\n\n```java\nJdbi.open()\n    .createUpdate(\"INSERT INTO posts(content, user_id) VALUES (:content, :user_id)\")\n    .bind(\"content\", \"Yay! Post content!\")\n    .bind(\"user_id\", 1)\n    .addCustomizer(new CounterCustomizer(\"users\", \"posts_count\", \"user_id\", \"id\"))\n    .execute();\n```\n\nThis will increment the `posts_count` column in the users table automatically!\n\n\u003e NOTE: In order to avoid potential SQL injections, you **MUST NOT** use _untrusted_ user input as arguments for the `CounterCustomizer` constructor\n\nYou can even use it with SqlObjects using the `@Counter` annotation :\n\n```java\npublic interface PostDAO {\n    @SqlUpdate(\"INSERT INTO posts(content, user_id) VALUES (:p.content, :p.userId)\")\n    @Counter(table = \"users\", column = \"posts_count\", binding = \"p.userId\")\n    void insert(@BindBean(\"p\") Post post);\n}\n```\n\nYou can also make the counter decrement by setting the `decrementing` argument to `true` in the annotation.\n\u003c/details\u003e\n\n### Capitalize Customizer\n\u003cdetails\u003e\n\u003csummary\u003eUse the `CapitalizeCustomizer` to automatically set bound fields to UPPER CASE!\u003c/summary\u003e\n\nFor example if you wanted to capitalize the content of each Post before saving\nto the database you would do something like this:\n\n```java\nJdbi.open()\n    .createUpdate(\"INSERT INTO posts(content, user_id) VALUES (:content, :user_id)\")\n    .bind(\"content\", \"Yay! Post content!\")\n    .bind(\"user_id\", 1)\n    .addCustomizer(new CapitalizeCustomizer(\"content\"))\n    .execute();\n```\n\u003c/details\u003e\n\n### Base64 Encoder\n\u003cdetails\u003e\n\u003csummary\u003eUse the `Base64Customizer` to automatically encode bound fields to Base64\u003c/summary\u003e\n\nFor example if you wanted to Base64 encode the content of each Post before saving  to the database you would do something like this:\n\n```java\nJdbi.open()\n    .createUpdate(\"INSERT INTO posts(content, user_id) VALUES (:content, :user_id)\")\n    .bind(\"content\", \"Yay! Post content!\")\n    .bind(\"user_id\", 1)\n    .addCustomizer(new Base64Customizer(\"content\"))\n    .execute();\n```\n\u003c/details\u003e\n\n\n### Validation\n\u003cdetails\u003e\n\u003csummary\u003eThe `@Valid` annotation provides validation for your method parameters in SqlObject methods.\nThe validation is done via the Hibernate Validator.\u003c/summary\u003e\n\nThe annotation also supports validation groups.\n\nA Simple example:\n\n```java\n\n// Person.java\npublic class Person {\n    @Min(value=1, groups=PersonUpdate.class)\n    private int id;\n\n    @NotEmpty\n    private String firstName;\n\n    @NotEmpty\n    private String lastName;\n\n    @Min(18)\n    private int age;\n\n    // ... getters and setters ..\n\n    public interface PersonUpdate {}\n}\n\n// Application.java\npublic class Application {\n\n    public static void main(String... args) {\n        PersonDAO dao = dbi.onDemand(PersonDAO.class);\n\n        Person p = new Person();\n\n        // This call will throw an `ValidationException` since there are validation errors\n        dao.insert(p);\n    }\n\n    @RegisterRowMapperFactory(BeanMapperFactory.class)\n    public interface PersonDAO {\n        @SqlUpdate(\"INSERT INTO people(firstName, lastName, age) VALUES (:p.firstName, :p.lastName, :p.age)\")\n        void insert(@BindBean(\"p\") @Valid Person person);\n\n        @SqlUpdate(\"UPDATE people firstName=:p.firstName, lastName=:p.lastName, age=:p.age WHERE id=:p.id\")\n        void update(@BindBean(\"p\") @Valid(groups=Person.PersonUpdate.class) Person person);\n    }\n}\n```\n\n\u003e NOTE: You don't necessarily have to use the `@BindBean` annotation. It should work with any\nbinding annotation - but that's not been tested thoroughly.\n\u003c/details\u003e\n\n## @UseClasspathSqlLocator compile-time checks\n\u003cdetails\u003e\n\u003csummary\u003eThe `useclasspathsql-checker` module implements an Annotation Processor that checks that \nSQL files for methods on your DAOs (SqlObjects in JDBI speak) exist and are not empty.\u003c/summary\u003e \n\nIn particular, it checks for SqlObjects that use the `@UseClasspathSqlLocator`\nfeature. It checks for SQL files for methods annotated with `@SqlQuery` or `@SqlUpdate`.\n\n**Why is this important?**\n\nUsing the annotation processor will protect you from bugs caused by a \nmissing or empty `.sql` file - **at compile time**. \n\nJDBI does throw Exceptions for these problems at runtime but it could be too late at that point, you know.\n\n**Usage**\n\nJust add the following dependency to your project, note the scope is `provided`\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecloud.nndi.oss\u003c/groupId\u003e\n    \u003cartifactId\u003ejdbi3-utils-useclasspathsql-checker\u003c/artifactId\u003e\n    \u003cversion\u003e0.1.0\u003c/version\u003e\n    \u003cscope\u003eprovided\u003c/scope\u003e\n\u003c/dependency\u003e\n```\n\nThis will generate an error like the following if an SQL file cannot be found:\n\n```\n[ERROR] .../jdbi-utils/example/src/main/java/com/github/zikani03/jdbi/ExampleDAO.java:[7,8] ClasspathSqlChecker could not find or load SQL file: ExampleDAO/selectOne.sql\n```\n\u003c/details\u003e\n\n## Installation\n\nCurrently not on any Maven repos. So first of all, clone this repo and run `mvn install` and then add to your project.\nAfter that, you can add the library as a dependency in your project's `pom.xml`\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecloud.nndi.oss\u003c/groupId\u003e\n    \u003cartifactId\u003ejdbi3-utils\u003c/artifactId\u003e\n    \u003cversion\u003e0.1.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nAlternatively, clone the git repository and install to your local maven repo with `mvn clean install`\n\n## Contributing\n\nPull requests are most welcome.\n\n## LICENSE\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnndi-oss%2Fjdbi-utils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnndi-oss%2Fjdbi-utils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnndi-oss%2Fjdbi-utils/lists"}