|
View:
New views
2 Messages
—
Rating Filter:
Alert me
|
|
|
Help with interesting little pointcut: automatically persist @Entity classesHi all,
Looking for a little design help with a nice little pointcut that I came up with while exploring the use of persistent interfaces in a JPA project I'm working on. I have a requirement to call em.persist(thing) on certain types, and, in an effort to make that transparent, I've added after returning advice that executes after @Entity constructors. It works nicely, except for one thing: it's called whenever the persistence provider instantiates a class as well as when the application does. My question becomes, then, how do I invoke the automatic persistence for only those invocations that come from non-persistence providers? I can't just skip doing it when a no-args constructor is called, because, while many of them are added by enhancement, some of the entities have bona fide no-arg constructors. My strategy is pretty straightforward: * Add <context:spring-configured /> to my application context * Add spring-aspects.jar to my aspect path * Create an aspect that introduces @Configurable for every @Entity and inject the EntityManager into each domain object: public aspect SpringConfigurableMixin { public static interface HasEntityManager { EntityManager getEntityManager(); } declare @type : (@Entity *) : @Configurable(autowire = Autowire.BY_TYPE, preConstruction = true); declare parents : (@Entity *) implements HasEntityManager; @PersistenceContext transient private EntityManager HasEntityManager.em; public EntityManager HasEntityManager.getEntityManager() { return em; } } * Now that every @Entity has the current thread's EntityManager, introduce an @Autopersist annotation (or let the user do it -- see code comment) for every @Entity, then, for every @Entity that is also annotated with @Autopersist, call persist after construction: privileged aspect AutopersistAspect { private static Logger log = LoggerFactory.getLogger(AutopersistAspect.class); pointcut autopersistentEntity(SpringConfigurableMixin.HasEntityManager entity) : within(@Entity *) && ((within(@Autopersist *) && execution(*.new(..))) || execution(@Autopersist *.new(..)) || execution(@Autopersist * *(..))) && target(entity); // introduce @Autopersist: not really necessary, just convenient declare @type : (@Entity *) && (!@Autopersist *) : @Autopersist; after(SpringConfigurableMixin.HasEntityManager entity) returning : autopersistentEntity(entity) { EntityManager em = entity.getEntityManager(); if (em == null) { log.warn("can't automatically persist object of type [" + entity.getClass() + ": EntityManager is null"); } else if (em.contains(entity)) { log.warn("skipping autopersistence of entity of type [" + entity.getClass() + "]: entity already persistent via EntityManager [" + em + "]"); } else { log.info("automatically persisting object of type [" + entity.getClass() + " with EntityManager [" + em + "]"); em.persist(entity); log.debug("automatically persisted object of type [" + entity.getClass() + " with EntityManager [" + em + "]"); } } } Now this almost does the trick. Problem is, too many constructor invocations are advised: not only the ones called by the object model client or internally by other object model classes, but also the ones called by the persistence provider as well, resulting, not surprisingly, in a StackOverflowError. My question: how can I design a way to only advise constructors **not** called by the persistence provider? Alternatively, how can I design a way to only advise constructors called from within the object model or from object model clients? Thanks, Matthew -- mailto:matthew@... skype:matthewadams12 yahoo:matthewadams aol:matthewadams12 google-talk:matthewadams12@... msn:matthew@... http://matthewadams.me http://www.linkedin.com/in/matthewadams _______________________________________________ aspectj-users mailing list aspectj-users@... https://dev.eclipse.org/mailman/listinfo/aspectj-users |
|
|
Re: Help with interesting little pointcut: automatically persist @Entity classesHi Matthew,
Here is where you can use cflow to good measure: pointcut insidePersistenceProvider() : cflow(within(PersistenceProvider)); And add && !insidePersistenceProvider() to your autopersistentEntity pointcut. Just a warning though, your autopersistentEntity pointcut is looking a little complex. I'd try breaking it up or documenting it a bit. 3 months from now, I'm going to guess that you will have no idea what that pointcut does any more. --a > Now this almost does the trick. Problem is, too many constructor > invocations are advised: not only the ones called by the object model > client or internally by other object model classes, but also the ones > called by the persistence provider as well, resulting, not > surprisingly, in a StackOverflowError. > > My question: how can I design a way to only advise constructors > **not** called by the persistence provider? Alternatively, how can I > design a way to only advise constructors called from within the object > model or from object model clients? aspectj-users mailing list aspectj-users@... https://dev.eclipse.org/mailman/listinfo/aspectj-users |
| Free embeddable forum powered by Nabble | Forum Help |