Skip to main content

Run Cassandra with Spring Data

Posted by otaviojava on August 25, 2013 at 6:05 AM PDT
Spring Data no Cassandra com Easy-Cassandra

Spring is an open source framework whose goals is facilitate the Java developer's life, it began with dependency injection and nowadays works on many plug-ins. Plug-ins such Spring Social, to connects social media like twitter and facebbok, Spring security beyond control inversion. The goal of this post is talk about Spring Data working with Cassandra.

Spring Data does part of Spring plug-in, it has as objective do a high level among a data base and Java application. This way, you can use POJO for persist in many kind of data bases.

  • RMDB with JPA and JDBC
  • BigData with Apache Hadoop
  • Data-Grid with GermFire
  • HTTP with Rest
  • NOSQL with MongoDB, Neo4J, Redis and Hbase

The main advantage of Spring data does part of Spring, it may run without Java EE server, it can run a simple container such tomcat or outside of a server. Its dependency injection works together of XML file, but, unlike some developers think, you may use annotations to help, however, you should know when use xml or annotation.

So Spring Data with Cassandra has as objective do a high level layer to NOSQL Cassandra, with POJO structured can do CRUD operations. The Spring Data Cassandra has not launched, but Easy-cassandra has integration with Spring, now you can use Cassandra with most popular frameworks around world.

The application will really simple, it does put information and retrieve by id. Firstly, make the Person entity, our POJO.


@Entity(name = "person") 
public class Person implements Serializable {

    @Id
    private UUID id;
    
    @Index
    @Column(name = "name")
    private String name;
   
    @Column(name = "born")
    private Integer year;
//getter and setter

}

POJO entity Peron


How you can see, the entity had mapped by JPA 20, secondly is configuration with XML file, within has information of Cassandra Base (base, port, default keySpace) is our connections factory Cassandra inside Spring, also was included the mapped class.

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/context
          http://www.springframework.org/schema/context/spring-context-3.0.xsd
          http://www.springframework.org/schema/beans
          <context:component-scan" title="http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<context:component-scan">http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
&...
base-package="org.javabahia.cassandra.spring" />
<bean id = "clusterInformation" class="org.easycassandra.persistence.cassandra.ClusterInformation">
<property name="keySpace" value="consegi" />
<property name="hosts">
<list>
<value>localhost</value>
</list>
</property>
</bean>
<bean id="cassandraFactory" class="org.easycassandra.persistence.cassandra.spring.CassandraFactoryAnnotation"
<constructor-arg name="clusterInformation" value="clusterInformation" />
<property name="annotatedClasses">
<list>
<value>org.javabahia.cassandra.spring.entity.Person</value>
</list>
</property>
</bean>

Spring Data configuration, that informs configurations of Cassandra (name of host, number of port, default keyspace and mapped class) beyond Cassandra's Template.


With Cassandra connections factory may return a session, the bridge among Cassandra and Easy-cassandra, also will create CassandraTemplase, it an api to do simple operations on Cassandra..

public interface CassandraTemplate{ 

    <T> T save(T entity);
   
    <T> Iterable<T> save(Iterable<T> entities);
   
    <T> void delete(T entity);
   
    <T> void delete(Iterable<T> entities);
   
    <K> void delete(K key, Class<?> entity);
   
    <K,T> void delete(Iterable<K>  keys, Class<T> entity);

    <T> void deleteAll(Class<T> entity);
   
    <T> T update(T entity);
   
    <T> Iterable<T> update(Iterable<T> entities);
   
    <T,K> T findOne(K key, Class<T> entity);
   
    <T,K> List<T> findAll(Iterable<K> keys, Class<T> entity);
   
    <T> List<T> findAll(Class<T> entity);
   
    <T,I> List<T> findByIndex(String columnName,I index,Class<T> entity);
   
    <K,T>boolean exist(K key, Class<T> entity);

    void executeUpdate(String query);

CassandraTemplase's operations


Also there is CassandraReposiroty, this abstract class implements CrudRepository of SpringData, to use it is necessary implement the method which returns CassandraTemplate.

@Repository("personRepository")
public class PersonRepository extends CassandraRepository<Person, UUID>{


@Autowired
private CassandraTemplate cassandraTemplate;

@Override
protected CassandraTemplate getCassandraTemplate() {
return cassandraTemplate;
}

}

PersonRepository with CassandraRepository


Whereby CassandraRepository implements the base of persistence on Spring Data, consequently, is available use this operations on Cassandra.

public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> { 
<S extends T> S save(S entity);

<S extends T> Iterable<S> save(Iterable<S> entities);

T findOne(ID id);

boolean exists(ID id);

Iterable<T> findAll();

Iterable<T> findAll(Iterable<ID> ids);

long count();

void delete(ID id);

void delete(T entity);
void delete(Iterable<? extends T> entities);

void deleteAll();
}

CrudRepository's Interface of Spring Data


Finally run this project.

public class App 
{
    public static void main( String[] args )
    {
    @SuppressWarnings("resource")
ApplicationContext ctx = new GenericXmlApplicationContext("SpringConfig.xml");
   
    PersonRepository personService=ctx.getBean(PersonRepository.class);
   
    UUID uuid=UUID.randomUUID();
    Person person=new Person();
    person.setId(uuid);
    person.setName("Otávio Santana");
    person.setYear(25);
   
    personService.save(person);
   
   
    Person otavio=personService.findOne(uuid);
    System.out.println(otavio.getName());
   
   
    }
}

Run a simple project, save and retrieve the object.


Concluding, was demonstrated concern about Spring Data how it works with Cassandra using Easy-Cassandra. Spring Data, absolutely, is a big tool to development with many data bases, thereby you can use types of databases with less effort, perhaps with just CRUDRepository interface. despite that a Java developer must know the impacts when change to another information center, that includes modeling.



Links:

Spring Data: http://www.springsource.org/spring-data
Easy-Cassandra: http://otaviojava.github.io/Easy-Cassandra/
Exemplo: https://github.com/otaviojava/Easy-Cassandra-samples

Comments

What is the default port number to connect ...

What is the default port number to connect cassandraDB?

Caused by: com.datastax.driver.core.exceptions.NoHostAvailableException: All host(s) tried for query failed (tried: localhost/127.0.0.1 (com.datastax.driver.core.ConnectionException: [localhost/127.0.0.1] Unexpected error during transport initialization (com.datastax.driver.core.TransportException: [localhost/127.0.0.1] Channel has been closed)))
...
bean id="cassandraFactory" class="org.easycassandra.persistence.cassandra.spring.CassandraFactoryAnnotation">
constructor-arg name="host" value="localhost" />
constructor-arg name="port" value="7000" />

the default port in Cassandra is: 9042

the default port in Cassandra is: 9042

Person Entity class with collection datatype package ...

Person Entity class with collection datatype

package org.javabahia.cassandra.spring.entity;

import java.io.Serializable;
import java.util.Map;
import java.util.UUID;

import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.Id;

import org.easycassandra.Index;

/**
*
* @author otavio
*/
@Entity(name = "person")
public class Person implements Serializable {

private static final long serialVersionUID = 3L;

@Id
private UUID id;

@Index
@Column(name = "name")
private String name;

@Column(name = "born")
private Integer year;

/**
* @return the propertyKeys
*/

public Map getPropertyKeys() {
return propertyKeys;
}

/**
* @param propertyKeys the propertyKeys to set
*/
public void setPropertyKeys(Map propertyKeys) {
this.propertyKeys = propertyKeys;
}

@ElementCollection
@Column(name="propertyKeys")
private Map propertyKeys;

public UUID getId() {
return id;
}

public void setId(UUID id) {
this.id = id;
}

public Integer getYear() {
return year;
}

public void setYear(Integer year) {
this.year = year;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}

}

Thank for your question on next version will have ...

Thank for your question on next version will have @ElementCollection as annotation but it does not implemented yet.

When you will use some collection you should ...

When you will use some collection you should use:

  • @MapData to java.util.Map
  • @ListData to java.util.List
  • @SetData to java.util.Set

You can get more information about collections here:
http://goo.gl/0oSTWQ

More about the project and wike here:
https://github.com/otaviojava/Easy-Cassandra/wiki

Thanks for your reply.

Thanks for your reply.

this improvement had done on version 2.0.0-RC9. Now you can ...

this improvement had done on version 2.0.0-RC9.
Now you can use @ElementCollection to java.util.List, java.util.Set and java.util.Map.

Thank you very much . Can u please give me a sample for ...

Thank you very much .

Can u please give me a sample for executing query with cassandra as below mongo with spring.

Query query = new Query();
uery.addCriteria(Criteria.where("userPID").is(id));
List receipt=mongoOps.find(query, Receipt.class, getMyCollection(Receipt.class));
return receipt;

Now you can use the SelectBuilder, it is a simple way to use ...

Now you can use the SelectBuilder, it is a simple way to use query with Easy-Cassandra.
https://github.com/otaviojava/Easy-Cassandra/wiki/Select-Builder

This version will be realese on 2.1.0 version.

Comming soon, to know more about Builders.
https://github.com/otaviojava/Easy-Cassandra/wiki/Builders

on Cassandra queries are very poorer than Mongodb, so you ...

on Cassandra queries are very poorer than Mongodb, so you can find by key or index with consistency level and you have methods: http://goo.gl/FaM1J4

Ok fine , then How i can find a row by following date range ...

Ok fine , then How i can find a row by following date range as http://cassandra.apache.org/doc/cql3/CQL.html#selectStmt

you can inject the factory and use the getSession()'s method ...

you can inject the factory and use the getSession()'s method with this session you can execute native methods to Cassandra, for this use the execute method.
More information here: http://www.datastax.com/drivers/java/2.0/apidocs/com/datastax/driver/cor...

But comming soon will have range on the query.

when i use an collection datatype as a field it show the ...

when i use an collection datatype as a field it show the following error

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cassandraFactory' defined in ServletContext resource [/WEB-INF/classes/spring-security.xml]: Invocation of init method failed; nested exception is com.datastax.driver.core.exceptions.SyntaxError: line 1:37 mismatched input ';' expecting '<'
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1455)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:605)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:925)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:472)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:383)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:283)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:111)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4206)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4705)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:799)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:779)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:601)
at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:675)
at org.apache.catalina.startup.HostConfig.deployDescriptors(HostConfig.java:601)
at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:502)
at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1317)
at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:324)
at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:142)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1065)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:840)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:463)
at org.apache.catalina.core.StandardService.start(StandardService.java:525)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:754)
at org.apache.catalina.startup.Catalina.start(Catalina.java:595)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
Caused by: com.datastax.driver.core.exceptions.SyntaxError: line 1:37 mismatched input ';' expecting '<'
at com.datastax.driver.core.exceptions.SyntaxError.copy(SyntaxError.java:35)
at com.datastax.driver.core.ResultSetFuture.extractCauseFromExecutionException(ResultSetFuture.java:269)
at com.datastax.driver.core.ResultSetFuture.getUninterruptibly(ResultSetFuture.java:183)
at com.datastax.driver.core.Session.execute(Session.java:111)
at com.datastax.driver.core.Session.execute(Session.java:80)
at org.easycassandra.persistence.cassandra.FixColumnFamily.executeAlterTableAdd(FixColumnFamily.java:137)
at org.easycassandra.persistence.cassandra.FixColumnFamily.verifyRow(FixColumnFamily.java:105)
at org.easycassandra.persistence.cassandra.FixColumnFamily.verifyRowType(FixColumnFamily.java:81)
at org.easycassandra.persistence.cassandra.FixColumnFamily.verifyColumnFamily(FixColumnFamily.java:55)
at org.easycassandra.persistence.cassandra.AbstractCassandraFactory.fixColumnFamily(AbstractCassandraFactory.java:87)
at org.easycassandra.persistence.cassandra.spring.CassandraFactoryAnnotation.mappedBean(CassandraFactoryAnnotation.java:62)
at org.easycassandra.persistence.cassandra.spring.CassandraFactoryAnnotation.afterPropertiesSet(CassandraFactoryAnnotation.java:46)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1514)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1452)
... 36 more



org.javabahia.cassandra.spring.entity.Person

Please revert me with sample using the collection datatype or give me a solution for this error.