{"id":16620293,"url":"https://github.com/chrisgleissner/jutil","last_synced_at":"2025-10-29T21:31:22.974Z","repository":{"id":45108707,"uuid":"144812725","full_name":"chrisgleissner/jutil","owner":"chrisgleissner","description":"Java Utilities","archived":false,"fork":false,"pushed_at":"2023-06-14T22:29:17.000Z","size":7657,"stargazers_count":2,"open_issues_count":2,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-02T04:51:24.756Z","etag":null,"topics":["csv","java","jdbc","log","partitioning","pretty-print","protobuf","sql","table","utility"],"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/chrisgleissner.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":"2018-08-15T06:09:12.000Z","updated_at":"2021-04-29T10:57:37.000Z","dependencies_parsed_at":"2022-09-02T12:31:50.606Z","dependency_job_id":null,"html_url":"https://github.com/chrisgleissner/jutil","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisgleissner%2Fjutil","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisgleissner%2Fjutil/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisgleissner%2Fjutil/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisgleissner%2Fjutil/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chrisgleissner","download_url":"https://codeload.github.com/chrisgleissner/jutil/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238899898,"owners_count":19549397,"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":["csv","java","jdbc","log","partitioning","pretty-print","protobuf","sql","table","utility"],"created_at":"2024-10-12T02:43:55.533Z","updated_at":"2025-10-29T21:31:22.278Z","avatar_url":"https://github.com/chrisgleissner.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# jutil\n\n[![Maven Central](https://img.shields.io/maven-central/v/com.github.chrisgleissner/jutil-protobuf)](https://search.maven.org/artifact/com.github.chrisgleissner/jutil-protobuf/)\n[![Build Status](https://travis-ci.org/chrisgleissner/jutil.svg?branch=master)](https://travis-ci.org/chrisgleissner/jutil)\n[![Coverage Status](https://coveralls.io/repos/github/chrisgleissner/jutil/badge.svg?branch=master)](https://coveralls.io/github/chrisgleissner/jutil?branch=master)\n[![Maintainability](https://api.codeclimate.com/v1/badges/04051d34bbf92198458e/maintainability)](https://codeclimate.com/github/chrisgleissner/jutil/maintainability)\n\nJava utilities for Protobuf message partitioning, table pretty printing and SQL execution recording.\n\nFeatures:\n* Partitioning of Protobuf messages to remain below a configurable data size.\n* JDBI column name remapping\n* Pretty-printing of tables with many customization options and adapters for both CSV frameworks and DB ResultSets.\n* Record all SQL executions sent via the DataSources in your Spring Boot application, either in memory or to disk.\n\n## Installation\n\nThe utilities are packaged in several modules and require at least JDK 8. They are automatically built and tested \nusing OpenJDK 8 and 11.\n\nTo use them, simply declare a dependency towards the module you are interested in:\n\n### Maven\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.github.chrisgleissner\u003c/groupId\u003e\n    \u003cartifactId\u003ejutil-protobuf\u003c/artifactId\u003e\n    \u003cversion\u003e1.1.11\u003c/version\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.github.chrisgleissner\u003c/groupId\u003e\n    \u003cartifactId\u003ejutil-sql-log\u003c/artifactId\u003e\n    \u003cversion\u003e1.1.11\u003c/version\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.github.chrisgleissner\u003c/groupId\u003e\n    \u003cartifactId\u003ejutil-table\u003c/artifactId\u003e\n    \u003cversion\u003e1.1.11\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n### Gradle\n\n```\ncompile 'com.github.chrisgleissner:jutil-protobuf:1.1.11'\ncompile 'com.github.chrisgleissner:jutil-sql-log:1.1.11'\ncompile 'com.github.chrisgleissner:jutil-table:1.1.11'\n```\n\n## Protobuf Utilities\n\n[![Javadocs](https://www.javadoc.io/badge/com.github.chrisgleissner/jutil-protobuf.svg)](https://www.javadoc.io/doc/com.github.chrisgleissner/jutil-protobuf)\n\nThe [ProtobufFieldPartitioner](https://github.com/chrisgleissner/jutil/blob/master/protobuf/src/main/java/com/github/chrisgleissner/jutil/protobuf/ProtobufFieldPartitioner.java) \nis useful for distributing the elements of a repeated field in a Protobuf message over multiple newly created messages. \n\nThis allows for sending a Protobuf message where size restrictions exist, for example when using the\n\u003ca href=\"https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-quotas\"\u003eAzure Message ServiceBus\u003c/a\u003e.\n\nExample:\n```java\nCollection\u003cMessage\u003e msgs = ProtobufFieldPartitioner.partition(msg, repeatedFieldToBePartitioned, 100);\n```\n\n## Sql Log\n\n[![Javadocs](https://www.javadoc.io/badge/com.github.chrisgleissner/jutil-sql-log.svg)](https://www.javadoc.io/doc/com.github.chrisgleissner/jutil-sql-log)\n\nThe [SqlLog](https://github.com/chrisgleissner/jutil/blob/master/sql-log/src/main/java/com/github/chrisgleissner/jutil/sqllog/SqlLog.java) \nrecords JSON-formatted SQL executions either in memory or to a file. It gets wired by using Spring Boot 2.3.x auto-configuration and relies on [net.ttddyy:datasource-proxy](https://github.com/ttddyy/datasource-proxy) for proxying data sources. \n\nTo use this feature, declare a dependency on `com.github.chrisgleissner:jutil-sql-log`.\n\n### Start and Stop\nTo start recording, wire in the `SqlLog` bean and call `startRecording` which returns a `SqlRecording`.\nYou will now record all SQL messages sent via any DataSource bean as part of your current thread or any thread which it starts. \n\nThe recording is kept either on heap (accessible via `sqlRecording.getMessages` and various methods in `SqlLog`) or written to the specified file. \nAll SQL is JSON encoded. \n\nCall `sqlLog.stopRecording(id)` or close a `SqlRecording` instance to stop its recording. \n\n### Default Recording\n\nAny SQL message not recorded otherwise is captured by a default recording which you can get via \n`sqlLog.getDefaultRecording()`.\n\nThis default recording can't be stopped,\nbut you can temporarily stop all recording (including for the default recording) by calling `sqlLog.setEnabled(false)`.\n\n### Example \n\nAs per [ExampleTest](https://github.com/chrisgleissner/jutil/blob/master/sql-log/src/test/java/com/github/chrisgleissner/jutil/sqllog/ExampleTest.java),\nafter wiring \n\n```java\n@Configuration\npublic class SampleConfig {\n    SampleConfig(JdbcTemplate jdbcTemplate, SqlLog sqlLog) {\n        try (SqlRecording rec = sqlLog.startRecording(\"example\", new File(\"sql.json\"), Charset.forName(\"UTF-8\"))) {\n            jdbcTemplate.execute(\"create table foo (id int)\");\n            jdbcTemplate.execute(\"insert into foo (id) values (1)\");\n        }\n    }\n}\n```\n\nyou will find that the `sql.json` file contains\n\n```json\n[{\"success\":true, \"type\":\"Statement\", \"batch\":false, \"querySize\":1, \"batchSize\":0, \"query\":[\"create table foo (id int)\"], \"params\":[]},\n{\"success\":true, \"type\":\"Statement\", \"batch\":false, \"querySize\":1, \"batchSize\":0, \"query\":[\"insert into foo (id) values (1)\"], \"params\":[]}]\n\n```\n\n## JDBI Column Name Mapping\n\nThe [JDBI Column Mapper](https://jdbi.org/#_column_mappers) allows for easy mapping of a `ResultSet` into Java objects. \nThe `jdbi` utility package in this repository provides a wrapper for remapping the column names exposed by a JDBC `ResultSet` and\ncan thus decorate any `ColumnMapper` implementation. \n\nThis is useful if the DB schema uses a different language or terminology than the Java model to which it is mapped and\nit is an alternative to applying this mapping via SQL query column labels.\n\nExample:\n\n```java\njdbiHandle.registerRowMapper(RenamingRowMapperFactory.mapColNames(\n        ConstructorMapper.factory(Person.class),\n        new CsvColumnNameMapping(Path.of(\"columnNameMappings.csv\"))));\nList\u003cPerson\u003e personList = jdbiHandle.createQuery(\"select id, nachname, geburtstag from person\")\n        .mapTo(Person.class)\n        .collect(Collectors.toList());\n```\n\n## Table Printer\n\n[![Javadocs](https://www.javadoc.io/badge/com.github.chrisgleissner/jutil-table.svg)](https://www.javadoc.io/doc/com.github.chrisgleissner/jutil-table)\n\nThe [TablePrinter](https://github.com/chrisgleissner/jutil/blob/master/table/src/main/java/com/github/chrisgleissner/jutil/table/TablePrinter.java) \nserializes a table to a pretty-printed string, either using ASCII or UTF borders.\n\nA table consists of a header and a random number of rows. These can can be specified as an `Iterable\u003cString\u003e` header \nand `Iterable\u003cIterable\u003cString\u003e\u003e` rows. Adapters to various 3rd party frameworks are available, see below. \n\nExample:\n```java\nIterable\u003cString\u003e headers = Arrays.asList(\"firstName\", \"lastName\");\nIterable\u003cIterable\u003cString\u003e\u003e rows = Arrays.asList(Arrays.asList(\"john\", \"doe\"), Arrays.asList(\"joe\", \"doe\"));\nSystem.out.println(DefaultTablePrinter.print(headers, rows));\n```\nresults in:\n```\n+===========+==========+\n| firstName | lastName |\n|===========|==========|\n| john      | doe      |\n| joe       | doe      |\n+===========+==========+\n```\n\nAlternatively, you can also print to an `OutputStream`.\n\n### Configuration\n\nThe TablePrinter is fully configurable to customize your output:\n\n```java\nIterable\u003cString\u003e headers = Arrays.asList(\"firstName\", \"lastName\");\nIterable\u003cIterable\u003cString\u003e\u003e rows = Arrays.asList(\n        Arrays.asList(\"Tom\", \"Selleck\"), \n        Arrays.asList(\"John\", \"Hillerman\"),\n        Arrays.asList(\"Roger E.\", null), \n        Arrays.asList(\"Larry\", \"Manetti\"));\n\nSystem.out.println(TablePrinter.builder()\n        .horizontalDividers(true)\n        .nullValue(\"n/a\")\n        .tableFormat(new Utf8TableFormat())\n        .rowNumbers(true)\n        .startRow(1)\n        .endRow(3)\n        .maxCellWidth(5)\n        .wraparound(false)\n        .build().print(headers, rows));\n```\nresults in:\n```\n╔═══╤═══════╤═══════╗\n║ # │ first │ lastN ║\n╠═══╪═══════╪═══════╣\n║ 1 │ John  │ Hille ║\n╟───┼───────┼───────╢\n║ 2 │ Roger │ n/a   ║\n╟───┼───────┼───────╢\n║ 3 │ Larry │ Manet ║\n╚═══╧═══════╧═══════╝\n```\n\nAs per the example above, if you have a very large data structure, you may want to use the `startRow` and `endRow` builder methods \nto only print the specified range. You can also set the maximum cell width (defaults to 100) and control the wrap-aroud of long cells (enabled by default).\n\nNewlines are supported and tabs are rendered as 8 spaces (configurable).\n\n### 3rd Party Adapters\n\nAny data structure that implements the [TableProvider](https://github.com/chrisgleissner/jutil/blob/master/table/src/main/java/com/github/chrisgleissner/jutil/table/provider/TableProvider.java) interface\ncan be printed and various adapters for this interface are available:\n\n\u003ca href=\"https://docs.oracle.com/javase/8/docs/api/java/sql/ResultSet.html\"\u003eDB ResultSet\u003c/a\u003e\n```java\nClass.forName(\"org.h2.Driver\");\nConnection conn = DriverManager.getConnection(\"jdbc:h2:mem:test\", \"sa\", \"\");\nString s = DefaultTablePrinter.print(\n        new ResultSetTableProvider(conn.createStatement().executeQuery(\"select * from foo\"))));\n```\n\n\u003ca href=\"https://www.univocity.com/pages/about-parsers\"\u003eUnivocity CSV Parser\u003c/a\u003e \n```java\nCsvParserSettings settings = new CsvParserSettings();\nsettings.setHeaderExtractionEnabled(true);\nCsvParser parser = new CsvParser(settings);\nString s = DefaultTablePrinter.print(\n        UnivocityTableProvider.of(parser.iterateRecords(new File(\"sample.csv\"))));\n```\n\n\u003ca href=\"https://commons.apache.org/proper/commons-csv/\"\u003eApache Commons CSV Parser\u003c/a\u003e\n```java\nString s = DefaultTablePrinter.print(\n    new ApacheCsvTableProvider(CSVFormat.DEFAULT.withFirstRecordAsHeader().parse(\n        new FileReader(new File(\"sample.csv\")))))\n                \n```\n\nJavaBeans\n```java\nIterable\u003cPerson\u003e people = Arrays.asList(new Person(\"john\", \"doe\", 30),\n        new Person(\"mary\", \"poppins\", 40));\nString s = DefaultTablePrinter.print(new BeanTableProvider(people))             \n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchrisgleissner%2Fjutil","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchrisgleissner%2Fjutil","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchrisgleissner%2Fjutil/lists"}