Recently approved as an EE4J project, Jakarta NoSQL is a specification in Jakarta EE to help developers create enterprise-grade applications using Java and NoSQL technologies. JNoSQL is the reference implementation of Jakarta NoSQL, providing a set of APIs and a standard implementation for a series of NoSQL databases, such as Cassandra, MongoDB, Neo4J, CouchDB, and OrientDB, among others.
Jakarta NoSQL consists of a Communication Layer (Diana), which brings a set of APIs designed for defining the communication with NoSQL databases. It contains four modules according to each NoSQL database type: key-value, column family, document, and graph; and a Mapping Layer (Artemis), which provides a series of APIs to help developers integrate Java applications with NoSQL databases. The mapping layer is annotation-driven and uses technologies like CDI and Bean Validation, making it simple for developers to use. It is possible to compare the mapping layer with JPA/Hibernate in the traditional RDBMS world.
(Image taken from github.com/eclipse-ee4j/nosql)
Let's go a little deeper and explore how to communicate with key-value, column family, document, and graph NoSQL databases.
The definition of an Entity is relatively similar to JPA. You basically use @Entity
, @Id
, @Column
and so on:
@Entity
public class Person {
@Id
private long id;
@Column
private String name;
@Column
private List phones;
}
Repositories looks like Spring Data repositories, where you extend a Repository<T, ID>
:
public interface PersonRepository extends Repository {
List<Person> findByName(String name);
Stream<Person> findByPhones(String phone);
}
However, from this point on, things change, since the Maven dependencies change according to the type of NoSQL database being used, as well the setup configuration and how we inject the repository in our services.
Let's compare the differences between column and document NoSQL databases:
Column
The following are the Maven artifacts:
<dependency>
<groupId>org.jnosql.artemis</groupId>
<artifactId>artemis-column</artifactId>
<version>0.0.9</version>
</dependency>
<dependency>
<groupId>org.jnosql.diana</groupId>
<artifactId>cassandra-driver</artifactId>
<version>0.0.9</version>
</dependency>
The following is a producer example used to set up the ColumnFamilyManager
:
@ApplicationScoped
public class ColumnFamilyManagerProducer {
private static final String KEY_SPACE = "developers";
private ColumnConfiguration<> cassandraConfiguration;
private ColumnFamilyManagerFactory managerFactory;
@PostConstruct
public void init() {
cassandraConfiguration = new CassandraConfiguration();
managerFactory = cassandraConfiguration.get();
}
@Produces
public ColumnFamilyManager getManagerCassandra() {
return managerFactory.get(KEY_SPACE);
}
}
And finally, an example of how to execute some inserts/queries:
Person person = Person.builder()
.withPhones(Arrays.asList("234", "432"))
.withName("Name")
.withId(id)
.build();
//using ColumnTemplate
ColumnTemplate columnTemplate = container.select(CassandraTemplate.class).get();
Person saved = columnTemplate.insert(PERSON);
System.out.println("Person saved" + saved);
ColumnQuery query = select().from("Person").where(eq(Column.of("id", 1L))).build();
Optional<Person> person = columnTemplate.singleResult(query);
System.out.println("Entity found: " + person);
//using PersonRepository
PersonRepository repository = container.select(PersonRepository.class).select(ofColumn()).get();
Person saved = repository.save(PERSON);
System.out.println("Person saved" + saved);
Optional<Person> person = repository.findById(1L);
System.out.println("Entity found: " + person);
Document
The following are the Maven artifacts:
<dependency>
<groupId>org.jnosql.artemis</groupId>
<artifactId>artemis-document</artifactId>
<version>0.0.9</version>
</dependency>
<dependency>
<groupId>org.jnosql.diana</groupId>
<artifactId>mongodb-driver</artifactId>
<version>0.0.9</version>
</dependency>
The following is a producer example used to set up the the DocumentCollectionManager
:
@ApplicationScoped
public class DocumentCollectionManagerProducer {
private static final String COLLECTION = "developers";
private DocumentConfiguration configuration;
private DocumentCollectionManagerFactory managerFactory;
@PostConstruct
public void init() {
configuration = new MongoDBDocumentConfiguration();
Map<String, Object> settings = Collections.singletonMap("mongodb-server-host-1", "localhost:27017");
managerFactory = configuration.get(Settings.of(settings));
}
@Produces
public DocumentCollectionManager getManager() {
return managerFactory.get(COLLECTION);
}
}
And finally, an example of how to execute some inserts/queries:
Person person = Person.builder()
.withPhones(Arrays.asList("234", "432"))
.withName("Name")
.withId(id)
.build();
//using DocumentTemplate
DocumentTemplate documentTemplate = container.select(DocumentTemplate.class).get();
Person saved = documentTemplate.insert(person);
System.out.println("Person saved" + saved);
DocumentQuery query = select().from("Person")
.where(eq(Document.of("_id", id))).build();
Optional<Person> personOptional = documentTemplate.singleResult(query);
System.out.println("Entity found: " + personOptional);
//using PersonRepository
PersonRepository repository = container.select(PersonRepository.class)
.select(ofDocument()).get();
repository.save(person);
List<Person> people = repository.findByName("Name");
System.out.println("Entity found: " + people);
repository.findByPhones("234").forEach(System.out::println);
More details on Jakarta NoSQL's reference implementation can be found at the JNoSQL page.
There is also a presentation of Jakarta NoSQL on Jakarta One available.
Users who want to contribute can subscribe to the mailing list, or get in touch through Twitter.