Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Eclipse JNoSQL 0.0.4, a Solution to Java in NoSQL Databases

DZone's Guide to

Eclipse JNoSQL 0.0.4, a Solution to Java in NoSQL Databases

Learn about Eclipse JNoSQL, a Java framework that streamlines the integration of a Java application with the NoSQL database.

· Database Zone ·
Free Resource

Compliant Database DevOps and the role of DevSecOps DevOps is becoming the new normal in application development, and DevSecOps is now entering the picture. By balancing the desire to release code faster with the need for the same code to be secure, it addresses increasing demands for data privacy. But what about the database? How can databases be included in both DevOps and DevSecOps? What additional measures should be considered to achieve truly compliant database DevOps? This whitepaper provides a valuable insight. Get the whitepaper

Eclipse JNoSQL is a Java framework that streamlines the integration of a Java application with the NoSQL database. It defines a set of APIs to interact with the NoSQL database and provides a standard implementation for most NoSQL databases. This clearly helps to achieve very low coupling with the underlying NoSQL technologies used in applications.

The project has two layers:

  1. Communication API: These are set to APIs that define communication with NoSQL database. In the traditional RDBMS world, these can be compared with JDBC APIs. This API set contains four modules with each one representing a NoSQL database storage type like Key-Value pair, Column Family etc.
  2. Mapping API: These are the APIs that help developers integrate their Java application with the NoSQL database. This layer is annotation-driven and uses technologies like CDI and Bean Validations to make it simpler for developers. In the traditional RDBMS world, this layer can be compared to JPA or ORM frameworks.

A Standard Easy-to-Use Extension

Eclipse JNoSQL API has an easy interface and it's easy to implement to a new database.

This particular behavior in a NoSQL database matters — that why the API is extensible.

Image title

Modules

The modules project was the most impacting change in the project, so each type has a particular module. Also, there're the bean validation module and configuration, when you would like to read configuration from either XML or JSON by @ConfigurationUnit annotation.

<dependency>
    <groupId>org.jnosql.artemis</groupId>
   <artifactId>artemis-key-value</artifactId>
    <version>0.0.4</version>
</dependency>
<dependency>
    <groupId>org.jnosql.artemis</groupId>
     <artifactId>artemis-column</artifactId>
     <version>0.0.4</version>
</dependency>
<dependency>
     <groupId>org.jnosql.artemis</groupId>
      <artifactId>artemis-document</artifactId>
      <version>0.0.4</version>
</dependency>

Improves the Query API in Document and Column Database Types

There are improvements in the fluent API to query in both document and column to select and delete entities.

//select
ColumnQuery query = select().from(columnFamily).where("name").eq(name).or("age").gt(10).build();
ColumnQuery query = select().from(columnFamily).where("name").eq(name).and("age").gt(10).build();
ColumnQuery query = select().from(columnFamily).where("name").not().eq(name).build();
ColumnQuery query = select().from(columnFamily).where("salary").between(valueA, valueB).build();
//delete
ColumnDeleteQuery query = delete().from(columnFamily).where("name").eq(name).build();
ColumnDeleteQuery query = delete().from(columnFamily).where("name").not().eq(name).build();
ColumnDeleteQuery query = delete().from(columnFamily).where("name").eq(name).and("age").gt(10).build();
ColumnDeleteQuery query = delete().from(columnFamily).where("name").eq(name).or("age").gt(10).build();
//select
DocumentQuery query = select().from(columnFamily).where("name").eq(name).or("age").gt(10).build();
DocumentQuery query = select().from(columnFamily).where("name").eq(name).and("age").gt(10).build();
DocumentQuery query = select().from(columnFamily).where("name").not().eq(name).build();
DocumentQuery query = select().from(columnFamily).where("salary").between(valueA, valueB).build();

//delete
DocumentDeleteQuery query = delete().from(columnFamily).where("name").eq(name).build();
DocumentDeleteQuery query = delete().from(columnFamily).where("name").not().eq(name).build();
DocumentDeleteQuery query = delete().from(columnFamily).where("name").eq(name).and("age").gt(10).build();
DocumentDeleteQuery query = delete().from(columnFamily).where("name").eq(name).or("age").gt(10).build();

New Methods to columntemplate and documenttemplate

Now, these classes have find and delete by ID.

It's also available to individual templates asynchronous.

ColumnTemplateAsync template =//new instance...;
Consumer<Optional<User>> callback = o → o.ifPresent(System.out::println);
Optional<User> user = template.find(User.class, 10L, callback);
Consumer<Void> callback = v → System.out.println(“Deleted”);
template.delete(User.class, 10, callback);


DocumentTemplateAsync template =//new instance...;
Consumer<Optional<User>> callback = o → o.ifPresent(System.out::println);
Optional<User> user = template.find(User.class, 10L, callback);
Consumer<Void> callback = v → System.out.println(“Deleted”);
template.delete(User.class, 10, callback);

Query With Object Mapper to Document and Column Mapping API

In the Artemis, there's the query mapper, which implements the same query builder. However, it maps each object field to a native one.

@Entity
public class God {

    @Column("native")
    private String name;

    @Column("native1")
    private String power;

}
   @Inject
   private ColumnQueryMapperBuilder mapperBuilder;

   public void query() {
   ColumnQuery query = mapperBuilder.selectFrom(God.class)
     .orderBy("name").asc().build();

     ColumnDeleteQuery deleteQuery = mapperBuilder.deleteFrom(God.class)
       .where("power").eq("Sun").build();
   }
   @Inject
   private DocumentQueryMapperBuilder mapperBuilder;


   public void query() {
   DocumentQuery query = mapperBuilder.selectFrom(God.class)
     .orderBy("name").asc().build();

     DocumentDeleteQuery deleteQuery = mapperBuilder.deleteFrom(God.class)
       .where("power").eq("Sun").build();
   }

New Extensions to Capture Particular Behavior From a NoSQL Database

The core concept of JNoSQL is basically that it has a common API; however, an extensible one would make it easier to use specific behavior because this really matters in a NoSQL world. There are new features to Cassandra, ArangoDB, Hazelcast, and OrientDB database. In this version, there is support for AQL, Arango Query language, within JNoSQL.

interface PersonRepository extends ArangoDBRepository<Person, String> {

  @AQL("FOR p IN Person RETURN p")
  List<Person> findAll();

  @AQL("FOR p IN Person FILTER p.name = @name RETURN p")
  List<Person> findByName(@Param("name") String name);
}

interface PersonAsyncRepository extends ArangoDBRepositoryAsync<Person, String> {

  @AQL("FOR p IN Person FILTER p.name = @name RETURN p")
  void queryName(@Param("name") String name, Consumer<List<Person>> callBack);

}

Also is possible to use the Param type in the repository class for both Cassandra and OrientDB.

interface PersonRepository extends CassandraRepository<Person, String> {

  @CQL("select * from Person where age = :age")
  List<Person> findByAge(@Param("age") Integer age);
}

interface PersonAsyncRepository extends CassandraRepositoryAsync<Person, String> {
  @CQL("select * from Person where name= :name")
  void queryName(@Param("name") String name, Consumer<List<Person>> callBack);
}
interface PersonRepository extends OrientDBCrudRepository<Person, String> {

  @SQL("select * from Person")
  List<Person> findAll();

  @SQL("select * from Person where name = ?")
  List<Person> findByName(String name);

  @SQL("select * from Person where age = :age")
  List<Person> findByAge(@Param("age") Integer age);
}

interface PersonAsyncRepository extends OrientDBCrudRepositoryAsync<Person, String> {

  @SQL("select * from Person where name = ?")
  void queryName(String name, Consumer<List<Person>> callBack);

  @SQL("select * from Person where age = :age")
  void queryName(@Param("age") Integer age, Consumer<List<Person>> callBack);

}

Hazelcast also has a Query syntax resource:

interface PersonRepository extends HazelcastRepository<Person, String> {

        @Query("active")
        List<Person> findActive();

        @Query("name = :name AND age = :age")
        Set<Person> findByAgeAndInteger(@Param("name") String name, @Param("age") Integer age);
    }  

HazelcastTemplate is a specialization of the Key-Value template that allows using the SQL syntax query.

      Collection<Person> people = template.query("active");
      Collection<Person> people2 = template.query("age = :age", singletonMap("age", 10));
      Collection<Person> people3 = template.query(Predicates.equal("name",  "Poliana"));

Diving Deep Into the Model With Graph API

As far graph databases go, NoSQL is the kind that allows more complexity deep in the relationship. This API comes with more integration with Apache Tinkerpop.

The GraphTemplate has new methods that recover the edges of an entity from either itself or its ID.

Person otavio = graphTemplate.insert(builder().withAge().withName("Otavio").build());

Animal dog = graphTemplate.insert(new Animal("dog"));
Book cleanCode = graphTemplate.insert(Book.builder().withName("Clean code").build());

EdgeEntity likes = graphTemplate.edge(otavio, "likes", dog);
EdgeEntity reads = graphTemplate.edge(otavio, "reads", cleanCode);

Collection<EdgeEntity> edges1 = graphTemplate.getEdges(otavio, Direction.BOTH);
Collection<EdgeEntity> edges2 = graphTemplate.getEdges(otavio, Direction.BOTH, "reads");
Collection<EdgeEntity> edges3 = graphTemplate.getEdges(otavio, Direction.BOTH, () -> "likes");
Collection<EdgeEntity> edges4 = graphTemplate.getEdges(otavio, Direction.OUT);
Collection<EdgeEntity> edges5 = graphTemplate.getEdges(cleanCode, Direction.IN);

//findById
Collection<EdgeEntity> edges6 = graphTemplate.getEdgesById(otavio.getId(), Direction.BOTH);
Collection<EdgeEntity> edges7 = graphTemplate.getEdgesById(otavio.getId(), Direction.BOTH, "reads");
Collection<EdgeEntity> edges8 = graphTemplate.getEdgesById(otavio.getId(), Direction.BOTH, () -> "likes");
Collection<EdgeEntity> edges9 = graphTemplate.getEdgesById(otavio.getId(), Direction.OUT);
Collection<EdgeEntity> edges10 = graphTemplate.getEdgesById(cleanCode.getId(), Direction.IN);

Graph Queries Improvements

There's an advance in the graph queries in this version such as for define order, predicate, loop resource.

Order:

Stream<EdgeEntity> edges1 = graphTemplate.getTraversalEdge().has(property)
                .orderBy(property).desc().stream();

Stream<EdgeEntity> edges2 = graphTemplate.getTraversalEdge().has(property)
                .orderBy(property).asc().stream();

Stream<Book> books1 = graphTemplate.getTraversalVertex().hasLabel(Book.class)
                .has(property).orderBy(property).desc().stream();

Stream<Book> books2 = graphTemplate.getTraversalVertex().hasLabel(Book.class)
                .has(property).orderBy(property).asc().stream();

Filter:

  long count = graphTemplate.getTraversalVertex()
                .hasLabel(Person.class).filter(Person::isAdult).count();

  EdgeEntity reads=//instance;
  long count = graphTemplate.getTraversalEdge().filter(reads::equals).count();

Pagination:

List<Person> people = graphTemplate.getTraversalVertex().limit(2).<Person>stream()
                .collect(toList());//limit by 2 elements

List<Person> people = graphTemplate.getTraversalVertex().range(1,3).<Person>stream()
                .collect(toList());//a range of one inclusive and three exclusive

Loop:

In the graph query, there're two ways to make a loop; the first one defines times to repeat an operation and repeats the process until the condition is accurate.

        Animal lion = graphTemplate.insert(new Animal("lion"));
        Animal snake = graphTemplate.insert(new Animal("snake"));
        Animal mouse = graphTemplate.insert(new Animal("mouse"));
        Animal plant = graphTemplate.insert(new Animal("plant"));

        graphTemplate.edge(lion, "eats", snake);
        graphTemplate.edge(snake, "eats", mouse);
        graphTemplate.edge(mouse, "eats", plant);

        Optional<Animal> topAnimal = graphTemplate.getTraversalVertex()
          .repeat().in("eats").times(3).<Animal>next();
        Optional<Animal> plantResult = graphTemplate
                .getTraversalVertex()
                .repeat().out("eats")
                .until().has("name", "plant").next();

What's Next?

The next step is to submit this as standard in the Java world through the JSR. The community effort is significant at this stage, so now is the opportunity to join the email list and also support this JSR.

References

Compliant Database DevOps and the role of DevSecOps DevOps is becoming the new normal in application development, and DevSecOps is now entering the picture. By balancing the desire to release code faster with the need for the same code to be secure, it addresses increasing demands for data privacy. But what about the database? How can databases be included in both DevOps and DevSecOps? What additional measures should be considered to achieve truly compliant database DevOps? This whitepaper provides a valuable insight. Get the whitepaper

Topics:
jnosql ,nosql ,eclipse ,javaee ,database ,tutorial

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}