https://github.com/wimdeblauwe/biob
Java library to store binary objects
https://github.com/wimdeblauwe/biob
java
Last synced: 12 months ago
JSON representation
Java library to store binary objects
- Host: GitHub
- URL: https://github.com/wimdeblauwe/biob
- Owner: wimdeblauwe
- License: apache-2.0
- Created: 2019-02-21T12:05:47.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2019-03-05T09:03:29.000Z (over 7 years ago)
- Last Synced: 2025-07-14T07:04:46.762Z (about 1 year ago)
- Topics: java
- Language: Java
- Size: 90.8 KB
- Stars: 4
- Watchers: 2
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.adoc
- License: LICENSE
Awesome Lists containing this project
README
= BIOB - Binary Object Repository
image:https://travis-ci.org/wimdeblauwe/biob.svg?branch=master["Build Status", link="https://travis-ci.org/wimdeblauwe/biob"]
image:https://sonarcloud.io/api/project_badges/measure?project=org.wimdeblauwe%3Abiob&metric=coverage["Coverage", link="https://sonarcloud.io/dashboard?id=org.wimdeblauwe%3Abiob"]
image:https://maven-badges.herokuapp.com/maven-central/io.github.wimdeblauwe/biob/badge.svg["Maven Central", link="https://search.maven.org/search?q=a:biob"]
== Goal
The goal of this project is to make it easy to store binary data
alongside the entities that refer to them.
For example:
* An avatar image that is linked to the `User` entity
* Attachments that are linked to an `Issue` in an issue tracker
== Example Usage
=== Add dependency
==== Maven
Use this dependency if you use Maven:
[source,xml]
----
io.github.wimdeblauwe
biob
${biob.version}
----
==== Gradle
For Gradle, use the following dependency:
[source, groovy]
----
implementation 'io.github.wimdeblauwe:biob:${biob.version}'
----
=== Basic setup
The library is not tied to Spring Boot, but I will use some
concepts of Spring Boot to explain it usage.
Suppose you have the following `User` entity:
[source,java]
----
@Entity
public class User {
@Id
private Long id;
private String username;
// further details of class omitted...
}
----
If you use Spring Data, you will have a repository to persist this
in the database:
[source,java]
----
public interface UserRepository extends CrudRepository {
}
----
and most likely a `Service` that uses this repository:
[source,java]
----
@Service
@Transactional
public class UserServiceImpl implements UserService {
private final UserRepository repository;
public UserServiceImpl(UserRepository repository) {
this.repository = repository;
}
public void createUser( String username ) {
repository.save( new User(null, username) );
}
}
----
=== Extending the User entity
We now extend the `User` class to store the avatar image of the user. However,
we will not store binary file in the database, but only store a reference to
the file in the database. The file itself will be stored in a `BinaryObjectStorage`
implementation of which our library has various implementations available.
The type of the reference in the entity can be any primitive or class you want. For
this example, we will go for a simple `UUID`:
[source,java]
----
@Entity
public class User {
@Id
private Long id;
private String username;
private UUID avatarId;
// further details of class omitted...
}
----
=== Adding a BinaryObjectRepository
To store a binary file, we create an instance of `BinaryObjectRepository`:
[source,java]
----
InMemoryBinaryObjectStorage storage = new InMemoryBinaryObjectStorage(); <1>
BinaryObjectRepository repository = new BinaryObjectRepository<>( <2>
UUID::randomUUID, <3>
(user, uuid) -> user.getId() + "/images/"
+ uuid.toString(), <4>
storage); <5>
----
<1> Creates in memory instance of `BinaryObjectStorage`
<2> The `BinaryObjectRepository` needs 2 generic types. The first one is the type of the entity
that the binary object is refered from (e.g. `User`). The second one is the type that is used by the reference
itself (e.g. `UUID`).
<3> The first argument is a function that generates a new object of the type of
the reference. This this case, we generate a random `UUID`.
<4> The second argument is a function that generates the path where the file should be stored. This
path will be relative and interpreted by the `BinaryObjectStorage` implementation as they see fit.
<5> The actual `BinaryObjectStorage` that will persist the file. This can be in memory, in a folder structure
on disk, on an S3 bucket, ...
=== Updating the UserService
There are now 2 ways to use the `BinaryObjectRepository` in our service:
* Inject the full `BinaryObjectRepository` instance into your service.
* Inject the `BinaryObjectStorage` and create the `BinaryObjectRepository` in the constructor of your service.
This is an example where we inject the backing storage in our service:
[source,java]
----
@Service
@Transactional
public class UserServiceImpl implements UserService {
private final UserRepository repository;
private final BinaryObjectRepository objectRepository;
public UserServiceImpl(UserRepository repository,
BinaryObjectStorage storage) {
this.repository = repository;
this.objectRepository = new BinaryObjectRepository<>( UUID::randomUUID, <1>
(user, uuid) -> user.getId() + "/images/"
+ uuid.toString(),
storage);
}
public void createUser( String username, MultipartFile avatar ) {
User user = repository.save( new User(null, username) );
UUID avatarId = objectRepository.store( user, <2>
getMetadata(avatar),
avatar.getInputStream() );
user.setAvatarId( avatarId ); <3>
}
private BinaryObjectMetadata getMetadata(MultipartFile multipartFile) { <4>
return new BinaryObjectMetadata(multipartFile.getSize(),
multipartFile.getOriginalFilename(),
multipartFile.getContentType());
}
}
----
<1> Create the `BinaryObjectRepository` in the constructor
<2> Store the binary file. We assume it was uploaded as a `MultipartFile` via a `@Controller` for example.
<3> Use the returned `avatarId` and set it on the entity so it is stored in the database along with the `User` entity.
<4> The `store()` method also requires some metadata with is gathered in the `BinaryObjectMetadata` object.
== Backing storage implementations
The project currently has the following backing storages implemented:
=== In memory
The `InMemoryBinaryObjectStorage` keeps all binary objects in memory. Its main
purpose is testing.
=== File based
The `LocalFileSystemBinaryObjectStorage` will store the binary objects on the local filesystem.
The generated path for each object that is stored will be relative to the `baseDir` that is passed at construction time.
== Development
* Builds are done on Travis: https://travis-ci.org/wimdeblauwe/biob
* Code quality is available via SonarQube: https://sonarcloud.io/dashboard?id=org.wimdeblauwe%3Abiob
== Deployment
* SNAPSHOT versions are put on https://oss.sonatype.org/content/repositories/snapshots
* All releases can be downloaded from https://oss.sonatype.org/content/groups/public
== Release
Release is done via the Maven Release Plugin:
`mvn release:prepare`
and
`mvn release:perform`
[NOTE]
====
Before releasing, run `export GPG_TTY=$(tty)`
====