Up ;) Nobody thinks it can be useful?
/me still waits for some feedbacks before commiting a first version... - Romain Le 29 juil. 2011 22:37, "Romain Manni-Bucau" <[email protected]> a écrit : > Here is a patch: > > http://pastebin.com/4CgcLkmH > > it is a bit dirty at JNDI level but it works if you want to try: > > The repository: > > @Repository(context = @PersistenceContext(unitName = "user")) > public interface UserDAO { > User findById(long id); > Collection<User> findByName(String name); > Collection<User> findAll(); > } > > An entity: > > @Entity > public class User { > @Id @GeneratedValue private long id; > private String name; > private int age; > > public long getId() { > return id; > } > > public void setId(long id) { > this.id = id; > } > > public String getName() { > return name; > } > > public void setName(String name) { > this.name = name; > } > > public int getAge() { > return age; > } > > public void setAge(int age) { > this.age = age; > } > > @Override > public String toString() { > return "User{" + > "id=" + id + > ", name='" + name + '\'' + > ", age=" + age + > '}'; > } > } > > A stateless to init the database: > > @Stateless > public class InitUserDAO { > @PersistenceContext private EntityManager em; > public void insert(User user) { > em.persist(user); > } > } > > The test: > > package org.superbiz.test; > > import org.junit.AfterClass; > import org.junit.BeforeClass; > import org.junit.Ignore; > import org.junit.Test; > import org.superbiz.dao.InitUserDAO; > import org.superbiz.dao.UserDAO; > import org.superbiz.model.User; > > import javax.ejb.embeddable.EJBContainer; > import javax.naming.Context; > import java.util.Collection; > > /** > * @author rmannibucau > */ > public class QueryTest { > private static Context context; > private static UserDAO dao; > > @BeforeClass public static void init() throws Exception { > context = EJBContainer.createEJBContainer().getContext(); > InitUserDAO init = (InitUserDAO) > context.lookup("java:global/dynamic-query/InitUserDAO"); > dao = (UserDAO) context.lookup("java:global/openejb/Repository/" + > UserDAO.class.getName()); > for (int i = 0; i < 10; i++) { > User u = new User(); > u.setAge(i * 8); > if (i % 3 == 0) { > u.setName("foo"); > } else { > u.setName("bar-" + i); > } > init.insert(u); > } > } > > @AfterClass public static void close() throws Exception { > if (context != null) { > context.close(); > } > } > > @Test public void query() { > Collection<User> u1 = dao.findByName("foo"); > Collection<User> users = dao.findAll(); > User u2 = dao.findById(1); > System.out.println("\n\n" + users + "\n\n" + u1 + "\n\n" + u2); > } > } > > and the persistence.xml: > > <persistence xmlns="http://java.sun.com/xml/ns/persistence" > version="2.0" > 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"> > <persistence-unit name="user" transaction-type="JTA"> > <jta-data-source>My Default DataSource</jta-data-source> > <class>org.superbiz.model.User</class> > <properties> > <property name="openjpa.jdbc.SynchronizeMappings" > value="buildSchema(ForeignKeys=true)"/> > </properties> > </persistence-unit> > </persistence> > > Don't hesitate to give me feedback if i should continue or not, what you > think should be done or not. > > - Romain > > 2011/7/29 Romain Manni-Bucau <[email protected]> > >> Hi, >> >> i discover a bit more spring data jpa and saw it was possible to create >> dynamically classes!! >> >> it is exactly the same than the stateless without interface excepted here >> the interface has no implementation. >> >> what do you think if we had it to OpenEJB, it is not standard but it is >> pretty cool. >> >> Here what i think we could do: >> >> 1. create a API to scan interfaces >> 1. we need persistencecontext information so we could use >> @PersistenceContext (i don't like) or add another annotation withthe same >> information (@Repository?) >> 2. we need a name, @Named can probably used or we can add it to >> @Repository >> 2. we scan "@Repository" interface constructing pseudo injection to >> be able to get an entitymanager >> 3. then we deploy it in JNDI >> 1. instead of binding a class we bind a proxy which manage to create >> the query from the name >> >> >> It is probably no clear so here some snippets: >> >> My repository: >> >> @Repository(name = "user") >> public interface UserDAO { >> User findById(long id); >> Collection<User> findByName(String name); >> Collection<User> findAll(); >> } >> >> >> One very simple implementation of the invocation handler which manage only >> one condition (this version need an EntityManagerHolder which is here only >> to be able to get the em, it is just an interface with a method >> getEntityManager()...just to do the poc): >> >> >> public class QueryProxy<T> implements InvocationHandler { >> public static final String FIND_PREFIX = "find"; >> >> private static final Map<String, List<String>> CONDITIONS = new >> ConcurrentHashMap<String, List<String>>(); >> >> private EntityManagerHolder entityManagerHolder; >> private Class<T> type; >> >> public QueryProxy(EntityManagerHolder holder, Class<T> entityClass) { >> entityManagerHolder = holder; >> type = entityClass; >> } >> >> public Object invoke(Object proxy, Method method, Object[] args) throws >> Throwable { >> if (!method.getName().startsWith(FIND_PREFIX)) { >> throw new IllegalArgumentException("finder should start with >> find"); >> } >> >> Query query = getQuery(entityManagerHolder.getEntityManager(), >> method.getName(), args); >> if (Collection.class.isAssignableFrom(method.getReturnType())) { >> return query.getResultList(); >> } >> return query.getSingleResult(); >> } >> >> private Query getQuery(EntityManager entityManager, String methodName, >> Object[] args) { >> final List<String> conditions = parseMethodName(methodName); >> final EntityType<T> et = entityManager.getMetamodel().entity(type); >> final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); >> >> CriteriaQuery<Object> query = cb.createQuery(); >> Root<T> from = query.from(type); >> query = query.select(from); >> >> int i = 0; >> for (String condition : conditions) { >> SingularAttribute<? super T, ?> attribute = >> et.getSingularAttribute(condition); >> Path<?> path = from.get(attribute); >> Class<?> javaType = attribute.getType().getJavaType(); >> if (javaType.equals(String.class)) { >> query = query.where(cb.like((Expression<String>) path, >> (String) args[i++])); >> } else if (Number.class.isAssignableFrom(javaType) || >> javaType.isPrimitive()) { >> query = query.where(cb.equal(path, args[i++])); >> } >> } >> >> return entityManager.createQuery(query); >> } >> >> private List<String> parseMethodName(final String methodName) { >> List<String> parsed; >> if (CONDITIONS.containsKey(methodName)) { >> parsed = CONDITIONS.get(methodName); >> } else { >> parsed = new ArrayList<String>(); >> String toParse = methodName.substring(FIND_PREFIX.length()); >> // TODO >> if (toParse.startsWith("By")) { >> toParse = StringUtils.uncapitalize(toParse.substring(2)); >> parsed.add(toParse); >> } >> CONDITIONS.put(methodName, parsed); >> } >> return parsed; >> } >> } >> >> >> Finally i can do: >> >> public class QueryTest { >> private static Context context; >> private static UserDAO dao; >> >> @BeforeClass public static void init() throws Exception { >> context = EJBContainer.createEJBContainer().getContext(); >> dao = (UserDAO) >> Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), >> new Class<?>[] { UserDAO.class }, >> new QueryProxy((EntityManagerHolder) >> context.lookup("java:global/dynamic-query/EMH"), User.class)); >> >> >> InitUserDAO init = (InitUserDAO) >> context.lookup("java:global/dynamic-query/InitUserDAO"); >> for (int i = 0; i < 10; i++) { >> User u = new User(); >> u.setAge(i * 8); >> if (i % 3 == 0) { >> u.setName("foo"); >> } else { >> u.setName("bar-" + i); >> } >> init.insert(u); >> } >> } >> >> @AfterClass public static void close() throws Exception { >> if (context != null) { >> context.close(); >> } >> } >> >> @Test public void query() { >> Collection<User> u1 = dao.findByName("foo"); >> Collection<User> users = dao.findAll(); >> User u2 = dao.findById(1); >> System.out.println("\n\n" + users + "\n\n" + u1 + "\n\n" + u2); >> } >> } >> >> Any thoughts? should it be added to OpenEJB (after some enhancement of >> course ;))? >> >> >> we could extend it to persist, update etc... methods >> >> >> - Romain >> >> >> >> >>
