I am currently working on an API implementation in Java with spring and hibernate.
I have two tables in my Model package
User and UserDetail which has a OneToMany mapping
#Entity
public class User {
private Long id;
private String userId;
private Set<UserDetail> userDetails;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "user")
public Set<UserDetail> getUserDetails() {
return userDetails;
}
public void setUserDetail(Set<UserDetail> userDetails) {
this.userDetails = userDetails;
}
}
#Entity
public class User {
private Long id;
private String key;
private String value;
private User user;
#ManyToOne
#JoinColumn(name = "USER_ID", nullable = false)
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
My API looks like this
#Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
public void addUserDetail(AddUserDetailRequest request) {
//... adds the user detail for the userId as request.getUserId()
}
#Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
public void deleteUserDetail(DeleteUserDetailRequest request) {
//... deletes a particular value for a user with userId as request.getUserId() and userDetail key as request.getDeleteKey()
}
I have written Junit test cases to test the addition and deletion of UserDetails for a user, My addUserDetail is working as it should, but when I call the delete the changes are not reflected and they fail.
Below is my test case
#Test
public void testDeletUserDetail() throws Exception {
//GIVEN
String userId = client.newUser().call(getCreateUserRequest()).getId();
client.newAddUserDetail().call(getAddUserDetailRequest(userId, "key1", "value1"));
client.newAddUserDetail().call(getAddUserDetailRequest(userId, "key2", "value2"));
//WHEN
client.newDeteteUserDetail().call(getDeleteUserDetailRequest(userId, "key2"));
//THEN
List<UserDetail> userDetails = client.newGetUserDetail().call(getGetUserDetailRequest(userId));
assertEquals(userDetails.size(), 1); // This check fails and says it has a size of 2 instead of 1.
}
I am using HSQL for testing purposes
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.iiitd.myAPI.model" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="HSQL" />
<property name="generateDdl" value="true" />
<property name="showSql" value="false" />
</bean>
</property>
</bean>
<jdbc:embedded-database id="dataSource" type="HSQL" />
I have two implementation for deleteUserDetail and one of them fails.
// This one works in both jUnit and manual testing
#Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
public void deleteUserDetail(DeleteUserDetailRequest request) {
User user = userRepository.findByUserId(request.getUserId());
if(!CollectionUtils.isEmpty(user.getUserDetail())) {
UserDetail toRemove = null;
for(UserDetail userDetail : user.getUserDetail()) {
if(StringUtils.equals(userDetail.getKey(), request.getDeleteKey())) {
toRemove = userDetail;
}
}
Assert.notNull(toRemove, "Detail user doesn't exist.");
user.getUserDetail().remove(toRemove);
userRepository.save(user);
}
}
//This one doesn't and unit tests fails but manual tests are OK
#Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
public void deleteUserDetail(DeleteUserDetailRequest request) {
UserDetail userDetail = userDetailRepository.getUserDetail();
Assert.notNull(userDetail, "Detail doesn't exists");
userDetailRepository.delete(userDetail);
}
All the repositories extends JpaRepository
Could anyone explain how to circumvent this issue ?
Any help would be appreciated.
Related
I am using Hibernate as an ORM for a Spring Boot Application to write values to my Postgres Database.I have configured the properties in my persistence.xml
Persistence.xml
<property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/ImageHoster" />
<property name="javax.persistence.jdbc.user" value="postgres" />
<property name="javax.persistence.jdbc.password" value="postgres" />
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL82Dialect" />
<property name="hibernate.temp.use_jdbc_metadata_defaults" value="false"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
</properties>
I have created an entity called Movie
Movie
#Entity
#Table(name = "Movie")
public class Movie {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
public String id;
#Column(name = "movie")
public String movie;
#Column(name = "updatedDate")
public Date updatedDate;
#Lob
#Column(name = "image")
public String image;
public String getMovie() {
return movie;
}
public void setMovie(String movie) {
this.movie = movie;
}
public Date getUpdatedDate() {
return updatedDate;
}
public void setUpdatedDate(Date updatedDate) {
this.updatedDate = updatedDate;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
}
At the first time when there is no movie table in my postgres database the table is getting created and there is no error.But as i am running the application once the table is created it is trying to create the table again which is causing the below error
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL via JDBC Statement.
My Configuration for the JPA goes like this
JPAConfig
#Configuration
public class JpaConfig {
#Bean
public EntityManagerFactory entityManagerFactory(){
LocalContainerEntityManagerFactoryBean emf =new LocalContainerEntityManagerFactoryBean();
emf.setPersistenceXmlLocation("classpath:META-INF/persistence.xml");
emf.afterPropertiesSet();
return emf.getObject();
}
#Bean
public DataSource dataSource(){
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("org.postgresql.Driver");
ds.setUrl("jdbc:postgresql://localhost:5432/ImageHoster");
ds.setUsername("postgres");
ds.setPassword("postgres");
return ds;
}
}
Any idea where i am going wrong as I have another entity called User which is working fine and is not getting created everytime the application runs.
Once i changed the table name from Movie to movie in my entity everything was working as expected.
#Entity
#Table(name = "movie"){
}
This made everything fine..any idea why this happened? as i am not able to understand why it is a problem.
I wrote my own SpringSecurity UserDetailsService. I used this tutorial for it.
The only differents between my configuration and that tutorial is, that I have a xml file for spring framework. But my application didn't work:
The problem is, that userDao.load(email); (watch UserDetailsService below) returns null and not an userObject. But if I switch the configuration of SpringSecurity to an inMemoryAuthentication and use userDao.load(email); in another context, the service returns the right user.
Stacktrace:
SCHWERWIEGEND: An internal error occurred while trying to authenticate the user.
org.springframework.security.authentication.InternalAuthenticationServiceException: Could not obtain transaction-synchronized Session for current thread
at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:110)
at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:132)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:177)
at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:211)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:506)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:537)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1081)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:658)
at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1566)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1523)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)
Caused by: org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:134)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1014)
at de.nak.cars.dao.UserDAO.load(UserDAO.java:61)
at de.nak.cars.service.impl.UserDetailsServiceImpl.loadUserByUsername(UserDetailsServiceImpl.java:34)
at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:102)
... 39 more
UserDetailsService:
#Component
#Qualifier("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {
#Autowired
private UserDAO userDao;
#Transactional(readOnly=true)
#Override
public UserDetails loadUserByUsername(final String email)
throws UsernameNotFoundException {
de.name.cars.model.User user = userDao.load(email); //load returns null, saw in debug mode
List<GrantedAuthority> authorities = buildUserAuthority(user.getRoles());
return buildUserForAuthentication(user, authorities);
}
private UserDetails buildUserForAuthentication(de.name.cars.model.User user,
List<GrantedAuthority> authorities) {
return new User(user.getEmail(), user.getPassword(), true, true, true, true, authorities);
}
private List<GrantedAuthority> buildUserAuthority(Set<UserRole> roles) {
Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();
for (UserRole role : roles){
setAuths.add(new SimpleGrantedAuthority(role.getRoleName()));
}
List<GrantedAuthority> result = new ArrayList<GrantedAuthority>(setAuths);
return result;
}
}
spring-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="de.nak.cars" />
<!-- The data source -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="org.h2.Driver"/>
<property name="url"
value="jdbc:h2:Y:/db/nak"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
<!-- The session factory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="de.nak.cars.model"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.H2Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.hbm2ddl.import_files">initial-sql.sql</prop>
</props>
</property>
</bean>
<!-- The transaction manager -->
<bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- The advice -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- The pointcut definition -->
<aop:config>
<aop:pointcut id="serviceMethods" expression="execution(* de.nak.cars.service.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethods"/>
</aop:config>
</beans>
User.java
#Entity
public class User implements Serializable {
/** Generated version id. */
private static final long serialVersionUID = -5464675373969471720L;
/** The identifier. */
private Long id;
/** The user's firstname. */
private String firstName;
/** The user's lastname. */
private String lastName;
/** The user's student identification number. */
private String email;
/** The user's roles. */
private Set<UserRole> roles;
/** The user's password. */
private String password;
/** Set of user-exam combinations. */
private Set<ExamKey> examKeys = new HashSet<ExamKey>(0);
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "FIRST_NAME", length = 100, nullable = false)
public String getFirstname() {
return firstName;
}
public void setFirstname(String firstName) {
this.firstName = firstName;
}
#Column(name = "LAST_NAME", length = 100, nullable = false)
public String getlastName() {
return lastName;
}
public void setlastName(String lastName) {
this.lastName = lastName;
}
#ManyToMany(fetch = FetchType.LAZY, cascade= CascadeType.ALL)
#JoinTable(name="USER_USERROLE", joinColumns = {
#JoinColumn(name="USER_ID", nullable = false, updatable = false)},
inverseJoinColumns = { #JoinColumn(name="ROLE_ID", nullable = false, updatable = false)})
public Set<UserRole> getRoles() {
return roles;
}
public void setRoles(Set<UserRole> roles) {
this.roles = roles;
}
#Column(name = "EMAIL", nullable = false, unique = true)
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#Column(name="PASSWORD", nullable = false)
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "examKeyId.user")
public Set<ExamKey> getExamKeys() {
return examKeys;
}
public void setExamKeys(Set<ExamKey> examKeys) {
this.examKeys = examKeys;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((firstName == null) ? 0 : firstName.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result
+ ((lastName == null) ? 0 : lastName.hashCode());
result = prime * result + ((lastName == null) ? 0 : email.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;
User other = (User) obj;
if (firstName == null) {
if (other.firstName != null)
return false;
} else if (!firstName.equals(other.firstName))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (lastName == null) {
if (other.lastName != null)
return false;
} else if (!lastName.equals(other.lastName))
return false;
if (!email.equals(other.email))
return false;
return true;
}
#Override
public String toString() {
return "User [id=" + id + ", firstName=" + firstName + ", lastName="
+ lastName + ", email=" + email + ", password=" + password + ", examKeys=" + examKeys
+ "]";
}
}
you need to enable transaction management support. In the guide you followed it was done with #EnableTransactionManagement annotation over AppConfig class. In your case you use xml configuration, so you should add <tx:annotation-driven transaction-manager="txManager" /> inside your spring-config.xml
I am using spring-data-jpa and JPA repositories
here is my source code
<beans:bean id="producerService" class="cz.services.RepositoryProducerService" />
<jpa:repositories base-package="cz.repository" />
<beans:bean id="myEmf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<beans:property name="dataSource" ref="dataSource" />
<beans:property name="packagesToScan" value="cz.models" />
<beans:property name="jpaVendorAdapter">
<beans:bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</beans:property>
<beans:property name="jpaProperties">
<beans:props>
<beans:prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect
</beans:prop>
<beans:prop key="hibernate.show_sql">true</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
<beans:bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<beans:property name="entityManagerFactory" ref="myEmf" />
</beans:bean>
<beans:bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
<beans:property name="url"
value="jdbc:mysql://localhost:3306/mydb?zeroDateTimeBehavior=convertToNull&characterEncoding=UTF-8" />
<beans:property name="username" value="root" />
<!--<property name="password" value="test" /> -->
<beans:property name="password" value="test"></beans:property>
</beans:bean>
and here is my entity and repository classes:
package cz.models;
import java.io.Serializable;
import javax.persistence.*;
import java.util.List;
/**
* The persistent class for the users database table.
*
*/
#Entity
#Table(name="users")
#NamedQuery(name="User.findAll", query="SELECT u FROM User u")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private int enabled;
private String password;
private String username;
//bi-directional many-to-one association to Authority
#OneToMany(mappedBy="user")
private List<Authority> authorities;
//bi-directional many-to-one association to Room
#OneToMany(mappedBy="user")
private List<Room> rooms;
//bi-directional many-to-one association to UsersData
#OneToMany(mappedBy="user")
private List<UsersData> usersData;
public User() {
}
....
public List<Room> getRooms() {
return this.rooms;
}
and here are User Repository:
public void setRooms(List<Room> rooms) {
this.rooms = rooms;
}
public Room addRoom(Room room) {
getRooms().add(room);
room.setUser(this);
return room;
}
public Room removeRoom(Room room) {
getRooms().remove(room);
room.setUser(null);
return room;
}
public List<UsersData> getUsersData() {
return this.usersData;
}
public void setUsersData(List<UsersData> usersData) {
this.usersData = usersData;
}
public UsersData addUsersData(UsersData usersData) {
getUsersData().add(usersData);
usersData.setUser(this);
return usersData;
}
public UsersData removeUsersData(UsersData usersData) {
getUsersData().remove(usersData);
usersData.setUser(null);
return usersData;
}
}
and userRepository:
public interface UserRepository extends JpaRepository<User, Integer> {
#Transactional
#Query("select u from User u WHERE u.enabled = 1 ")
public List<User> findAllactiveUsers();
#Transactional
#Query("select u from User u WHERE u.username = :username ")
public User findByUsername(#Param("username")String username);
}
and my service for spring security:
#Service
public class MyUserDetailsService implements UserDetailsService {
#Resource
UserRepository repositoryUser;
#Resource
AuthorityRepository repositoryAuthority;
public UserDetails loadUserByUsername(String username) {
System.out.println("start");
cz.models.User userModel = null;
UserDetails userDetail = null;
try{
userModel = repositoryUser.findByUsername(username);
// User user = userModel;
System.out.println(userModel.getUsername());
List<Authority> authorities = repositoryAuthority.findAllByUser(userModel);
// repositoryUserData.findAll();
System.out.println(userModel.getAuthorities().size());
Collection<SimpleGrantedAuthority> collectionAuthorities = new ArrayList<SimpleGrantedAuthority>();
for (int i = 0; i < authorities.size(); i++) {
collectionAuthorities.add(new SimpleGrantedAuthority(authorities
.get(i).getAuthority()));
}
userDetail = new User(userModel.getUsername(),
userModel.getUsername(), collectionAuthorities);
}catch(Exception e){
e.printStackTrace();
}
return userDetail;
}
}
The problem is: when I want call - this peace of code:
userModel.getAuthorities()
which call child (fk in db). I have exception :
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
When I add second repository Authorities I do not have this no session problem. But I do not want create every time method in my repository.
List<Authority> authorities = repositoryAuthority.findAllByUser(userModel);
I have to use hibernate.LazyInitialization instead of eanger.(and some stable)
I saw a lot of post with this problem with JPA, but nothing work for me :(
Use a query that fetches the data you want so that it is there when you need it.
#Query("select u from User u left join fetch u.authorities WHERE u.username = :username ")
public User findByUsernameFetchAuthorities(#Param("username")String username);
Using findByUsernameFetchAuthorities when you want to access the authorities will cause them to be pre-fetched, avoiding the error and keeping them lazily fetched for every other query.
I keep getting the message
java.lang.NoSuchMethodError: org.apache.cassandra.thrift.TBinaryProtocol: method <init>(Lorg/apache/thrift/transport/TTransport;)V not found
at com.impetus.client.cassandra.schemamanager.CassandraSchemaManager.initiateClient(CassandraSchemaManager.java:446)
at com.impetus.kundera.configure.schema.api.AbstractSchemaManager.exportSchema(AbstractSchemaManager.java:101)
at com.impetus.client.cassandra.schemamanager.CassandraSchemaManager.exportSchema(CassandraSchemaManager.java:138)
at com.impetus.kundera.configure.SchemaConfiguration.configure(SchemaConfiguration.java:172)
at com.impetus.kundera.configure.ClientMetadataBuilder.buildClientFactoryMetadata(ClientMetadataBuilder.java:45)
at com.impetus.kundera.persistence.EntityManagerFactoryImpl.configureClientFactories(EntityManagerFactoryImpl.java:352)
at com.impetus.kundera.persistence.EntityManagerFactoryImpl.<init>(EntityManagerFactoryImpl.java:116)
at com.impetus.kundera.KunderaPersistence.createEntityManagerFactory(KunderaPersistence.java:83)
at com.impetus.kundera.KunderaPersistence.createContainerEntityManagerFactory(KunderaPersistence.java:65)
Whenever I try to run my Java Spring MVC 3.2 Project. I am trying to connect to Apache Cassandra 1.2.8 that I have installed on my machine from the Spring WebApp using Kundera. I have included the following dependencies in the pom.xml file of the project:
scale7-pelops(1.3-1.1.x)
cassandra-all & cassandra-clientutil (1.2.8)
kundera-core & kundera-cassandra (2.6)
My Spring Project uses XML-less configuration (Java Config) and JPA apart from kundera's persistence.xml which is under {PROJECT}/src/main/resources/META-INF so as to be at the base of the classpath during deployment. My persistence.xml looks like:
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="cassandra_pu">
<provider>com.impetus.kundera.KunderaPersistence</provider>
<class>org.tutiworks.orm.Role</class>
<class>org.tutiworks.orm.User</class>
<properties>
<property name="kundera.nodes" value="localhost"/>
<property name="kundera.port" value="9160"/>
<property name="kundera.keyspace" value="afrikana"/>
<property name="kundera.dialect" value="cassandra"/>
<property name="kundera.ddl.auto.prepare" value="update"/>
<property name="kundera.client.lookup.class" value="com.impetus.client.cassandra.pelops.PelopsClientFactory" />
<property name="kundera.cache.provider.class" value="com.impetus.kundera.cache.ehcache.EhCacheProvider"/>
<property name="kundera.cache.config.resource" value="/ehcache-cassandra.xml"/>
</properties>
</persistence-unit>
</persistence>
And the configuration class creating the entityManager looks like:
#Configuration
public class SpringDataConfig extends WebMvcConfigurerAdapter{
#Autowired
private Environment env;
#Value("${kundera.nodes}") private String node;
#Value("${kundera.port}") private String port;
#Value("${kundera.keyspace}") private String keyspace;
#Value("${kundera.dialect}") private String dialect;
#Value("${kundera.ddl.auto.prepare}") private String dbGenerator;
#Value("${kundera.cache.provider.class}") private String cacheClass;
#Value("${kundera.client.lookup.class}") private String lookupClass;
#Value("${kundera.cache.config.resource}") private String configResource;
#Value("${persistence.unit.name}") private String persistenceUnitName;
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setPersistenceUnitName(persistenceUnitName);
return em;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
}
The following class shows how the persistence context is used.
public abstract class GenericDAO< T extends Serializable > {
private Class<T> clazz;
#PersistenceContext
EntityManager entityManager;
protected void setClazz( Class<T> clazzToSet ){
this.clazz = clazzToSet;
}
public T findOne( String id ){
return this.entityManager.find( this.clazz, id );
}
#SuppressWarnings("unchecked")
public List< T > findAll(){
return this.entityManager.createQuery( "from " + this.clazz.getName() )
.getResultList();
}
public void save( T entity ){
this.entityManager.persist( entity );
}
public void update( T entity ){
this.entityManager.merge( entity );
}
public void delete( T entity ){
this.entityManager.remove( entity );
}
public void deleteById( String entityId ){
T entity = this.findOne( entityId );
this.delete( entity );
}
}
A sample of the ORM that is mapped to a column family in Apache Cassandra installation looks like the following.
#XmlRootElement(name = "Role")
#Entity(name="Role")
#Table(name = "roles", schema = "afrikana#cassandra_pu")
public class Role implements Serializable {
private static final long serialVersionUID = 9127322651789683331L;
#Id
#Column(name="id")
#XmlID
private String id;
#Column(name = "role_name")
#XmlElement(name = "role_name")
private String roleName;
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
Where would I be going wrong with my configuration? What I'm I missing? How do I fix the error?
Kundera cassandra libraries are running on 1.2.4 version. Ideally 1.2.8 or higher versions should always be backward compatible, but in this case unfortunately they are not!
I am attempting to handle an 'entity' through annotation instead of a hibernate xml mapping.
I face a situation where addition succeeds but retrieval fails - help is appreciated.
Model class:
#Entity
#Table(name = "PERSON")
public class Person implements Serializable {
private static final long serialVersionUID = -5527566248002296042L;
#Id
#Column(name = "ID")
#GeneratedValue
private Integer id;
#Column(name = "FIRST_NAME")
private String firstName;
#Column(name = "LAST_NAME")
private String lastName;
#Column(name = "MONEY")
private Double money;
.....setters and getters
}
spring configuration:
<context:annotation-config />
<context:component-scan base-package="org.spring.entity,org.spring.service" />
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
....
</bean>
<!-- Hibernate session factory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
...
<property name="packagesToScan">
<list>
<value>org.spring.entity</value>
<value>org.spring.service</value>
</list>
</property>
<property name="hibernateProperties">
...
</property>
</bean>
Service class:
public void add(String firstName, String lastName, Double money) {
// Retrieve session from Hibernate
Session session = sessionFactory.openSession();
try{
// Create a new person
Person person = new Person();
person.setFirstName(firstName);
person.setLastName(lastName);
person.setMoney(money);
// Save
session.save(person);
}
finally{
session.close();
}
}
public void edit(Integer id, String firstName, String lastName, Double money) {
// Retrieve session from Hibernate
Session session = sessionFactory.openSession();
try{
// Retrieve existing person via id
Query query = session.createQuery("FROM Person WHERE ID=?");<=FAILS HERE
query.setInteger(0, id);
Person person = (Person)query.list().get(0);
......
}
The error is as below:
Exception in thread "main" org.hibernate.hql.internal.ast.QuerySyntaxException:
person is not mapped [from person where ID=?]
at org.hibernate.hql.internal.ast.util.SessionFactoryHelper.requireClass
Persister(SessionFactoryHelper.java:180)
at org.hibernate.hql.internal.ast.tree.FromElementFactory.addFromElement
(FromElementFactory.java:110)
at org.hibernate.hql.internal.ast.tree.FromClause.addFromElement(FromCla
use.java:93)
at org.hibernate.hql.internal.ast.HqlSqlWalker.createFromElement(HqlSqlW
alker.java:324)
Your HQL is wrong, Do this way:
(in case of multiple results, their might be some syntax left right, please check.)
Query query = session.createQuery("FROM Person WHERE ID=:ID")
List list=query.setParameter("ID",ID).list();
or
(in case of Single result)
Person person =new Person ();
person =(Person ) session.get(Person .class, ID);