Set up
I am working on a Spring Boot
project where we would like to make use of DynamoDB
.
Instead of using the AWS
library directly, we would like to use JNOSQL; this API allows to easily switch databases by selecting a different driver, which we may want to do in the future.
In our project, I created a small standalone configuration class to test the library by following the instructions in this tutorial and following the official docs for a Key-Value DB
(here).
The docs show that, once configured the database, I should be able to @Produces
a BucketManager
, this would allow me to then @Inject
a KeyValueTemplate
in my database service to write to the DB.
These are CDI annotations, with which I am not too familiar; this said, I am aware that @Inject
is something that Spring understands, while this may not be the case for @Produces
, which could be replaced with @Bean
The issue
By simply following the docs, whenever I try to run the application, Spring complaints that no KeyValueTemplate
bean can be found:
Field template in com.max.backend.service.TestEntryService required a bean of type 'jakarta.nosql.mapping.keyvalue.KeyValueTemplate' that could not be found.
Rightfully so: I am declaring a bean for BucketManager
, not for KeyValueTemplate
.
Notice that the docs show a sample app in which an SeContainer
is created, something I did not think I would need given that I am using Spring.
My hunch
I think this may have something to do with CDI vs Spring, where the library is somehow creating a bean for KeyValueTemplate
when I @Produces
the BucketManager
, but Spring does not see this bean.
Ideally I would like to either make this work fully with Spring, avoiding CDI altogether, or find a comprehensive and minimal solution to leverage the KeyValueTemplate
I'm surprised I did not find much about this online, this is a pretty established and useful library, I find peculiar that there are not many usages in Spring.
If you know a similar lib for Spring, please let me know!!
My code
Note: a full example of a JNOSQL demo for a KeyValue db (not for Spring), can be seen here.
Relevant Dependencies in build.gradle
// Spring
implementation 'org.springframework.boot:spring-boot-starter-web'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-validation', version: '2.3.5.RELEASE'
// JNOSQL
implementation group: 'org.eclipse.jnosql.artemis', name: 'artemis-key-value', version: '1.0.0-b1'
implementation group: 'org.eclipse.jnosql.diana', name: 'dynamodb-driver', version: '1.0.0-b1'
// JSON parsing
implementation group: 'javax.json.bind', name: 'javax.json.bind-api', version: '1.0'
implementation group: 'org.eclipse', name: 'yasson', version: '1.0.4'
implementation group: 'org.glassfish', name: 'javax.json', version: '1.1'
// For CDI (needed primarily for annotations)
implementation group: 'javax', name: 'javaee-web-api', version: '8.0'
Configuration MaxDatabase.java
package com.max.backend.service.jnosql;
import jakarta.nosql.Settings;
import jakarta.nosql.keyvalue.BucketManager;
import org.eclipse.jnosql.diana.dynamodb.keyvalue.DynamoDBBucketManagerFactory;
import org.eclipse.jnosql.diana.dynamodb.keyvalue.DynamoDBKeyValueConfiguration;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import java.util.HashMap;
import java.util.Map;
@Configuration
@ApplicationScoped
public class MyDatabase {
private DynamoDBKeyValueConfiguration configuration;
private DynamoDBBucketManagerFactory managerFactory;
@PostConstruct
public void initialize() {
// Set up the DB
configuration = new DynamoDBKeyValueConfiguration();
Map<String, Object> settings = new HashMap<>();
settings.put("dynamodb.endpoint", "http://localhost:8073");
settings.put("dynamodb.region", "eu-west-1");
settings.put("dynamodb.awsaccesskey", "myLocalKeyId");
settings.put("dynamodb.secretaccess", "myLocalSecretAccessKey");
managerFactory = configuration.get(Settings.of(settings));
}
@Produces // use @Bean instead?
public BucketManager getManager() {
return managerFactory.getBucketManager("initiatives");
}
}
Service
package com.max.backend.service;
import com.max.backend.model.TestEntry;
import jakarta.nosql.mapping.keyvalue.KeyValueTemplate;
import org.springframework.stereotype.Service;
import javax.inject.Inject;
import java.util.Optional;
@Service
public class TestEntryService {
@Inject
private KeyValueTemplate template;
public void put(TestEntry user) {
template.put(user);
}
public Optional<TestEntry> find(String id) {
return template.get(id, TestEntry.class);
}
}
(TestEntry
is just a small POJO, irrelevant to the issue I am facing here)