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
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>
> >>
> >>
>
>

Reply via email to