Logo of JNoSQL: image of Duke, Java's cartoon mascot, with a bow and arrow pointing to the right

The Eclipse JNoSQL is a framework to help developers create enterprise-grade applications using Java and NoSQL technologies. It helps them create scalable applications while maintaining low coupling with the underlying NoSQL technology.

View on GitHub

Minimum requirements

  • Java 8 (or higher)
  • CDI implementation e.g.: Weld
  • Bean Validation implementation e.g.: Hibernate Validator (optional, needed when enabling Bean Validation)
  • JSON-B implementation e.g.: Eclipse Yasson When it needs JSON binding to either read a JSON configuration's file, or it needs to serialize or deserialize values to a database implementation.

Starting with Key-Value

Add the Eclipse JNoSQL Artemis dependency

<dependency>
   <groupId>org.jnosql.artemis</groupId>
   <artifactId>artemis-core</artifactId>
   <version>version</version>
</dependency>

Add a key-value vendor. e.g:

<dependency>
   <groupId>org.jnosql.diana</groupId>
   <artifactId>hazelcast-driver</artifactId>
   <version>version</version>
</dependency>

Use annotation to define both the Id and the entity name, same as JPA.

@Entity
public class User implements Serializable {

  @Id
  private String userName;

  private String name;

  private List<String> phones;
  //Getters and setters are not required.
  //However, the class must have a non-private constructor with no arguments.
}

Create an eligible BucketManager using the Producer methods in BucketManager.

@ApplicationScoped
public class BucketManagerProducer {

  private static final String BUCKET = "developers";

  private KeyValueConfiguration configuration;

  private BucketManagerFactory managerFactory;

  @PostConstruct
  public void init() {
    configuration = new HazelCastKeyValueConfiguration();
    Map<String, Object> settings = singletonMap("hazelcast-instanceName", "hazelcast");
    managerFactory = configuration.get(Settings.of(settings));
  }

  @Produces
  public BucketManager getManager() {
    return managerFactory.getBucketManager(BUCKET);
  }
}

That's it! Now you're ready to go with CDI and a Key-Value NoSQL database.

public class App {

  private static final User USER = User.builder().
  withPhones(Arrays.asList("234", "432"))
  .withUsername("username")
  .withName("Name")
  .build();

  public static void main(String[] args) {

    try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
      KeyValueTemplate keyValueTemplate = container.select(KeyValueTemplate.class).get();
      User userSaved = keyValueTemplate.put(USER);
      System.out.println("User saved: " + userSaved);
      Optional<User> user = keyValueTemplate.get("username", User.class);
      System.out.println("Entity found: " + user);
    }
  }

  private App() {
  }
}


public class UserService {

  @Inject
  private KeyValueTemplate template;


  public User put(User user) {
    return template.put(user);
  }

  public Optional<User> find(String id) {
    return template.get(id, User.class);
  }
}

Create your own repository

public interface UserRepository extends Repository<User, String> {}

Don't worry about the implementation, Eclipse JNoSQL will handle that for you.

public class App2 {

  private static final User USER = User.builder().
  withPhones(Arrays.asList("234", "432"))
  .withUsername("username")
  .withName("Name")
  .build();

  public static void main(String[] args) {

    try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {

      UserRepository repository = container.select(UserRepository.class, DatabaseQualifier.ofKeyValue()).get();
      repository.save(USER);
      Optionaly<User> user = repository.findById("username");
      System.out.println("User found: " + user);
      System.out.println("The user found: " + repository.existsById("username"));
    }
  }

  private App2() {
  }
}


public class UserService {

  @Inject
  @Database(DatabaseType.KEY_VALUE)
  private UserRepository repository;


  public User save(User user) {
    return repository.save(user);
  }

  public Optional<User> find(String id) {
    return repository.findById(id);
  }
}

Starting with Column

Add the Eclipse JNoSQL Artemis dependency

<dependency>
   <groupId>org.jnosql.artemis</groupId>
   <artifactId>artemis-column</artifactId>
   <version>version</version>
</dependency>

Choose any column vendor. e.g:

<dependency>
   <groupId>org.jnosql.diana</groupId>
   <artifactId>cassandra-driver</artifactId>
   <version>version</version>
</dependency>

Use annotation to define both the Id and the entity name, same as JPA. Note that here you'll need to also define what values are stored in columns with @Column annotations.

@Entity("Person")
public class Person {

  @Id("id")
  private long id;

  @Column
  private String name;

  @Column
  private List<String> phones;
  //Getters and setters are not required.
  //However, the class must have a non-private constructor with no arguments.
}

Make an eligible ColumnFamilyManager using the Producer methods in 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);
  }

}



That's it, you're ready to go with CDI and a Column NoSQL database.

public class App {

  private static final Person PERSON = Person.builder().
  withPhones(Arrays.asList("234", "432"))
  .withName("Name")
  .withId(1)
  .withIgnore("Just Ignore").build();

  public static void main(String[] args) {

    try(SeContainer container = SeContainerInitializer.newInstance().initialize()) {
      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);

    }
  }

  private App() {
  }
}



public class PersonService {

  @Inject
  private ColumnTemplate template;


  public Person insert(Person person) {
    return template.insert(person);
  }

  public Optional<Person> find(Long id) {
    ColumnQuery query = select().from("Person").where("id").eq(id).build();
    return template.singleResult(query);
  }
}

Create your own repository

public interface PersonRepository extends Repository<Person, Long> {}

Don't worry about the implementation, Eclipse JNoSQL will handle that for you.

public class App2 {

  private static final Person PERSON = Person.builder().
  withPhones(Arrays.asList("234", "432"))
  .withName("Name")
  .withId(1)
  .build();

  public static void main(String[] args) {

    try(SeContainer container = SeContainerInitializer.newInstance().initialize()) {
      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);

    }
  }

  private App2() {
  }
}


public class PersonService {

  @Inject
  @Database(DatabaseType.COLUMN)
  private PersonRepository repository;


  public Person save(Person person) {
    return repository.save(person);
  }

  public Optional<Person> find(Long id) {
    return repository.findById(id);
  }
}

Starting with Document

Add the Eclipse JNoSQL Artemis dependency

<dependency>
   <groupId>org.jnosql.artemis</groupId>
   <artifactId>artemis-document</artifactId>
   <version>version</version>
</dependency>

Choose any document vendor. e.g:

<dependency>
   <groupId>org.jnosql.diana</groupId>
   <artifactId>mongodb-driver</artifactId>
   <version>version</version>
</dependency>

Use annotation to define Id, Entity name and Columns to store, like in JPA.

@Entity("Person")
public class Person {

  @Id("id")
  private long id;

  @Column
  private String name;

  @Column
  private Address address;

  @Column
  private List<String> phones;
  //Getters and setters are not required.
  //However, the class must have a non-private constructor with no parameters.
}


@Embeddable
public class Address {

  @Column
  private String street;

  @Column
  private String city;

  @Column
  private Integer number;

}

Make an eligible DocumentCollectionManager using the Producer methods in 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);

  }

}


That's it, you are ready to go with CDI and a Document NoSQL Database.

public class App {


  public static void main(String[] args) {

    Random random = new Random();
    Long id = random.nextLong();
    try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {

      Person person = Person.builder().
      withPhones(Arrays.asList("234", "432"))
      .withName("Name")
      .withId(id)
      .build();

      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);

    }
  }

  private App() {
  }
}


public class PersonService {

  @Inject
  private DocumentTemplate template;


  public Person insert(Person person) {
    return template.insert(person);
  }

  public Optional<Person> find(Long id) {
    DocumentQuery query = select().from("Person").where("id").eq(id).build();
    return template.singleResult(query);
  }
}

Create your own repository

public interface PersonRepository extends Repository<Person, Long> {

  List<Person> findByName(String name);

  Stream<Person> findByPhones(String phone);
}

Don't worry about the implementation, Eclipse JNoSQL will handle that for you.

public class App2 {


  public static void main(String[] args) {

    Random random = new Random();
    Long id = random.nextLong();

    try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {

      Person person = Person.builder().
      withPhones(Arrays.asList("234", "432"))
      .withName("Name")
      .withId(id)
      .build();

      PersonRepository repository = container.select(PersonRepository.class)
      .select(DatabaseQualifier.ofDocument()).get();
      repository.save(person);

      List<Person> people = repository.findByName("Name");
      System.out.println("Entity found: " + people);
      repository.findByPhones("234").forEach(System.out::println);

    }
  }

  private App2() {
  }
}



public class PersonService {

  @Inject
  @Database(DatabaseType.DOCUMENT)
  private PersonRepository repository;


  public Person save(Person person) {
    return repository.save(person);
  }

  public Optional<Person> find(Long id) {
    return repository.findById(id);
  }
}

Starting with Graph

Add the Eclipse JNoSQL Artemis dependency

<dependency>
   <groupId>org.jnosql.artemis</groupId>
   <artifactId>artemis-graph</artifactId>
   <version>version</version>
</dependency>

Choose any graph with TinkerPop support, e.g:

<dependency>
   <groupId>org.apache.tinkerpop</groupId>
   <artifactId>gremlin-core</artifactId>
   <version>version</version>
<dependency>
<dependency>
   <groupId>org.apache.tinkerpop</groupId>
   <artifactId>gremlin-groovy</artifactId>
   <version>version</version>
<dependency>
<dependency>
   <groupId>org.janusgraph</groupId>
   <artifactId>janusgraph-core</artifactId>
   <version>version</version>
<dependency>
<dependency>
   <groupId>org.janusgraph</groupId>
   <artifactId>janusgraph-berkeleyje</artifactId>
   <version>version</version>
<dependency>
<dependency>
   <groupId>org.janusgraph</groupId>
   <artifactId>janusgraph-lucene</artifactId>
   <version>version</version>
<dependency>

Use annotations to define the Id, the Column fields and the Entity name, like in JPA.

@Entity
public class Person {

  @Id
  private Long id;

  @Column
  private String name;

  @Column
  private int age;

  @Column
  private String occupation;

  @Column
  private Double salary;
  //Getters and setters are not required.
  //However, the class must have a non-private constructor with no parameters.
}

Make an eligible Graph using the @Produces method.

@ApplicationScoped
public class GraphProducer {

  private static final String FILE_CONF = "conf/janusgraph-berkeleyje-lucene.properties";

  private Graph graph;


  @PostConstruct
  public void init() {
    JanusGraph janusGraph = JanusGraphFactory.open(FILE_CONF);
    GraphTraversalSource g = janusGraph.traversal();
    if (g.V().count().next() == 0) {
      GraphOfTheGodsFactory.load(janusGraph);
    }
    this.graph = janusGraph;
  }

  @Produces
  @ApplicationScoped
  public Graph getGraph() {
    return graph;
  }

  public void close(@Disposes Graph graph) throws Exception {
    graph.close();
  }
}




That's it, you are ready to go with CDI and a Graph NoSQL database.

public final class MarketingApp {


  private MarketingApp() {
  }


  public static void main(String[] args) {

    try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
      GraphTemplate graph = container.select(GraphTemplate.class).get();

      Person banner = graph.insert(builder().withAge(30).withName("Banner")
      .withOccupation("Developer").withSalary(3_000D).build());

      Person natalia = graph.insert(builder().withAge(32).withName("Natalia")
      .withOccupation("Developer").withSalary(5_000D).build());

      Person rose = graph.insert(builder().withAge(40).withName("Rose")
      .withOccupation("Design").withSalary(1_000D).build());

      Person tony = graph.insert(builder().withAge(22).withName("tony")
      .withOccupation("Developer").withSalary(4_500D).build());


      graph.edge(tony, "knows", rose).add("feel", "love");
      graph.edge(tony, "knows", natalia);

      graph.edge(natalia, "knows", rose);
      graph.edge(banner, "knows", rose);

      List<Person> developers = graph.getTraversalVertex()
      .has("salary", gte(3_000D))
      .has("age", between(20, 25))
      .has("occupation", "Developer")
      .<Person>stream().collect(toList());

      List<Person> peopleWhoDeveloperKnows = graph.getTraversalVertex()
      .has("salary", gte(3_000D))
      .has("age", between(20, 25))
      .has("occupation", "Developer")
      .out("knows")
      .<Person>stream().collect(toList());

      List<Person> both = graph.getTraversalVertex()
      .has("salary", gte(3_000D))
      .has("age", between(20, 25))
      .has("occupation", "Developer")
      .outE("knows")
      .bothV()
      .<Person>stream()
      .distinct()
      .collect(toList());

      List<Person> couple = graph.getTraversalVertex()
      .has("salary", gte(3_000D))
      .has("age", between(20, 25))
      .has("occupation", "Developer")
      .outE("knows")
      .has("feel", "love")
      .bothV()
      .<Person>stream()
      .distinct()
      .collect(toList());

      System.out.println("Developers has salary greater than 3000 and age between 20 and 25: " + developers);
      System.out.println("Person who the Developers target know: " + peopleWhoDeveloperKnows);
      System.out.println("The person and the developers target: " + both);
      System.out.println("Developers to Valentine days: " + couple);

    }
  }

}



public class PersonService {

  @Inject
  private GraphTemplate template;


  public Person insert(Person person) {
    return template.insert(person);
  }

  public Optional<Person> find(Long id) {
    return template.find(id);
  }
  public EdgeEntity<Person, Person> meet(Person personA, Person personB) {
    return template.edge(personA, "knows", personB);
  }
}

Create your own repository

public interface PersonRepository extends Repository<Person, Long> {

  Stream<Person> findByOccupationAndSalaryGreaterThan(String ocuppation, Double salary);

  Stream<Person> findByAgeBetween(Integer ageA, Integer ageB);
}

Don't worry about the implementation, Eclipse JNoSQL will handle that for you.

public final class MarketingApp2 {


  private MarketingApp2() {
  }


  public static void main(String[] args) {

    try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
      PersonRepository repository = container.select(PersonRepository.class, DatabaseQualifier.ofGraph()).get();

      Person banner = repository.save(builder().withAge(30).withName("Banner")
      .withOccupation("Developer").withSalary(3_000D).build());

      Person natalia = repository.save(builder().withAge(32).withName("Natalia")
      .withOccupation("Developer").withSalary(5_000D).build());

      Person rose = repository.save(builder().withAge(40).withName("Rose")
      .withOccupation("Design").withSalary(1_000D).build());

      Person tony = repository.save(builder().withAge(22).withName("tony")
      .withOccupation("Developer").withSalary(4_500D).build());


      System.out.println("findByOccupationAndSalaryGreaterThan");
      repository.findByOccupationAndSalaryGreaterThan("Developer", 3_000D)
      .forEach(System.out::println);
      System.out.println("findByAgeBetween");
      repository.findByAgeBetween(20, 30)
      .forEach(System.out::println);


    }
  }

}


public class PersonService {

  @Inject
  @Database(DatabaseType.GRAPH)
  private PersonRepository repository;


  public Person save(Person person) {
    return repository.save(person);
  }

  public Optional<Person> find(Long id) {
    return repository.findById(id);
  }
}

References