-
1. Re: Generic DAO
pmuir Jun 2, 2009 1:44 PM (in response to musketyr)JSR-299 only identifies generic types as identical if they have the same type parameter, here you don't have an implementation of DAO<MyEntity>.
-
2. Re: Generic DAO
musketyr Jun 2, 2009 1:57 PM (in response to musketyr)It's quite shame :( I think this looks like a nice idiom. It would be great to have build in support for such a binding (maybe with specialization - use concreate implementation where possible), but I don't even know if is it possible to obtain all needed info in runtime (or what info exactly is needed)
-
3. Re: Generic DAO
gavin.king Jun 2, 2009 6:48 PM (in response to musketyr)you're right. The latest spec considers Dao<T> injectable to Dao<MyEntity>, it's just not implemented in the RI yet.
-
4. Re: Generic DAO
musketyr Jun 2, 2009 9:43 PM (in response to musketyr)That's great! I'm looking forward so much on final release of jsr299 and all other java ee 6 stuff. And Seam 3 too :) Thanks for great work you've all done!
-
5. Re: Generic DAO
wuhaixing.wuhaixing.gmail.com Apr 8, 2010 4:32 PM (in response to musketyr)Can I write a generic DAO with interceptor?
I have a few classes and interface just as follow:
public interface FinderExecutor {
/**
* Execute generic query
*/
Object executeFinder(String query, Object[] queryArgs, Method method, Integer firstResults, Integer maxResults);
/**
* Execute generic bulk update
*/
void executeUpdate(String query, Object[] queryArgs);
}public interface GenericDao<T, PK extends Serializable> extends FinderExecutor {
/**
* Get an entity by id
*
* @param id
* @return entity
*/
T findById(PK id);
// /**
// * Find all entites
// *
// * @return list of entities
// */
// List<T> findAll();
/**
* Stores an entity
*
* @param entity entity to save
*/
T save(T entity);
/**
* Deletes an entity
*
* @param entity entity to delete
*/
void delete(T entity);
/**
* refresh an entity
*
* @param entity entity to refresh
*/
void refresh(T entity);
/**
* Returns the represented generic type
*/
Class<T> getType();
}@InterceptorBinding
@Retention(RUNTIME)
@Target({METHOD, TYPE})
public @interface Query {
/**
* Contains the HQL Statement
*/
@Nonbinding String value() default "";
/**
* if true, the last two parameters of the annotated method have to be
* integers which are first result and maximum result
*/
@Nonbinding boolean limitClause() default false;
}
@Query @Interceptor
public class QueryInterceptor {
@PersistenceContext
EntityManager entityManager;
@AroundInvoke
public Object executeQuery(InvocationContext ctx) throws Exception {
Object result = entityManager.createQuery( .........);
return result;
}
}public interface UserDao extends GenericDao<UserEntity, Integer> {
@Query("select u from UserEntity u join fetch u.role r join fetch r.rights where u.username like ?")
UserEntity findUserByUsername(String username);
@Query("select u from UserEntity u where u.sessionId = ?")
UserEntity findUserBySessionId(String sessionId);
@Query("select distinct u from UserEntity u where u.email like ?")
List<UserEntity> findUserByEmail(String email);
@Query("select count(u) from UserEntity u where u.username like ?")
long existsUsername(String username);
@Query("select count(u) from UserEntity u where u.role = ?")
Long countUserForRole(RoleEntity role);
@Query(value = "select distinct(u) from UserEntity u join u.role.rights as r where r.right = ?")
List<UserEntity> findUserWithRight(String right);
}Can I just inject the UserDao in the action class and get the result by interceptor?
-
6. Re: Generic DAO
wuhaixing.wuhaixing.gmail.com Apr 8, 2010 4:34 PM (in response to musketyr)sorry for the code format,but I cann't edit it any more
-
7. Re: Generic DAO
pmuir Apr 12, 2010 12:31 PM (in response to musketyr)Post again with better formatting, no-one can read that ;-)
-
8. Re: Generic DAO
wuhaixing.wuhaixing.gmail.com Apr 12, 2010 2:38 PM (in response to musketyr)I want to execute query in the interceptor and specify the ql in the method with annotation,just as follow:
@Query @Interceptor public class QueryInterceptor { @PersistenceContext EntityManager em; @AroundInvoke public Object executeQuery(InvocationContext ctx) throws Exception { Object result = null; Query queryAnnotation = getQueryAnnotation(ctx.getMethod()); String queryValue = queryAnnotation.value(); if (queryAnnotation.limitClause()) { Object orginal[] = ctx.getParameters(); for (Object obj:orginal) { System.out.println(obj); } } else { System.out.println(queryValue); result = em.createQuery(queryValue) .getResultList(); } return result; } private Query getQueryAnnotation(Method m) { for (Annotation a : m.getAnnotations()) { if (a instanceof Query) { return (Query) a; } } for (Annotation a : m.getDeclaringClass().getAnnotations()) { if (a instanceof Query) { return (Query) a; } } throw new RuntimeException("@Query not found on method " + m.getName() + " or its class " + m.getClass().getName()); } }
and
@InterceptorBinding @Retention(RUNTIME) @Target({METHOD, TYPE}) public @interface Query { /** * Contains the HQL Statement */ @Nonbinding String value() default ""; /** * if true, the last two parameters of the annotated method have to be * integers which are first result and maximum result */ @Nonbinding boolean limitClause() default false; }
just use interceptor as :
@Produces @Named @RequestScoped @SuppressWarnings("unchecked") @Query("select w from Widget w order by w.name") List<Widget> getWidgets();
How can I get method arguments with interceptor?
-
9. Re: Generic DAO
pmuir Apr 13, 2010 2:17 PM (in response to musketyr)Do:
String ql = ctx.getMethod().getAnnotation(Query.class).value();
-
10. Re: Generic DAO
wuhaixing.wuhaixing.gmail.com Apr 15, 2010 3:44 AM (in response to musketyr)In an application use JPA,there's a lot of entityManager.createQuery(.....)。I had spy the devproof's GenericDao implementations,he use spring's ProxyFactory and interceptor introduce a simpler approach:
public class FinderDispatcherGenericDaoImpl<T, PK extends Serializable> extends HibernateDaoSupport implements FactoryBean, Serializable { private static final long serialVersionUID = -3752572093862325307L; private Object servicesImpl; private Class<T> entityClass; private Class<?> daoInterface; private UsernameResolver usernameResolver; public Object getObject() throws Exception { ProxyFactory result = new ProxyFactory(); GenericDao<T, PK> genericDao = createGenericHibernateDao(); result.setTarget(genericDao); result.setInterfaces(new Class[]{daoInterface}); result.addAdvice(createGenericDaoInterceptor()); return result.getProxy(); } }
What you need is just A interface specify the query and method arguments、result,no repeate createQuery any more:
@CacheQuery(region = UserConstants.QUERY_CACHE_REGION) public interface UserDao extends GenericDao<UserEntity, Integer> { @Query("select u from UserEntity u join fetch u.role r join fetch r.rights where u.username like ?") UserEntity findUserByUsername(String username); @Query("select u from UserEntity u where u.sessionId = ?") UserEntity findUserBySessionId(String sessionId); @Query("select distinct u from UserEntity u where u.email like ?") List<UserEntity> findUserByEmail(String email); @Query("select count(u) from UserEntity u where u.username like ?") long existsUsername(String username); @Query("select count(u) from UserEntity u where u.role = ?") Long countUserForRole(RoleEntity role); @Query(value = "select distinct(u) from UserEntity u join u.role.rights as r where r.right = ?") List<UserEntity> findUserWithRight(String right); }
bean declaretion in the configuration:
<bean id="userDao" parent="baseGenericDao"> <property name="daoInterface" value="org.devproof.portal.core.module.user.dao.UserDao"/> <property name="entityClass" value="org.devproof.portal.core.module.user.entity.UserEntity"/> </bean>
Can this is implented in weld?
Spring version Source can be viewed in http://code.google.com/p/devproof/source/browse/svn/trunk/portal-core/src/main/java/org/devproof/portal/core/module/common/dao -
11. Re: Generic DAO
pmuir Apr 15, 2010 1:06 PM (in response to musketyr)Yes, you could implement this in Weld. For example you could use an interceptor or you could use lifecycle events to read the annotations and create beans.
-
12. Re: Generic DAO
andygibson.contact.andygibson.net Apr 15, 2010 11:56 PM (in response to musketyr)Is there much need for this? Where would you call it from while passing it the parameters and such that the interceptors will still fire?
I don't think that calling one injected bean from another bean fires the interceptors on the injected bean method i.e.
class SomeBean { @SomeInterceptor public Object someMethod(String param) { ... } } class SomeOtherBean { @Inject private SomeBean someBean; public void someCode() { ... ... someBean.someMethod(aValue); ... } }
I don't believe that in this case, if you call SomeOtherBean.someCode, when it calls someMethod on the injected SomeBean instance, the Interceptor won't fire, nor would parameter injection or any other bean enhancements?
So, you could call it like #{someBean.someMethod} from JSF, or as an event handler or something like that, which is fine, but I don't see query methods being called like this, and there's no real way to stick parameters on there.
Also, when you bind a JSF page to some query results, you don't pass in method parameters when getting the values, and you can only inject parameters on a @produces method.
I'm just wondering if there is a real use case for it, because the only way I see it being useful is returning data from @Produces method calls that don't have parameters (or only have injected parameters).
Cheers,
Andy
-
13. Re: Generic DAO
nickarls Apr 16, 2010 8:13 AM (in response to musketyr)Without looking too much at the code I think they might fire for normal scoped beans since I think the interceptor stack is built into the proxy. Ish.
-
14. Re: Generic DAO
wuhaixing.wuhaixing.gmail.com Apr 16, 2010 8:23 AM (in response to musketyr)There is what I want to implement:
A interface just for describe the query should be executed:public interface UserDao extends GenericDao<UserEntity, Integer> { @Query("select distinct u from UserEntity u where u.email like ?") List<UserEntity> findUserByEmail(String email); }
A interceptor populate the EntityManager Query from the annotation and method arguments,or just proxy it to a generic dao implementation:
@QuerySpecifiction @Interceptor public class QueryInterceptor { private @Inject Logger logger; @Inject GenericDao target; @AroundInvoke public Object executeQuery(InvocationContext ctx) throws Exception { Method method = ctx.getMethod(); QuerySpecifiction querySpecification = getQueryAnnotation(method); if (querySpecification.limitClause()) { Object orginal[] = ctx.getParameters(); int len = orginal.length - 2; Object copy[] = new Object[len]; for (int i = 0; i < len; i++) { copy[i] = orginal[i]; } return target.executeFinder(querySpecification.value(), copy, method, (Integer) orginal[len], (Integer) orginal[len + 1]); } else { return target.executeFinder(querySpecification.value(), ctx.getParameters(), method, null, null); } } ......... }
A @Produces method create the dao's instance:
@Produces @Dao public UserDao getUserDao() { return null; }
A interceptor create the dao's proxy instant:
@Interceptor @Dao public class DaoInterceptor { private @Inject Logger logger; @AroundInvoke public Object createDao(InvocationContext ctx) throws Exception { Class<?> returnType = ctx.getMethod().getReturnType(); logger.info("create dao {}",returnType.getName()); if (!returnType.isInterface()) { throw new UnsupportedOperationException("Only results of methods " + "which produce implementations of an interface can be replaced!"); } Object result = ctx.proceed(); result = Proxy.newProxyInstance( returnType.getClassLoader(), new Class[] { returnType }, new DaoInvocationHandler(result)); return result; } }
Then in the client,I could find the user by email like this:
@Inject UserDao userDao; return userDao. findUserByEmail("some@mail.com");
Because lots of method just create the query and set the parameters with method arguments,so I think should write those code once and reuse it for different entity.However,I cann't figure out how to achieve this with weld yet.