Recentemente aprovado com um projeto EE4J, o Jakarta NoSQL é uma especificação no Jakarta EE para ajudar os desenvolvedores a criarem aplicações usando Java e NoSQL. O JNoSQL é a implementação de referência do Jakarta NoSQL, fornecendo uma série de APIs e uma implementação padrão para uma série de databases NoSQL, tais como Cassandra, MongoDB, Neo4J, CouchDB, e OrientDB, além de outros.
O Jakarta NoSQL possui duas camadas, a Communication Layer (Diana), que traz uma série de APIs projetadas para definir a comunicação com os databases NoSQL, contendo quatro módulos de acordo com cada tipo de database: Key-Value, Column Family, Document, and Graph; e a Mapping Layer (Artemis) que fornece uma série de APIs para ajudar os desenvolvedores a integrar aplicações Java com os databases. A Mapping Layer usa tecnologias como o CDI e Bean Validation, facilitando a vida dos desenvolvedores. É possível comparar a Mapping Layer com o JPA/Hibernate em um tradicional mundo RDBMS.
(Imagem obtida em github.com/eclipse-ee4j/nosql)
Vamos nos aprofundar um pouco e explorar como é feita a comunicação com databases NoSQL do tipo Key-Value, Column Family, Document, e Graph.
Definir uma entidade é muito semelhante a como se define uma entidade com o JPA. Basicamente são usados @Entity
, @Id
, @Column
e assim por diante:
@Entity
public class Person {
@Id
private long id;
@Column
private String name;
@Column
private List phones;
}
Os repositórios são muito semelhantes aos repositórios do Spring Data, no qual basta estender um Repository<T, ID>
:
public interface PersonRepository extends Repository {
List<Person> findByName(String name);
Stream<Person> findByPhones(String phone);
}
A partir daqui, cada implementação começa a ter suas particularidades, desde os artefatos maven que mudam de acordo com o tipo de database NoSQL, assim como as configurações de conexão e como injetar um repositório nos serviços.
Vamos ver as diferenças entre um database NoSQL do tipo Column e outro do tipo Document:
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>
A seguir um exemplo de producer usado para configurar o 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);
}
}
E finalmente, um exemplo de como executar alguns inserts/queries:
Person person = Person.builder()
.withPhones(Arrays.asList("234", "432"))
.withName("Name")
.withId(id)
.build();
//usando 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);
//usando 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
Os artefatos maven são:
<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>
A seguir um exemplo de producer usado para configurar o 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);
}
}
E finalmente um exemplo de como executar alguns inserts/queries:
Person person = Person.builder()
.withPhones(Arrays.asList("234", "432"))
.withName("Name")
.withId(id)
.build();
//usando 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);
//usando 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);
Maiores detalhes sobre a implementação de referência do Jakarta NoSQL podem ser encontrados na página do JNoSQL.
Uma apresentação sobre o Jakarta NoSQL no Jakarta One também está disponível.
Usuários que quiserem contribuir podem se inscrever na lista de email, ou entrar em contato através do Twitter.