everytime when i am running my spring with hibernate socket program it saves for the first time but i am sending infinitely from the client side but in server end only first time it is saving..What type of problem i am facing?? how to resolve
package utilclass;
import org.hibernate.*;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
public class HibernateUtemplate {
private static HibernateTemplate template;
public void setTemplate(HibernateTemplate template){
HibernateUtemplate.template=template;
}
public static SessionFactory getSessionFactory(){
return template.getSessionFactory();
}
public static Session getSession(){
getSessionFactory().getCurrentSession().beginTransaction();
return getSessionFactory().getCurrentSession();
}
public static void commitTransaction() {
getSession().getTransaction().commit();
}
public static void rollbackTransaction() {
getSession().getTransaction().rollback();
}
public static void closeSession() {
getSession().close();
}
}
this is my generic file
package daoimplclasses;
import java.io.Serializable;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateTemplate;
import utilclass.HibernateUtemplate;
import daointerfaces.GenericDao;
public abstract class GenericDaoimpl<T, ID extends Serializable> implements GenericDao<T, ID> {
//HibernateTemplate template;
protected Session getSession() {
return HibernateUtemplate.getSession();
}
public void save(T entity) {
//template.saveOrUpdate(entity);
HibernateUtemplate.getSession().saveOrUpdate(entity);
// HibernateUtemplate.beginTransaction().saveOrUpdate(entity);
}
public void merge(T entity) {
// template.merge(entity);
HibernateUtemplate.getSession().merge(entity);
// HibernateUtemplate.beginTransaction().merge(entity);
}
public void update(T entity) {
// template.update(entity);
HibernateUtemplate.getSession().update(entity);
// HibernateUtemplate.beginTransaction().update(entity);
}
public void delete(T entity) {
// template.delete(entity);
HibernateUtemplate.getSession().delete(entity);
//HibernateUtemplate.beginTransaction().delete(entity);
}
public List<T> findMany(Query query) {
List<T> t;
t = (List<T>) query.list();
return t;
}
public T findOne(Query query) {
T t;
t = (T) query.uniqueResult();
return t;
}
public T findByID(Class claz,String siteid){
T t=null;
//t=(T)template.get(claz, siteid);
t=(T) HibernateUtemplate.getSession().get(claz, siteid);
//t=(T) HibernateUtemplate.beginTransaction().get(claz, siteid);
return t;
}
public List<T> findAll(Class clazz) {
List<T> T = null;
Query query= HibernateUtemplate.getSession().createQuery("from "+clazz.getName());
// Query query= HibernateUtemplate.beginTransaction().createQuery("from "+clazz.getName());
T = query.list();
return T;
}
}
Related
I have other BaseDaoImpl which is already generic but i want to add PaginationandSortiongRepository as generic, Please Help to Implement
I have tried every way to add GenericJPADAO as bean but its not possible is there, Is there any other way to implement?
public interface BaseDao<T, ID extends Serializable> {
public List<T> findAll();
public T findOne(final long id);
public T update(T object);
public T get(Long id);
public void delete(T object);
public void insert(T object);
public boolean exists(Long id);
T getByCondition(String fieldName, Object value);
List<T> getALL();
}
public class BaseDaoImpl<T, ID extends Serializable> implements BaseDao<T, ID> {
#PersistenceContext
protected EntityManager entityManager;
private Class<T> entityType;
public BaseDaoImpl() {
this.entityType = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
}
#Override
#Transactional
public void insert(T entity) {
entityManager.persist(entity);
}
#Transactional
public List<T> findAll() {
return entityManager.createQuery("from " + entityType.getName()).getResultList();
}
#Override
#Transactional
public T findOne(long id) {
return entityManager.find(entityType, id);
}
#Override
#Transactional
public T update(T entity) {
return entityManager.merge(entity);
}
#Override
#Transactional
public T get(Long id) {
// TODO Auto-generated method stub
return entityManager.find(entityType, id);
}
#Override
#Transactional
public void delete(T object) {
entityManager.remove(object);
}
#Override
#Transactional
public boolean exists(Long id) {
return entityManager.contains(id);
}
#Override
#Transactional
public T getByCondition(String fieldName, Object value) {
System.out.println(entityType);
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<T> criteria = cb.createQuery(entityType);
Root<T> member = criteria.from(entityType);
criteria.select(member).where(cb.equal(member.get(fieldName), value + ""));
List<T> results = entityManager.createQuery(criteria).getResultList();
if (results.isEmpty()) {
return null;
} else {
return (T) results.get(0);
}
}
#Override
public List<T> getALL() {
return null;
}}
#NoRepositoryBean
public interface GenericJpaDao<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> {
enter code here
}
#Repository
public class AccountDaoImpl extends BaseDaoImpl<Account, Long> implements AccountDao {
/* Not able to Inject If add #Repository on GenericJapDao, How to Implement As generic Same as BaseDaoImpl*/
GenericJpaDao< Account, Long> generiCJPADao;
#Override
public Account getAccount(String emailAddress) {
return getByCondition("emailAddress", emailAddress);
}
#Override
public void saveAccount(Account account) {
insert(account);
}}
Not able to add GenericJPA and i am not sure how to make Repository as Generic,
Thnaks in Advance
Lets suppose, that we have a bean like this:
public class Response<T> {
private T data;
private double executionDuration;
private boolean success;
private String version;
//HOW TO Make Jackson to inject this?
private Class<T> dataClass;
public Optional<T> getData() {
return Optional.ofNullable(data);
}
public double getExecutionDuration() {
return executionDuration;
}
public Class<T> getDataClass() {
return dataClass;
}
public String getVersion() {
return version;
}
public boolean isSuccess() {
return success;
}
}
The deserialization happens like this:
objectMapper.readValue(json, new TypeReference<Response<SomeClass>>() {});
Can I somehow make Jackson to inject the class "SomeClass" into my bean? Injecting the type reference itself would be also ok, I think.
If it is undesirable to save class info in json and use #JsonTypeInfo I would suggest to use #JacksonInject:
public class Response<T> {
private T data;
private double executionDuration;
private boolean success;
private String version;
#JacksonInject("dataClass")
private Class<T> dataClass;
public Optional<T> getData() {
return Optional.ofNullable(data);
}
public double getExecutionDuration() {
return executionDuration;
}
public Class<T> getDataClass() {
return dataClass;
}
public String getVersion() {
return version;
}
public boolean isSuccess() {
return success;
}
}
Deserialization would look like:
ObjectMapper mapper = new ObjectMapper();
InjectableValues.Std injectable = new InjectableValues.Std();
injectable.addValue("dataClass", SomeClass.class);
mapper.setInjectableValues(injectable);
final Response<Integer> response = mapper.readValue(json, new TypeReference<Response<SomeClass>>() { });
this worked for me;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
#Getter
#Setter
#NoArgsConstructor
public class Entity<T> {
private T data;
#JsonSerialize(converter = ClassToStringConverter.class)
#JsonDeserialize(converter = StringToClassConverter.class)
private Class<T> dataClass;
}
and
import com.fasterxml.jackson.databind.util.StdConverter;
public class ClassToStringConverter extends StdConverter<Class<?>, String> {
public String convert(Class<?> aClass) {
// class java.lang.Integer
return aClass.toString().split("\\s")[1];
}
}
and
import com.fasterxml.jackson.databind.util.StdConverter;
public class StringToClassConverter extends StdConverter<String, Class<?>> {
public Class<?> convert(String s) {
try {
return Class.forName(s);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
Main;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
Entity<Integer> data = new Entity<Integer>();
data.setData(5);
data.setDataClass(Integer.class);
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(data);
Entity<Integer> jsonData = mapper.readValue(json, new TypeReference<Entity<Integer>>() {});
System.out.println(jsonData.getData());
System.out.println(jsonData.getDataClass().getCanonicalName());
}
}
But, maybe it will be better, to not save the class type, but use method to get type from data?
public Class<T> getType() {
return (Class<T>) data.getClass();
}
public class Response<T> {
private T data;
// other fields & methods
public Class getType() {
return Optional.ofNullable(data).map(Object::getClass).orElse(Void.class);
}
public Optional<Class> getSafeType() {
return Optional.ofNullable(data).map(Object::getClass);
}
}
Super simple, no need to tinker with Jackson, NPE safe...
I want UserDao class to extend GenericDAO where i'll have all CRUD methods. I have read article from IBM: http://www.ibm.com/developerworks/java/library/j-genericdao/index.html , but i could not implement it. Could someone show me example based on my custom UserDao class.
#Transactional(value="myTransactionManager")
public class UserDao {
#Qualifier("mySessionFactory")
public SessionFactoryImpl sessionFactory;
public void setSessionFactory(SessionFactoryImpl sessionFactory) {
this.sessionFactory = sessionFactory;
}
public List<UserEntity> getAll() {
Query query = sessionFactory.getCurrentSession().createQuery(
"from UserEntity ");
List<UserEntity> userList = query.list();
return userList;
}
public void updaet(UserEntity userEntity) {
sessionFactory.getCurrentSession().update(userEntity);
}
public void delete(UserEntity userEntity) {
sessionFactory.getCurrentSession().delete(userEntity);
}
public void save(UserEntity userEntity) {
sessionFactory.getCurrentSession().save(userEntity);
}
}
i tried to write class like this
public class GenericDao{
#Qualifier("mySessionFactory")
public SessionFactoryImpl sessionFactory;
public void setSessionFactory(SessionFactoryImpl sessionFactory) {
this.sessionFactory = sessionFactory;
}
public <T> List<T> getAll(Class<T> t) {
Query query = sessionFactory.getCurrentSession().createQuery(
"from " + t.getName());
List<T> list = query.list();
return list;
}
public <T> void save(T t) {
sessionFactory.getCurrentSession().save(t);
}
public <T> void update(T t) {
sessionFactory.getCurrentSession().update(t);
}
public <T> void delete(T t) {
sessionFactory.getCurrentSession().delete(t);
}
}
but when i try to pull data with UserDao like this:
public List<UserEntity> getAll() {
List<UserEntity> list = UserDao.findAll();
}
Eclipse IDE for line List<UserEntity> list = UserDao.findAll(); give error : The method findAll() is underfined for type UserDao.
this is my implementation :
GenericDao :
#Repository
public class GenericDao<T extends DbObject> {
#Autowired
private SessionFactory sessionFactory;
private Class<T> getParameterizedClass() {
return (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
public T findById(final Serializable id) {
return (T) getCurrentSession().get(getParameterizedClass(), id.toString());
}
public void persist(final T object) {
getCurrentSession().persist(object);
}
public void saveOrUpdate(final T object) {
getCurrentSession().saveOrUpdate(object);
}
public void delete(final T object) {
getCurrentSession().delete(object);
}
public T merge(final T object) {
return (T) getCurrentSession().merge(object);
}
}
UserDao :
public class UserDao extends GenericDao<User> {
}
Entity :
#Entity
#Table(name = "...")
public class User extends DbObject {
}
in my use case i need to develop a custom annotation by wich i can instanziate the implementation of a DAO.
So i have the interface:
public interface IDAO{
public void method1();
public void method2();
}
and the resource config implementation:
public class JAXRSConfig extends ResourceConfig {
public JAXRSConfig() {
register(new AbstractBinder() {
#Override
protected void configure() {
/*Factory Classes Binding*/
bindFactory(DaoFactory.class).to(IDAO.class).in(RequestScoped.class);
/*Injection Resolver Binding*/
bind(CustomContextInjectionResolver.class).to(new TypeLiteral<InjectionResolver<CustomContext>>(){}).in(Singleton.class);
}
});
}
I'm stucking with the factory implementation:
public class DaoFactory implements Factory<IDAO>{
private final HttpServletRequest request;
#Inject
public DaoFactory(HttpServletRequest request) {
this.request = request;
}
#Override
public IDAO provide() {
IDAO dao = null;
try {
???????????
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
return dao;
}
#Override
public void dispose( IDAO mud) {
}
}
And here of course i have my IDAO implementation:
public class DAOImplementation implements IDAO {
public void method1(){
//do some stuff
}
public void method2(){
//do some stuff
}
public MyEntity getEntity(){
//get my entity
}
}
Result i want to get is:
#Path("/myResource")
public class myService(){
#CustomContext
DAOImplementation myDao;
public String myService(){
MyEntity entity = myDao.getEntity();
}
}
Is there a way to connect the factory to the injection resolver the way i can get the real implementation to provide? Does hk2 provide any means to do this?
EDITED
I can have multiple implementations of the IDAO interface... for example if i have:
public class DAOImplementation2 implements IDAO {
public void method1(){
//do some stuff
}
public void method2(){
//do some stuff
}
public MyEntity2 getEntity2(){
//get my entity
}
}
i should be able to get second implementation like this:
#Path("/myResource")
public class myService(){
#CustomContext
DAOImplementation myDao;
#CustomContext
DAOImplementation2 mySecondDao;
public String myService(){
MyEntity entity = myDao.getEntity();
MyEntity2 entity = mySecondDao.getEntity2();
}
}
So based on our previous chat, below is the idea I was trying to get across. Basically you would add a Feature where the user can pass the IDao implementation classes to. In the Feature you can bind them by name
public static class DaoFeature implements Feature {
private final Class<? extends IDao>[] daoClasses;
public DaoFeature(Class<? extends IDao> ... daoClasses) {
this.daoClasses = daoClasses;
}
#Override
public boolean configure(FeatureContext context) {
context.register(new Binder());
return true;
}
private class Binder extends AbstractBinder {
#Override
protected void configure() {
...
for (Class<? extends IDao> daoClass: daoClasses) {
bind(daoClass).to(IDao.class)
.named(daoClass.getCanonicalName()).in(RequestScoped.class);
}
}
}
}
Then in the InjectionResolver you can look then up by name and also add it to the CloseableService. All without the need for any ugly reflection.
public static class CustomContextResolver
implements InjectionResolver<CustomContext> {
#Inject
private ServiceLocator locator;
#Inject
private IDaoProviders daoClasses;
#Inject
private CloseableService closeableService;
#Override
public Object resolve(Injectee injectee, ServiceHandle<?> root) {
Type requiredType = injectee.getRequiredType();
for (Class type: daoClasses.getDaoClasses()) {
if (requiredType == type) {
IDao dao = locator.getService(IDao.class, type.getCanonicalName());
addToCloseableService(dao);
return type.cast(dao);
}
}
return null;
}
...
}
The EntityManager would be handled with a Factory. The Factory I used is a Jersey class that lets you get the ContainerRequest which you can pretty much get anything you would be able to get from a HttpServletRequest
public static class DummyEntityManagerFactory
extends AbstractContainerRequestValueFactory<DummyEntityManager> {
#Override
public DummyEntityManager provide() {
ContainerRequest request = getContainerRequest();
// get some condition for EntityManager
return new DummyEntityManager();
}
}
In the abstract IDao class, you can inject the EntityManager, and handle and disposing of resource yourself.
public static abstract class IDao {
#Inject
private DummyEntityManager em;
protected abstract String getData();
public void close() {
em.close();
}
protected DummyEntityManager getEntityManager() {
return em;
}
}
Here's the complete test case
import java.io.Closeable;
import java.io.IOException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;
import javax.ws.rs.core.Response;
import org.glassfish.hk2.api.Injectee;
import org.glassfish.hk2.api.InjectionResolver;
import org.glassfish.hk2.api.ServiceHandle;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.api.TypeLiteral;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.process.internal.RequestScoped;
import org.glassfish.jersey.server.CloseableService;
import org.glassfish.jersey.server.ContainerRequest;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.internal.inject.AbstractContainerRequestValueFactory;
import org.glassfish.jersey.test.JerseyTest;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class CustomDaoTest extends JerseyTest {
public static class DummyEntityManager {
String findByDaoClass(Class cls) {
return "Data from " + cls.getSimpleName();
}
public void close() { /* noop */ }
}
public static abstract class IDao {
private static final Logger LOG = Logger.getLogger(IDao.class.getName());
#Inject
private DummyEntityManager em;
protected abstract String getData();
public void close() {
LOG.log(Level.INFO, "Closing IDAO: {0}", this.getClass().getName());
em.close();
}
protected DummyEntityManager getEntityManager() {
return em;
}
}
public static class DaoImplOne extends IDao {
#Override
public String getData() {
return getEntityManager().findByDaoClass(this.getClass());
}
}
public static class DaoImplTwo extends IDao {
#Override
protected String getData() {
return getEntityManager().findByDaoClass(this.getClass());
}
}
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.FIELD, ElementType.CONSTRUCTOR})
public static #interface CustomContext{}
public static class CustomContextResolver
implements InjectionResolver<CustomContext> {
#Inject
private ServiceLocator locator;
#Inject
private IDaoProviders daoClasses;
#Inject
private CloseableService closeableService;
#Override
public Object resolve(Injectee injectee, ServiceHandle<?> root) {
Type requiredType = injectee.getRequiredType();
for (Class type: daoClasses.getDaoClasses()) {
if (requiredType == type) {
IDao dao = locator.getService(IDao.class, type.getCanonicalName());
addToCloseableService(dao);
return type.cast(dao);
}
}
return null;
}
private void addToCloseableService(final IDao idao) {
closeableService.add(new Closeable(){
#Override
public void close() throws IOException {
idao.close();
}
});
}
#Override
public boolean isConstructorParameterIndicator() {
return false;
}
#Override
public boolean isMethodParameterIndicator() {
return false;
}
}
public static class DummyEntityManagerFactory
extends AbstractContainerRequestValueFactory<DummyEntityManager> {
#Override
public DummyEntityManager provide() {
ContainerRequest request = getContainerRequest();
// get some condition for EntityManager
return new DummyEntityManager();
}
}
public static class IDaoProviders {
private final List<Class<? extends IDao>> daoClasses;
public IDaoProviders(Class<? extends IDao> ... daoClasses) {
this.daoClasses = new ArrayList<>(Arrays.asList(daoClasses));
}
public List<Class<? extends IDao>> getDaoClasses() {
return daoClasses;
}
}
public static class DaoFeature implements Feature {
private final Class<? extends IDao>[] daoClasses;
public DaoFeature(Class<? extends IDao> ... daoClasses) {
this.daoClasses = daoClasses;
}
#Override
public boolean configure(FeatureContext context) {
context.register(new Binder());
return true;
}
private class Binder extends AbstractBinder {
#Override
protected void configure() {
bind(CustomContextResolver.class)
.to(new TypeLiteral<InjectionResolver<CustomContext>>(){})
.in(Singleton.class);
bindFactory(DummyEntityManagerFactory.class)
.to(DummyEntityManager.class)
.in(RequestScoped.class);
for (Class<? extends IDao> daoClass: daoClasses) {
bind(daoClass).to(IDao.class)
.named(daoClass.getCanonicalName()).in(RequestScoped.class);
}
IDaoProviders daoProviders = new IDaoProviders(daoClasses);
bind(daoProviders).to(IDaoProviders.class);
}
}
}
#Path("dao")
public static class DaoResource {
#CustomContext
private DaoImplOne daoOne;
#CustomContext
private DaoImplTwo daoTwo;
#GET
#Path("one")
public String getOne() {
return daoOne.getData();
}
#GET
#Path("two")
public String getTwo() {
return daoTwo.getData();
}
}
#Override
public ResourceConfig configure() {
return new ResourceConfig(DaoResource.class)
.register(new DaoFeature(DaoImplOne.class, DaoImplTwo.class));
}
#Test
public void should_return_dao_one_data() {
Response response = target("dao/one").request().get();
assertEquals(200, response.getStatus());
assertEquals("Data from DaoImplOne", response.readEntity(String.class));
response.close();
}
#Test
public void should_return_dao_two_data() {
Response response = target("dao/two").request().get();
assertEquals(200, response.getStatus());
assertEquals("Data from DaoImplTwo", response.readEntity(String.class));
response.close();
}
}
UPDATE
Using web.xml (no ResourceConfig)
import java.io.Closeable;
import java.io.IOException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;
import javax.ws.rs.core.Response;
import org.glassfish.hk2.api.Injectee;
import org.glassfish.hk2.api.InjectionResolver;
import org.glassfish.hk2.api.ServiceHandle;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.api.TypeLiteral;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.internal.util.PropertiesHelper;
import org.glassfish.jersey.process.internal.RequestScoped;
import org.glassfish.jersey.server.CloseableService;
import org.glassfish.jersey.server.ContainerRequest;
import org.glassfish.jersey.server.internal.inject.AbstractContainerRequestValueFactory;
import org.glassfish.jersey.servlet.ServletContainer;
import org.glassfish.jersey.test.DeploymentContext;
import org.glassfish.jersey.test.JerseyTest;
import org.glassfish.jersey.test.ServletDeploymentContext;
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
import org.glassfish.jersey.test.spi.TestContainerFactory;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class WebXmlCustomDaoTest extends JerseyTest {
public static class DummyEntityManager {
String findByDaoClass(Class cls) {
return "Data from " + cls.getSimpleName();
}
public void close() { /* noop */ }
}
public static abstract class IDao {
private static final Logger LOG = Logger.getLogger(IDao.class.getName());
#Inject
private DummyEntityManager em;
protected abstract String getData();
public void close() {
LOG.log(Level.INFO, "Closing IDAO: {0}", this.getClass().getName());
em.close();
}
protected DummyEntityManager getEntityManager() {
return em;
}
}
public static class DaoImplOne extends IDao {
#Override
public String getData() {
return getEntityManager().findByDaoClass(this.getClass());
}
}
public static class DaoImplTwo extends IDao {
#Override
protected String getData() {
return getEntityManager().findByDaoClass(this.getClass());
}
}
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.FIELD, ElementType.CONSTRUCTOR})
public static #interface CustomContext {
}
public static class CustomContextResolver
implements InjectionResolver<CustomContext> {
#Inject
private ServiceLocator locator;
#Inject
private IDaoProviders daoClasses;
#Inject
private CloseableService closeableService;
#Override
public Object resolve(Injectee injectee, ServiceHandle<?> root) {
Type requiredType = injectee.getRequiredType();
for (Class type : daoClasses.getDaoClasses()) {
if (requiredType == type) {
IDao dao = locator.getService(IDao.class, type.getCanonicalName());
addToCloseableService(dao);
return type.cast(dao);
}
}
return null;
}
private void addToCloseableService(final IDao idao) {
closeableService.add(new Closeable() {
#Override
public void close() throws IOException {
idao.close();
}
});
}
#Override
public boolean isConstructorParameterIndicator() {
return false;
}
#Override
public boolean isMethodParameterIndicator() {
return false;
}
}
public static class DummyEntityManagerFactory
extends AbstractContainerRequestValueFactory<DummyEntityManager> {
#Override
public DummyEntityManager provide() {
ContainerRequest request = getContainerRequest();
// get some condition for EntityManager
return new DummyEntityManager();
}
}
public static class IDaoProviders {
private final List<Class<? extends IDao>> daoClasses;
public IDaoProviders(Class<? extends IDao>... daoClasses) {
this.daoClasses = new ArrayList<>(Arrays.asList(daoClasses));
}
public List<Class<? extends IDao>> getDaoClasses() {
return daoClasses;
}
}
public static class DaoFeature implements Feature {
public static final String DAO_IMPLEMENTATIONS = "dao.implementations";
#Override
public boolean configure(FeatureContext context) {
Map<String, Object> props = context.getConfiguration().getProperties();
String initParam = getValue(props, DAO_IMPLEMENTATIONS, String.class);
context.register(new Binder(getFromStringParam(initParam)));
return true;
}
private List<Class<? extends IDao>> getFromStringParam(String initParam) {
String[] daoClassNames = initParam.split(",");
List<Class<? extends IDao>> daoClasses = new ArrayList<>();
for (int i = 0; i < daoClassNames.length; i++) {
try {
String classname = daoClassNames[i].trim();
Class<?> cls = Class.forName(daoClassNames[i].trim());
if (IDao.class.isAssignableFrom(cls)) {
Class<? extends IDao> c = (Class<? extends IDao>)cls;
daoClasses.add(c);
}
} catch (ClassNotFoundException ex) {
// noop - ignore non IDao classes.
System.out.println(ex.getMessage());
}
}
return daoClasses;
}
public static <T> T getValue(Map<String, ?> properties, String key, Class<T> type) {
return PropertiesHelper.getValue(properties, key, type, null);
}
private class Binder extends AbstractBinder {
List<Class<? extends IDao>> daoClasses;
public Binder(List<Class<? extends IDao>> daoClasses) {
this.daoClasses = daoClasses;
}
#Override
protected void configure() {
bind(CustomContextResolver.class)
.to(new TypeLiteral<InjectionResolver<CustomContext>>() {
})
.in(Singleton.class);
bindFactory(DummyEntityManagerFactory.class)
.to(DummyEntityManager.class)
.in(RequestScoped.class);
for (Class<? extends IDao> daoClass : daoClasses) {
bind(daoClass).to(IDao.class)
.named(daoClass.getCanonicalName()).in(RequestScoped.class);
}
Class<? extends IDao>[] array = daoClasses.toArray(new Class[]{});
IDaoProviders daoProviders = new IDaoProviders(array);
bind(daoProviders).to(IDaoProviders.class);
}
}
}
#Path("dao")
public static class DaoResource {
#CustomContext
private DaoImplOne daoOne;
#CustomContext
private DaoImplTwo daoTwo;
#GET
#Path("one")
public String getOne() {
return daoOne.getData();
}
#GET
#Path("two")
public String getTwo() {
return daoTwo.getData();
}
}
#Override
protected TestContainerFactory getTestContainerFactory() {
return new GrizzlyWebTestContainerFactory();
}
/**
*
* This method is to configure a web deployment using a "web.xml".
*
* The "dao.implementations" is a property from the `DaoFeature`
* The user should list the `IDao` implementation classes separated
* by a comma.
*
* The `DaoFeature` is register with the Jersey init-param
* `jersey.config.server.provider.classnames`
*
* The class names I listed use a `$` only because they are inner classes.
* Normally you would not need that.
*
* See http://stackoverflow.com/a/7007859/2587435
*/
#Override
protected DeploymentContext configureDeployment() {
return ServletDeploymentContext
.forServlet(ServletContainer.class)
.initParam("jersey.config.server.provider.packages",
this.getClass().getPackage().getName())
.initParam("jersey.config.server.provider.classnames",
"com.stackoverflow.dao.WebXmlCustomDaoTest$DaoFeature")
.initParam("dao.implementations",
"com.stackoverflow.dao.WebXmlCustomDaoTest$DaoImplOne,"
+ "com.stackoverflow.dao.WebXmlCustomDaoTest$DaoImplTwo")
.build();
}
#Test
public void should_return_dao_one_data() {
Response response = target("dao/one").request().get();
assertEquals(200, response.getStatus());
assertEquals("Data from DaoImplOne", response.readEntity(String.class));
response.close();
}
#Test
public void should_return_dao_two_data() {
Response response = target("dao/two").request().get();
assertEquals(200, response.getStatus());
assertEquals("Data from DaoImplTwo", response.readEntity(String.class));
response.close();
}
}
I'm having problems with Spring transactions. I really need help as I can't figure out why personsDao2 is not rolled back as should (see assert below commented with "FAILS!"). Any input?
My Eclipse project is available for download at http://www52.zippyshare.com/v/4142091/file.html. All dependencies are there so it's easy to get going.
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.google.common.collect.Lists;
public class MyInnerClass {
private PersonsDao personsDao;
public MyInnerClass() {
}
public PersonsDao getPersonsDao() {
return personsDao;
}
public void setPersonsDao(PersonsDao personsDao) {
this.personsDao = personsDao;
}
#Transactional(propagation = Propagation.REQUIRES_NEW, noRollbackFor = Exception.class)
public void method() {
personsDao.createPersons(Lists.newArrayList(new Person("Eva")));
}
}
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.google.common.collect.Lists;
public class MyOuterClass {
private MyInnerClass myInnerClass;
private PersonsDao personsDao;
public MyInnerClass getMyInnerClass() {
return myInnerClass;
}
public void setMyInnerClass(MyInnerClass myInnerClass) {
this.myInnerClass = myInnerClass;
}
public void setMyInnerClass() {
}
public PersonsDao getPersonsDao() {
return personsDao;
}
public void setPersonsDao(PersonsDao personsDao) {
this.personsDao = personsDao;
}
public MyOuterClass() {
}
#Transactional(propagation = Propagation.REQUIRED, rollbackFor=Exception.class)
public void method() {
try {
personsDao.createPersons(Lists.newArrayList(new Person("Adam")));
throw new RuntimeException("Forced rollback");
} finally {
myInnerClass.method();
}
}
}
public class Person {
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public String toString() {
return "Customer [name=" + name + "]";
}
#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 (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
private String name;
}
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSourceUtils;
public class PersonsDao {
public PersonsDao(DataSource dataSource, String tableName) {
namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
this.tableName = tableName;
}
public List<Person> getPersons() {
Map<String, Object> namedParameters = new HashMap<String, Object>();
String getCustomers = "SELECT name FROM " + tableName + " ORDER BY name ASC";
return namedParameterJdbcTemplate.query(getCustomers, namedParameters, getRowMapper());
}
public void createPersons(List<Person> customers) {
SqlParameterSource[] params = SqlParameterSourceUtils.createBatch(customers.toArray());
String createCustomer = "INSERT INTO " + tableName + " VALUES(:name)";
namedParameterJdbcTemplate.batchUpdate(createCustomer, params);
}
public void deleteCustomers() {
Map<String, Object> namedParameters = new HashMap<String, Object>();
String deleteCustomers = "DELETE FROM " + tableName;
namedParameterJdbcTemplate.update(deleteCustomers, namedParameters);
}
private static RowMapper<Person> getRowMapper() {
return new RowMapper<Person>() {
#Override
public Person mapRow(ResultSet arg0, int arg1) throws SQLException {
return new Person(arg0.getString("name"));
}
};
}
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
private String tableName;
}
import static org.junit.Assert.*;
import javax.annotation.Resource;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "/beans.xml")
#Transactional(rollbackFor = Exception.class)
public class PersonsDaoTest {
#Resource
private MyInnerClass myInnerClass;
#Resource
private MyOuterClass myOuterClass;
#Test(expected = Exception.class)
public void test() {
myOuterClass.method();
fail();
}
#After
public void after() {
assertEquals(1, myInnerClass.getPersonsDao().getPersons().size());
assertEquals(0, myOuterClass.getPersonsDao().getPersons().size());
}
#Before
public void before() {
myInnerClass.getPersonsDao().deleteCustomers();
myOuterClass.getPersonsDao().deleteCustomers();
assertEquals(0, myInnerClass.getPersonsDao().getPersons().size());
assertEquals(0, myOuterClass.getPersonsDao().getPersons().size());
}
}
First of all, the #Transactional annotations on your two classes are ignored, since you instantiates these classes directly (using new) rather than getting an instance from the spring context.
So in fact, it boild down to this code:
try {
personDao2.createPerson(); // creates a person in persons2
throw new RuntimeException();
}
finally {
personDao1.createPerson(); // creates a person in person1
}
A finally block is always executed, even if an exception is thrown in the try block. So the test creates a person in person1 and in person2.
#Anders Your InnerClass with the #Transactional annotation does not derive from an interface, if you are not using AspectJ weaving or CG-LIB based proxies, the #Transactional aspect won't take effect, as the dynamic proxies require an interface to be present. A quick fix will be to derive your inner class from an interface, define the bean in the spring config and consistently use the interface for referring to the bean.