{"id":16408696,"url":"https://github.com/mjfryc/mjaron-etudes-java","last_synced_at":"2025-09-01T05:33:52.527Z","repository":{"id":65509035,"uuid":"389948904","full_name":"mjfryc/mjaron-etudes-java","owner":"mjfryc","description":"Library for printing Java objects as a Markdown, CSV, HTML or custom-formatted table, minor utilities.","archived":false,"fork":false,"pushed_at":"2023-10-15T16:48:11.000Z","size":874,"stargazers_count":5,"open_issues_count":5,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-04T13:21:53.033Z","etag":null,"topics":["android-library","array","html-table-generator","jar","java","java-8","java-library","javalibrary","library","library-java","markdown","markdown-converter","object","pair","reflection","table","tables","timer","utils"],"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/mjfryc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-07-27T11:00:28.000Z","updated_at":"2024-07-28T13:09:02.000Z","dependencies_parsed_at":"2024-10-28T15:27:20.244Z","dependency_job_id":"d555fe82-a9b4-4d63-b116-e750b8e049b2","html_url":"https://github.com/mjfryc/mjaron-etudes-java","commit_stats":null,"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"purl":"pkg:github/mjfryc/mjaron-etudes-java","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mjfryc%2Fmjaron-etudes-java","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mjfryc%2Fmjaron-etudes-java/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mjfryc%2Fmjaron-etudes-java/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mjfryc%2Fmjaron-etudes-java/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mjfryc","download_url":"https://codeload.github.com/mjfryc/mjaron-etudes-java/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mjfryc%2Fmjaron-etudes-java/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273077227,"owners_count":25041358,"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","status":"online","status_checked_at":"2025-09-01T02:00:09.058Z","response_time":120,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["android-library","array","html-table-generator","jar","java","java-8","java-library","javalibrary","library","library-java","markdown","markdown-converter","object","pair","reflection","table","tables","timer","utils"],"created_at":"2024-10-11T06:17:33.926Z","updated_at":"2025-09-01T05:33:52.504Z","avatar_url":"https://github.com/mjfryc.png","language":"Java","readme":"# mjaron-etudes-java\n\nStandalone library for printing Java object lists (arrays, iterables) as a Markdown, CSV or HTML formatted table.  \nUtils compatible with Java 1.8.\n\n[![Maven Central](https://img.shields.io/maven-central/v/io.github.mjfryc/mjaron-etudes-java?color=dark-green\u0026style=flat)](https://search.maven.org/artifact/io.github.mjfryc/mjaron-etudes-java/)\n[![Java CI with Gradle](https://github.com/mjfryc/mjaron-etudes-java/actions/workflows/gradle.yml/badge.svg)](https://github.com/mjfryc/mjaron-etudes-java/actions/workflows/gradle.yml)\n[![Publish package to GitHub Packages](https://github.com/mjfryc/mjaron-etudes-java/actions/workflows/gradle-publish.yml/badge.svg)](https://github.com/mjfryc/mjaron-etudes-java/actions/workflows/gradle-publish.yml)\n[![Run on Repl.it](https://img.shields.io/badge/replit-Try%20online-orange)](https://replit.com/@mjfryc/Test-of-mjaron-etudes-java030?v=1)\n\n![Etudes](other/Etudes.png)\n\n## Table generation utils\n\n### Short example\n\n```gradle\nimplementation 'io.github.mjfryc:mjaron-etudes-java:0.3.0'\n```\n\n```\nTable.render(persons, Person.class).run();\n```\n\n| name  | surname  | birthday                      | address | contact                     |\n|-------|----------|-------------------------------|---------|-----------------------------|\n| Sally | Fox      | Mon Mar 25 00:00:00 CET 3872  | London  | sally@sallymfox.com         |\n| Jay   | Elephant | Mon Mar 20 00:00:00 CET 3820  | Paris   | jay.elephant@protonmail.com |\n| Bella | Tran     | Sun Apr 12 00:00:00 CEST 3863 | China   | tran@bella.com              |\n\n### Verbose example\n\nLet's assume following Person class:\n\n```java\npackage pl.mjaron.etudes.sample;\n\nimport java.util.Date;\n\n@SuppressWarnings(\"unused\")\npublic class Person {\n    private final String name;\n    private final String surname;\n    private final Date birthday;\n    private final String address;\n    private final String contact;\n\n    public Person(String name, String surname, Date birthday, String address, String contact) {\n        this.name = name;\n        this.surname = surname;\n        this.birthday = birthday;\n        this.address = address;\n        this.contact = contact;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public String getSurname() {\n        return surname;\n    }\n\n    public Date getBirthday() {\n        return birthday;\n    }\n\n    public String getAddress() {\n        return address;\n    }\n\n    public String getContact() {\n        return contact;\n    }\n\n    public static Person[] getSampleData() {\n        return new Person[]{\n                new Person(\"Sally\", \"Fox\", new Date(1972, 2, 25), \"London\", \"sally@sallymfox.com\"),\n                new Person(\"Jay\", \"Elephant\", new Date(1920, 2, 20), \"Paris\", \"jay.elephant@protonmail.com\"),\n                new Person(\"Bella\", \"Tran\", new Date(1963, 3, 12), \"China\", \"tran@bella.com\")\n        };\n    }\n}\n\n```\n\nThen following code will render the table:\n\n```java\npackage pl.mjaron.etudes.sample;\n\nimport pl.mjaron.etudes.Table;\nimport pl.mjaron.etudes.table.VerticalAlign;\n\npublic class PersonVerboseSample {\n    public static void run() {\n        // Verbose options demo\n        Table.render(Person.getSampleData(), Person.class)\n\n                // By default, the Markdown table format without escaper is used.\n                // Calling .markdown() causes using Markdown renderer and Markdown escaper.\n                .markdown() // Use Markdown renderer and escaper.\n                // or\n                // .csv() // Use CSV renderer and CSV escaper.\n                // or\n                // .html() // Use HTML renderer and HTML escaper.\n\n                // Skip escaping the special characters.\n                .withEscaper(null)\n\n                // Optionally force align / do not align column widths.\n                .withAlignedColumnWidths()\n                // or\n                //.withoutAlignedColumnWidths()\n                // or\n                //.withEqualColumnWidths()\n\n                // Optionally use the custom cell delimiter.\n                // ',' is the default cell delimiter.\n                .withCellDelimiter(',')\n\n                // How the lines will be separated.\n                .withLineBreakCRLF()\n                // or '\\n'\n                // .withLineBreakLF()\n                // or '\\r'\n                // .withLineBreakCR()\n\n                // How align the text (Left, Right or Center)\n                .withAlign(VerticalAlign.Left)\n                // or\n                // .withAlign(VerticalAlign.Right)\n                // or\n                // .withAlign(VerticalAlign.Center)\n                // or\n                // .withAlign(null) // Use the default align.\n\n                // Where to save the table.\n                .toFile(\"build/sample.csv\")\n                // By default, the System.out is used, which can be specified as:\n                // .to(System.out)\n                // or: .to(Stream|PrintStream|Appendable|File|StringBuilder out)\n\n                // Run the render operation.\n                .run()\n        // or\n        // .runToString() // to create the String with whole table.\n        ;\n    }\n}\n\n```\n\n### Markdown customization\n\nFollowing example shows the Markdown customization options.\n\n```java\npackage pl.mjaron.etudes.sample;\n\nimport pl.mjaron.etudes.Table;\nimport pl.mjaron.etudes.table.VerticalAlign;\n\nimport static pl.mjaron.etudes.table.RenderContext.col;\n\npublic class MarkdownCustomizationSample {\n    public static void customizeAlignment() {\n        Table.render(Person.getSampleData(), Person.class).markdown().withAlign(VerticalAlign.Right).withAlign(1, VerticalAlign.Left).run();\n    }\n\n    public static void customizeColumnsOrder() {\n        Table.render(Person.getSampleData(), Person.class).markdown().withColumns(\n                // @formatter:off Preferences \u003e Editor \u003e Code Style \u003e Formatter Control\n                 col(\"contact\", \"CONTACT\")\n                .col(\"address\")\n                .col(\"surname\").as(\"SURNAME\")\n                // @formatter:on\n        ).run();\n    }\n}\n\n```\n\n#### Column alignment\n\nThere is possibility to set the all columns alignment and particular columns alignment. Column indexes are counted from 0.\n\n|  name | surname  |                      birthday | address |                             contact |\n|------:|:---------|------------------------------:|--------:|------------------------------------:|\n| Sally | Fox      |  Mon Mar 25 00:00:00 CET 3872 |  London |             sally@sallymfox\u0026#46;com |\n|   Jay | Elephant |  Mon Mar 20 00:00:00 CET 3820 |   Paris | jay\u0026#46;elephant@protonmail\u0026#46;com |\n| Bella | Tran     | Sun Apr 12 00:00:00 CEST 3863 |   China |                  tran@bella\u0026#46;com |\n\n#### Column names and order\n\nThere is possibility to filter the columns, customize column names and order.\n\n| CONTACT                             | address | SURNAME  |\n|-------------------------------------|---------|----------|\n| sally@sallymfox\u0026#46;com             | London  | Fox      |\n| jay\u0026#46;elephant@protonmail\u0026#46;com | Paris   | Elephant |\n| tran@bella\u0026#46;com                  | China   | Tran     |\n\n### CSV customization\n\nBelow sample CSV snippet. Custom value separator may be set. Columns may be aligned but it is not recommended when importing by spreadsheet programs.\n\n```java\npackage pl.mjaron.etudes.sample;\n\nimport pl.mjaron.etudes.Table;\n\nimport static pl.mjaron.etudes.table.RenderContext.col;\n\npublic class CsvCustomizationSample {\n    public static void run() {\n        Table.render(Person.getSampleData(), Person.class).csv()\n                .withCellDelimiter(\" , \")    // Allows changing the cell separator; ',' is by default.\n\n                // Column alignment used here only to make it more human-readable.\n                // Column alignment is not recommended for CSV due to importing it later by spreadsheet applications.\n                // Additional spaces for alignment may break the cell content.\n                // E.g. Use \"Trim spaces\" option when importing with LibreOffice Calc.\n                .withAlignedColumnWidths()\n\n                // Let's select the rendered columns.\n                .withColumns(\n                // @formatter:off Preferences \u003e Editor \u003e Code Style \u003e Formatter Control\n                col(\"contact\", \"CONTACT\")\n                        .col(\"address\")\n                        .col(\"surname\").as(\"SURNAME\")\n                // @formatter:on\n        ).run();\n    }\n}\n\n```\n\n```csv\nCONTACT                     , address , SURNAME \nsally@sallymfox.com         , London  , Fox     \njay.elephant@protonmail.com , Paris   , Elephant\ntran@bella.com              , China   , Tran    \n\n```\n\n### HTML customization\n\nBasic HTML table may be rendered. When the align is specified, it is written as inline style attribute.\n\nThere is possibility to set the table id and class HTML attributes, so it can be customized with CSS.\n\n```java\npackage pl.mjaron.etudes.sample;\n\nimport pl.mjaron.etudes.Table;\nimport pl.mjaron.etudes.table.VerticalAlign;\n\nimport static pl.mjaron.etudes.table.Html.tableId;\nimport static pl.mjaron.etudes.table.RenderContext.col;\n\npublic class HtmlCustomizationSample {\n    public static void run() {\n        // @formatter:off Preferences \u003e Editor \u003e Code Style \u003e Formatter Control\n        Table.render(Person.getSampleData(), Person.class)\n                .html(tableId(\"my-table-id\").tableClass(\"my-table-class\"))\n                .withAlign(VerticalAlign.Center)\n                .withAlign(1, VerticalAlign.Right)\n\n                // Let's select the rendered columns.\n                .withColumns(\n                        col(\"contact\", \"CONTACT\")\n                        .col(\"address\")\n                        .col(\"surname\").as(\"SURNAME\")\n        ).run();\n        // @formatter:on\n    }\n}\n\n```\n\n```html\n\u003ctable id=\"my-table-id\" class=\"my-table-class\"\u003e\n    \u003ctr\u003e\n        \u003cth style=\"text-align: center;\"\u003eCONTACT\u003c/th\u003e\n        \u003cth style=\"text-align: right;\"\u003eaddress\u003c/th\u003e\n        \u003cth style=\"text-align: center;\"\u003eSURNAME\u003c/th\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd style=\"text-align: center;\"\u003esally@sallymfox.com\u003c/td\u003e\n        \u003ctd style=\"text-align: right;\"\u003eLondon\u003c/td\u003e\n        \u003ctd style=\"text-align: center;\"\u003eFox\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd style=\"text-align: center;\"\u003ejay.elephant@protonmail.com\u003c/td\u003e\n        \u003ctd style=\"text-align: right;\"\u003eParis\u003c/td\u003e\n        \u003ctd style=\"text-align: center;\"\u003eElephant\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n        \u003ctd style=\"text-align: center;\"\u003etran@bella.com\u003c/td\u003e\n        \u003ctd style=\"text-align: right;\"\u003eChina\u003c/td\u003e\n        \u003ctd style=\"text-align: center;\"\u003eTran\u003c/td\u003e\n    \u003c/tr\u003e\n\u003c/table\u003e\n\n```\n\n\n\n\n### Table generation sequence\n\nThe table is generated in the following sequence:\n\n```mermaid\nsequenceDiagram\n User-\u003e\u003e+Rendering operation: render\n Rendering operation -\u003e\u003e Rendering context: isComputeColumnWidths()? [null | true | false]\n opt computeColumnWidths == null\n Rendering operation -\u003e\u003e ITableWriter: get default value of computing column widths [true | false]\n Rendering operation -\u003e\u003e Rendering context: Update compute column widths value\n end\n\n opt computeColumnWidths == true\n Rendering operation -\u003e\u003e TableColumnsWidthDetector: compute column widths\n end\n\n Rendering operation -\u003e\u003e Rendering context: getCellDelimiter()\n Rendering operation -\u003e\u003e ITableWriter: getDefaultDelimiter()\n\n opt rendering context hasn't cell delimiter but ITableWriter provides default delimiter\n Rendering operation -\u003e\u003e Rendering context: Update the cell delimiter from ITableWriter\n end\n\n Rendering operation -\u003e\u003e IEscaper: beginTable(renderingContext)\n Rendering operation -\u003e\u003e ITableWriter: beginTable(renderingContext)\n\n opt ITableSource.hasHeaders() == true\n Rendering operation -\u003e\u003e ITableWriter: beginHeader()\n loop For each headerCell\n Rendering operation -\u003e\u003e IEscaper: escape(headerCell)\n Rendering operation -\u003e\u003e ITableWriter: writeCell(escapedHeaderCell)\n end\n Rendering operation -\u003e\u003e ITableWriter: endHeader()\n end\n\n loop For each row\n Rendering operation -\u003e\u003e ITableWriter: beginRow()\n loop For each cell\n Rendering operation -\u003e\u003e IEscaper: escape(cell)\n Rendering operation -\u003e\u003e ITableWriter: writeCell(escapedCell)\n end\n Rendering operation -\u003e\u003e ITableWriter: endRow()\n end\n Rendering operation -\u003e\u003e ITableWriter: endTable(renderingContext)\n Rendering operation--\u003e\u003e-User: rendered table\n```\n\n## Object utils\n\n### Getting object values\n\n```\n{topSpeed=35.24, legsCount=4, lazy=true, name=John}\n```\n\n```java\nclass Sample {\n    void test() {\n        Cat cat = new Cat();\n        Map\u003cString, Object\u003e values = Obj.getFieldValues(cat);\n        System.out.println(values);\n    }\n}\n```\n\n## Array utils\n\n### Joining arrays, adding elements\n\n```java\nclass Sample {\n    void test() {\n        int[] a = new int[]{1, 2, 3};\n        int[] b = new int[]{6, 7, 5};\n        int[] c = Arr.add(a, b);\n        assertArrayEquals(c, new int[]{1, 2, 3, 6, 7, 5});\n    }\n}\n```\n\n## Pair implementation\n\n```java\nclass Sample {\n    void test() {\n        Pair\u003cInteger, String\u003e pair = new Pair\u003c\u003e(5, \"C\");\n        assertEquals(5, pair.getKey());\n        assertEquals(\"C\", pair.getValue());\n    }\n}\n```\n\n## Resource (file) path utils\n\n### Get extension(without a dot)\n\n```java\nclass Sample {\n    void test() {\n        assertEquals(\"txt\", Path.extension(\"/my/path/to/file.txt\"));\n        assertEquals(\"\", Path.extension(\"/my/path/to/file\"));\n        assertEquals(\"\", Path.extension(\"/my/path/to/file.\"));\n    }\n}\n```\n\n## String utils\n\n```java\nclass Sample {\n    void test() {\n        assertEquals(2, Str.charsCount(\"commit\", 'm'));\n        assertEquals(\"String\", Str.capitalize(\"string\"));\n        assertEquals(\"  3\", Str.padLeft(\"3\", 3));\n        assertEquals(\"3  \", Str.padRight(\"3\", 3));\n    }\n}\n```\n\n## Time utils\n\n```java\nclass Sample {\n    void test() {\n        Timer t = new Timer();\n        doLongOperation();\n        System.out.println(\"Passed time: \" + t.getMillis() + \" milliseconds.\");\n    }\n}\n```\n\n## How to integrate with Gradle\n\n### From Maven Central\n\n\u003chttps://search.maven.org/artifact/io.github.mjfryc/mjaron-etudes-java/0.3.0/jar\u003e\n\n```gradle\nimplementation 'io.github.mjfryc:mjaron-etudes-java:0.3.0'\n```\n\n### As local `jar` file\n\n* Download the latest release\n    * From [here](https://github.com/mjfryc/mjaron-etudes-java/releases)\n    * To `[gradle's root directory]/libs/`\n    * E.g: `my-project/libs/mjaron-etudes-java-0.3.0.jar`\n* In any Gradle subproject which needs this library, put following content:\n    * `implementation files(project.rootDir.absolutePath + '/libs/mjaron-etudes-java-0.3.0.jar')`\n* Now import package and use it, e.g:\n    * `import pl.mjaron.etudes.*;`\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmjfryc%2Fmjaron-etudes-java","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmjfryc%2Fmjaron-etudes-java","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmjfryc%2Fmjaron-etudes-java/lists"}