Today it is a simple implementation managing only finders but if someone give me some clues to manage correctly transaction i would like to add persistence methods.
- Romain 2011/8/2 David Blevins <[email protected]> > This looks like a cool idea. It's not worth investigating, but this is > exactly how CMP home interfaces look. The developer creates an interface > with "create" and "find" method and the container makes it work. > > Home interfaces were actually pretty useful for CMP, just CMP itself was > terrible and home interfaces weren't very useful for session beans. So they > got the axe in EJB 3.0. > > I haven't had a chance to check out the implementation code, but the > concept lines up very well. > > > -David > > On Jul 31, 2011, at 1:31 PM, Romain Manni-Bucau wrote: > > > I commited, > > > > you can test it with this interface: > > > > @Repository public interface Foo { > > MyEntity findByXXX(String xxx); > > MyEntity findById(long i); > > List<MyEntity> findByBar(int bar); > > // ... > > } > > > > look the logs you'll have the glbal jndi name ;) > > > > - Romain > > > > 2011/7/31 Romain Manni-Bucau <[email protected]> > > > >> 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 > >>>> > >>>> > >>>> > >>>> > >>>> > >> > >> > >
