{"id":36705625,"url":"https://github.com/ununbium/bettertype","last_synced_at":"2026-01-12T11:42:24.237Z","repository":{"id":57731134,"uuid":"272817844","full_name":"ununbium/bettertype","owner":"ununbium","description":"A library for making error handling code a little cleaner","archived":false,"fork":false,"pushed_at":"2022-05-02T21:11:51.000Z","size":67,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-10T13:48:51.638Z","etag":null,"topics":["container","converter","error-handling","failable","optional"],"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/ununbium.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":"2020-06-16T21:41:31.000Z","updated_at":"2022-05-01T22:58:11.000Z","dependencies_parsed_at":"2022-09-26T22:01:47.806Z","dependency_job_id":null,"html_url":"https://github.com/ununbium/bettertype","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/ununbium/bettertype","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ununbium%2Fbettertype","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ununbium%2Fbettertype/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ununbium%2Fbettertype/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ununbium%2Fbettertype/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ununbium","download_url":"https://codeload.github.com/ununbium/bettertype/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ununbium%2Fbettertype/sbom","scorecard":{"id":911092,"data":{"date":"2025-08-11","repo":{"name":"github.com/ununbium/bettertype","commit":"93ecf85ea93070aecc9899ae2a9003f08ddb6bf9"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 0/28 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 3 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-24T19:13:32.127Z","repository_id":57731134,"created_at":"2025-08-24T19:13:32.128Z","updated_at":"2025-08-24T19:13:32.128Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28338972,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T10:58:46.209Z","status":"ssl_error","status_checked_at":"2026-01-12T10:58:42.742Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["container","converter","error-handling","failable","optional"],"created_at":"2026-01-12T11:42:24.171Z","updated_at":"2026-01-12T11:42:24.226Z","avatar_url":"https://github.com/ununbium.png","language":"Java","readme":"# BetterType\nA library for making your error handling code a little cleaner.\n\n# Motivation\nReturning Optional\u003cString\u003e is a great way to indicate to other developers that a specific outcome might not happen. \nIt is often the case that the outcome of an action is more complex than either a value with success or a failure without\na value.\n\nWhile Exceptions can be used to communicate failure reasons, they can result in some messy code and poor interfaces. By\ninstead relying on strongly semantic return types the interface becomes cleaner, catch blocks can be eliminated favoring\nplain code and the nature of the error and how it is handled becomes more prominent in the planning process. \n\n# Dependency\nJust include the core as follows;\n```xml\n\u003cdependency\u003e\n    \u003cartifactId\u003ebettertype-core\u003c/artifactId\u003e\n    \u003cgroupId\u003edev.errant\u003c/groupId\u003e\n    \u003cversion\u003e0.6.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n# Types\nA run through the core concepts with some example code for each.\n\n## Failable\nRepresents an outcome of an action that can fail. The result can either be successful or failure, each with an \nassociated value. The success and failure values can (and normally will) have different types, but note that they are \narbitrary and inferred from the failable parameter.\n\nDeclare much like an optional;\n```java\n    public Failable\u003cInteger, String\u003e countChickens() {\n        if(hatched == eggs) {\n            return Failable.success(eggs);\n        } else {\n            return Failable.failure(\"Some not yet hatched\");\n        }\n    }\n```\n\nUse the type safe responses;\n```java\n    public void bragAboutNumberOfChickens() {\n        Failable\u003cInteger, String\u003e chickenCount = countChickens();\n\n        if (chickenCount.isSuccess()) {\n            int chickens = chickenCount.getSuccess();\n            brag(chickens);\n        } else {\n            String reason = chickenCount.getFailure();\n            quietlyReport(reason);\n        }\n    }\n```\n\n## SimpleFailable\nRepresents an outcome of an action that can fail. The result can either be successful or failure, but unlike Failable only\n failure has an associated value for a SimpleFailable.\n\nDeclaration is similar to Failable but with no \"Success value\"; \n```java\n    public SimpleFailable\u003cDoorNotClosedReason\u003e closeCoopDoor() {\n        if(chickensTotal \u003c chickensInCoop) {\n            return SimpleFailable.failure(DoorNotClosedReason.NOT_ALL_ACCOUNTED_FOR);\n        } else if(doorStuck) {\n            return SimpleFailable.failure(DoorNotClosedReason.DOOR_STUCK);\n        } else {\n            return SimpleFailable.success();\n        }\n    }\n```\n\nSimilarly, null checks or semantically problematic enum values (DoorNotClosedReason.NONE) can be avoided, and the \nresulting code is very readable; \n```java\n    public void lockUpForNight() {\n        SimpleFailable\u003cDoorNotClosedReason\u003e closedDoor = closeCoopDoor();\n        \n        if(closedDoor.isSuccess()) {\n            callItADay();\n        } else {\n            DoorNotClosedReason failure = closedDoor.getFailure();\n            fixIssue(failure);\n        }\n    }\n```\n\n## Absorbing errors (Exceptions)\nThe static method \"absorb\" on Failable and SimpleFailable execute some code and soak up any exceptions. If an exception \nis thrown it is absorbed and returned as the failure reason.\n\nSimpleFailable.absorb(...) is used to wrap an action with no \"success value\", but some potential exceptions such as \nwriting to a file;\n```java\n    public SimpleFailable\u003cException\u003e updateChickenFile(String chickenNotes) {\n        return SimpleFailable.absorb(\n            () -\u003e Files.write(Paths.get(\"chickens.txt\"), chickenNotes.getBytes(), StandardOpenOption.APPEND)\n        );\n    }\n```\n\nFailable.absorb(...) is used to wrap an action with a \"success value\" and some potential exceptions such as \nreading data from a file;\n```java\n    public Failable\u003cString, Exception\u003e readChickenFile(String chickenNotes) {\n        return Failable.absorb(\n                () -\u003e Files.readString(Paths.get(\"chickens.txt\"))\n        );\n    }\n```\n\nNote that the return type is \"Exception\" because we've not specified how to convert exceptions to other values. \nThe next section details how to do this. \n\n## Exception Converters\nIt is normally desirable to convert exceptions to some other more meaningful format, like a String, enumerated \"cause\" \nor complex type. Exception converters are a functional interface that can be either overriden inline or by inheritance.\nThere are also some premade basic converters declared statically in ExceptionConverters.\n\nUsing ExceptionConverters.messagePrintingConverter() we can capture just the message from the previous example;\n```java\n    public Failable\u003cString, String\u003e readChickenFile(String chickenNotes) {\n        return Failable.absorb(\n                () -\u003e Files.readString(Paths.get(\"chickens.txt\")),\n                ExceptionConverters.messagePrintingConverter()\n        );\n    }\n```\nNote that the return type is now Failable\u003cString, String\u003e rather than Failable\u003cString, Exception\u003e\n\nWhile there are some provided basic implementations, the library user is encouraged to implement their own \nExceptionConverter to capture any relevant information in cases where Exceptions cannot be eliminated, e.g. 3rd party \nintegrations.\n\n# See also\nSome very basic examples from this document can be found [here](https://github.com/ununbium/bettertype/tree/master/core/src/test/java/dev/errant/bettertype/basic/example/chickens) (in the core test folder, in the package *dev.errant.bettertype.basic.example.chickens*)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fununbium%2Fbettertype","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fununbium%2Fbettertype","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fununbium%2Fbettertype/lists"}