{"id":21419315,"url":"https://github.com/wimdeblauwe/biob","last_synced_at":"2025-08-02T14:09:03.645Z","repository":{"id":57735203,"uuid":"171864623","full_name":"wimdeblauwe/biob","owner":"wimdeblauwe","description":"Java library to store binary objects","archived":false,"fork":false,"pushed_at":"2019-03-05T09:03:29.000Z","size":93,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-14T07:04:46.762Z","etag":null,"topics":["java"],"latest_commit_sha":null,"homepage":null,"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/wimdeblauwe.png","metadata":{"files":{"readme":"README.adoc","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":"2019-02-21T12:05:47.000Z","updated_at":"2022-12-18T05:29:05.000Z","dependencies_parsed_at":"2022-09-26T16:41:13.011Z","dependency_job_id":null,"html_url":"https://github.com/wimdeblauwe/biob","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/wimdeblauwe/biob","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wimdeblauwe%2Fbiob","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wimdeblauwe%2Fbiob/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wimdeblauwe%2Fbiob/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wimdeblauwe%2Fbiob/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wimdeblauwe","download_url":"https://codeload.github.com/wimdeblauwe/biob/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wimdeblauwe%2Fbiob/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268401594,"owners_count":24244464,"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-08-02T02:00:12.353Z","response_time":74,"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":["java"],"created_at":"2024-11-22T19:39:22.065Z","updated_at":"2025-08-02T14:09:03.613Z","avatar_url":"https://github.com/wimdeblauwe.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"= BIOB - Binary Object Repository\n\nimage:https://travis-ci.org/wimdeblauwe/biob.svg?branch=master[\"Build Status\", link=\"https://travis-ci.org/wimdeblauwe/biob\"]\nimage:https://sonarcloud.io/api/project_badges/measure?project=org.wimdeblauwe%3Abiob\u0026metric=coverage[\"Coverage\", link=\"https://sonarcloud.io/dashboard?id=org.wimdeblauwe%3Abiob\"]\nimage:https://maven-badges.herokuapp.com/maven-central/io.github.wimdeblauwe/biob/badge.svg[\"Maven Central\", link=\"https://search.maven.org/search?q=a:biob\"]\n\n== Goal\n\nThe goal of this project is to make it easy to store binary data\nalongside the entities that refer to them.\n\nFor example:\n\n* An avatar image that is linked to the `User` entity\n* Attachments that are linked to an `Issue` in an issue tracker\n\n== Example Usage\n\n=== Add dependency\n\n==== Maven\n\nUse this dependency if you use Maven:\n\n[source,xml]\n----\n\u003cdependency\u003e\n  \u003cgroupId\u003eio.github.wimdeblauwe\u003c/groupId\u003e\n  \u003cartifactId\u003ebiob\u003c/artifactId\u003e\n  \u003cversion\u003e${biob.version}\u003c/version\u003e\n\u003c/dependency\u003e\n----\n\n==== Gradle\n\nFor Gradle, use the following dependency:\n\n[source, groovy]\n----\nimplementation 'io.github.wimdeblauwe:biob:${biob.version}'\n----\n\n=== Basic setup\n\nThe library is not tied to Spring Boot, but I will use some\nconcepts of Spring Boot to explain it usage.\n\nSuppose you have the following `User` entity:\n\n[source,java]\n----\n@Entity\npublic class User {\n\n  @Id\n  private Long id;\n  private String username;\n\n  // further details of class omitted...\n}\n----\n\nIf you use Spring Data, you will have a repository to persist this\nin the database:\n\n[source,java]\n----\npublic interface UserRepository extends CrudRepository\u003cUser, Long\u003e {\n}\n----\n\nand most likely a `Service` that uses this repository:\n\n[source,java]\n----\n@Service\n@Transactional\npublic class UserServiceImpl implements UserService {\n\n  private final UserRepository repository;\n\n  public UserServiceImpl(UserRepository repository) {\n    this.repository = repository;\n  }\n\n  public void createUser( String username ) {\n    repository.save( new User(null, username) );\n  }\n}\n----\n\n=== Extending the User entity\n\nWe now extend the `User` class to store the avatar image of the user. However,\nwe will not store binary file in the database, but only store a reference to\nthe file in the database. The file itself will be stored in a `BinaryObjectStorage`\nimplementation of which our library has various implementations available.\n\nThe type of the reference in the entity can be any primitive or class you want. For\nthis example, we will go for a simple `UUID`:\n\n[source,java]\n----\n@Entity\npublic class User {\n\n  @Id\n  private Long id;\n  private String username;\n  private UUID avatarId;\n\n  // further details of class omitted...\n}\n----\n\n=== Adding a BinaryObjectRepository\n\nTo store a binary file, we create an instance of `BinaryObjectRepository`:\n\n[source,java]\n----\nInMemoryBinaryObjectStorage storage = new InMemoryBinaryObjectStorage(); \u003c1\u003e\nBinaryObjectRepository\u003cUser, UUID\u003e repository = new BinaryObjectRepository\u003c\u003e( \u003c2\u003e\n                                                    UUID::randomUUID, \u003c3\u003e\n                                                    (user, uuid) -\u003e user.getId() + \"/images/\"\n                                                                    + uuid.toString(), \u003c4\u003e\n                                                    storage); \u003c5\u003e\n----\n\u003c1\u003e Creates in memory instance of `BinaryObjectStorage`\n\u003c2\u003e The `BinaryObjectRepository` needs 2 generic types. The first one is the type of the entity\nthat the binary object is refered from (e.g. `User`). The second one is the type that is used by the reference\nitself (e.g. `UUID`).\n\u003c3\u003e The first argument is a function that generates a new object of the type of\nthe reference. This this case, we generate a random `UUID`.\n\u003c4\u003e The second argument is a function that generates the path where the file should be stored. This\npath will be relative and interpreted by the `BinaryObjectStorage` implementation as they see fit.\n\u003c5\u003e The actual `BinaryObjectStorage` that will persist the file. This can be in memory, in a folder structure\non disk, on an S3 bucket, ...\n\n=== Updating the UserService\n\nThere are now 2 ways to use the `BinaryObjectRepository` in our service:\n\n* Inject the full `BinaryObjectRepository` instance into your service.\n* Inject the `BinaryObjectStorage` and create the `BinaryObjectRepository` in the constructor of your service.\n\nThis is an example where we inject the backing storage in our service:\n\n[source,java]\n----\n@Service\n@Transactional\npublic class UserServiceImpl implements UserService {\n\n  private final UserRepository repository;\n  private final BinaryObjectRepository objectRepository;\n\n  public UserServiceImpl(UserRepository repository,\n                         BinaryObjectStorage storage) {\n    this.repository = repository;\n    this.objectRepository = new BinaryObjectRepository\u003c\u003e( UUID::randomUUID, \u003c1\u003e\n                                                          (user, uuid) -\u003e user.getId() + \"/images/\"\n                                                                          + uuid.toString(),\n                                                          storage);\n  }\n\n  public void createUser( String username, MultipartFile avatar ) {\n    User user = repository.save( new User(null, username) );\n\n    UUID avatarId = objectRepository.store( user, \u003c2\u003e\n                                            getMetadata(avatar),\n                                            avatar.getInputStream() );\n\n    user.setAvatarId( avatarId ); \u003c3\u003e\n  }\n\n  private BinaryObjectMetadata getMetadata(MultipartFile multipartFile) { \u003c4\u003e\n    return new BinaryObjectMetadata(multipartFile.getSize(),\n                                    multipartFile.getOriginalFilename(),\n                                    multipartFile.getContentType());\n  }\n}\n----\n\u003c1\u003e Create the `BinaryObjectRepository` in the constructor\n\u003c2\u003e Store the binary file. We assume it was uploaded as a `MultipartFile` via a `@Controller` for example.\n\u003c3\u003e Use the returned `avatarId` and set it on the entity so it is stored in the database along with the `User` entity.\n\u003c4\u003e The `store()` method also requires some metadata with is gathered in the `BinaryObjectMetadata` object.\n\n== Backing storage implementations\n\nThe project currently has the following backing storages implemented:\n\n=== In memory\n\nThe `InMemoryBinaryObjectStorage` keeps all binary objects in memory. Its main\npurpose is testing.\n\n=== File based\n\nThe `LocalFileSystemBinaryObjectStorage` will store the binary objects on the local filesystem.\nThe generated path for each object that is stored will be relative to the `baseDir` that is passed at construction time.\n\n== Development\n\n* Builds are done on Travis: https://travis-ci.org/wimdeblauwe/biob\n* Code quality is available via SonarQube: https://sonarcloud.io/dashboard?id=org.wimdeblauwe%3Abiob\n\n== Deployment\n\n* SNAPSHOT versions are put on https://oss.sonatype.org/content/repositories/snapshots\n* All releases can be downloaded from https://oss.sonatype.org/content/groups/public\n\n== Release\n\nRelease is done via the Maven Release Plugin:\n\n`mvn release:prepare`\n\nand\n\n`mvn release:perform`\n\n[NOTE]\n====\nBefore releasing, run `export GPG_TTY=$(tty)`\n====\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwimdeblauwe%2Fbiob","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwimdeblauwe%2Fbiob","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwimdeblauwe%2Fbiob/lists"}