For personal education I am currently developing a little application framework around Guice to learn-by-doing how Spring etc. work behind the scenes.
Intro
Just for the sake of context, here is what I have so far and plan to do so you get a feeling for what I try to archive:
Context (Core)
ApplicationContext/-Configuration
Modules (auto discovered, setting up the Guice bindings)
Extensions
Config: #Config
Locale: #Locale and i18n services
Resources: #Property, #Resource and some classes providing easy access to resources
Persistence: Problems - there we go!
Question
I'd like to use the JDO standard (and its reference implementation DataNucleus) for the persistence layer. Setting up the PersistenceManagerFactory was easy, so was using it in a basic manner. I am however targeting a typical service / repository layer architecture, e.g.:
Person
PersonRepository (JDO)
PersonService (Transactions, using PersonRepository)
That alone wouldn't be too hard either, but as soon as I tried properly integrating transactions into the concept I got a bit lost.
Desired
class PersonService {
#Transactional(TxType.REQUIRED)
public Set<Person> doX() {
// multiple repository methods called here
}
}
class PersonRepository {
private PersistenceManagerFactory pmf;
public Set<Person> doX() {
try (PersistenceManager pm = pmf.getPersistenceManager()) {
pm.....
}
}
}
Difficulties
DataNucleus supports RESOURCE_LOCAL (pm.currentTransaction()) as well as JTA transactions and I would like to support both as well (the user should not have to distinguish between the two outside the configuration). He should not have to bother about transaction handling anyway, that is part of the annotation's method interceptor (I guess).
I'd love to support the #Transactional (from JTA) annotation that can be placed on service layer methods. Knowing that annotation is not per-se available in JDO, I thought it could be made usable as well.
How exactly should the repository layer "speak" JDO? Should each method get a PersistenceManager(Proxy)from the PersistenceManagerFactory and close it afterwards (as in the example) or get a PersistenceManager injected (rather than the factory)? Should each method close the PersistenceManager (in both scenarios)? That would not work with RESOURCE_LOCAL transactions I guess since a transaction is bound to one PersistenceManager.
What I tried
I have a JDOTransactionalInterceptor (working with pmf.getPersistenceManagerProxy) and a JTATransactionalInterceptor (very similar to https://github.com/HubSpot/guice-transactional/blob/master/src/main/java/com/hubspot/guice/transactional/impl/TransactionalInterceptor.java working with a ThreadLocal)
Summary
I am aware that my question may not be as clear as desired and mixes the service / repository layer questions (which is my main problem I think) and transaction stuff (which I could figure out once I understand how to properly use PMF/PM in repository layer I think)
There is no scope à la RequestScoped etc. I just want the first #Transactional method call to be the starting point for that whole thing (and that is the point: Is this impossible and the PMF/PM have to be scoped before and I have to direct my thinkings into that direction?)
Thanks for any clarification / help!
Related
So, I have an application running on WildFly10, which uses JSF, Spring (DI), JPA, Spring Data;
Right now we're trying to move it to CDI and remove Spring(DI). For now we'll keep Spring Data.
So, I set up CDI and made an EntityManager producer.
#Produces
#Dependent
#PersistenceContext
public EntityManager entityManager;
So, I'm able to inject repositories with CDI and all.
However on my original environment we had a custom repository factory,that was defined in my SpringConfiguration like this:
#EnableJpaRepositories(basePackages = {"com.foo.repository" }, repositoryFactoryBeanClass=CustomJpaRepositoryFactoryBean.class)
So, the question is, how can I define this repositoryFactoryBeanClass=CustomJpaRepositoryFactoryBean.class on a CDI environment?
The current implementation doesn't allow the configuration of the JpaRepositoryFactoryBean as one can see from the code where it gets instantiated.
So I guess you have the following options:
reimplement the instantiation process.
open a feature request.
do 2. and 1. in a reusable way and submit the result as a PR for the issue.
When trying to solve this problem I found that the custom impl was not being picked up. The solution suggested in this question helped me however: https://stackoverflow.com/a/38541669/188624
Basically is uses Java8 default interface method to provide the additional functionality. I had to use the "CDI.current().select" method to get hold of the entity manager though as property injection of course won't work.
I tested with Spring Data JPA 2.0.0
This is with reference to JPA 2.0: Adding entity classes to PersistenceUnit *from different jar* automatically and Unable to call Hibernate/QueryDSL from another maven subproject
It seems that Hibernate 4 had a great way to dynamically load entity classes using
org.hibernate.integrator.spi.Integrator service.
Now when using Hibernate 5, the Integrator interface's integrate method gives me
public void integrate(Metadata metadata, SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry)
{
}
Where metadata is of type org.hibernate.boot.Metadata
I am unable to call addAnnotatedClass(), neither I am able to obtain the original Configuration object that was there in Hibernate 4.
How do I get around with this?
I am using maven and jetty.
I am not using spring (so please do not provide any spring based solution)
This was actually related to something I was wrestling with over the weekend in getting caught up on Hibernate 5. You can read about the planned changes related to the Configuration class in the latest Javadoc for Hibernate 4. The new place for getting info on all loaded entity classes including annotated entities is the Metadata class you mentioned. It has a getEntityBindings() method that will return the PersistentClass entity metadata representation for known all entities. This Collection is immutable however.
Recommendation is that you rethink using an Integrator to add entity bindings at runtime. This may have worked in the past, but the docs clearly point towards that not being intentional as this should be done at the time of initialization. The Metadata and SessionFactoryImplementor are for the most part immutable once built, and so the Integrator's intended purpose is not to modify these configuration items but instead use them as information on how to configure new Service integrations using the SessionFactoryServiceRegistry.
And if you're finding it annoying to configure your Session to find all your annotated classes at runtime, I suggest you try using the EntityManagerFactory approach for initializing Hibernate as it is far more straightforward and uses standard JPA syntax that can be switched to a handful of other providers if you ever need to. This will automatically scan for annotated entities on your behalf. The API is a bit more simplified and limited, but if you really ever need the power of native Hibernate-specific functionality there is a way to access the native underlying API.
The issue is the following: in ma Karaf container, I have two modules, the first one is used to fetch data in the DB via a JPA interface implemented by Hibernate. Collections are fetched in a lazy way.
The second module gets the object containing the collections. When trying to access elements of a collection, an error is thrown:
failed to lazily initialize a collection of role:
mapp3.model.ProductDefinition, could not initialize proxy - no Session
It has no session to access the DB and fetch the missing elements.
I know in J2EE there is a concept of Sticky Session that makes a Thread create and share the same session across all beans.
It there something similar in Karaf/OSGi or is there another way of properly acheiving lazy loading between different modules ?
I have just implemented a similar feature in Aries JPA 2.1.0. It uses the OSGi Coordinator spec to share an EntityManager session on a thread. It works together with Aries transaction blueprint 1.3.0 which now also uses a Coordination. Both are available in Apache Karaf 4.0.1.
So to achieve a session that is kept over several calls between beans you annotate the outermost method involved with #Transactional. If you do not want an actual transaction but just the shared EM then you can use #Transaction with type Support. So starting from this method all calls made downwards will share the same em.
So for example you can do something like this:
#Transactional
public void myServiceMethod() {
Person person = personRepo.getPerson();
List<Task> person.getTask();
}
So in the example above the PersonRepo would inject the EntityManager using #PersistenceContext and work with it.
MyService.myServiceMethod would be on the service layer and should not know about jpa or the EntityManager. Still using the #Transactional annoation the method would provide a coordinaton over the execution of the method that holds the EntityManager.
Also see my example Apache Karaf Tutorial Part 9 - Annotation based blueprint and JPA. The example does not show the overarching #Transactional but should get you started easily if you want to dig into it. As soon as the upcoming Aries releases are done I will also create an example that shows exactly the case you are looking for.
I have a #SessionScoped ApplicationBean for storing user login info and injecting it into other managed beans successfully as told here.
I also use my Dao interfaces by #ManagedProperty annotation but I feel something wrong with my usage.
Assume that there is as StockDao that has a public method listStocks(String companyCode) and companyCode is stored in the ApplicationBean when user logins.
So my managed bean is calling the DAO layer like this
#ManagedProperty(value = "#{appBean}")
ApplicationBean appBean;
public void getStockList() {
return stockDao.listStocks(appBean.getCompanyCode());
}
This repeats everywhere where the sql needs companyCode.
I feel that it would be better if my DAO layer had known companyCode (which means injecting ApplicationBean into DAOs) and I should use my methods like below
public void getStockList() {
return stockDao.listStocks();
}
So the question is, which API design would be better and if you vote for the second, how can I inject #SessionScoped beans into DAO layer?
For me 1st approach is much cleaner ,
i dont want to tie DAO layer with the session managed bean.
I keep my general artifacts especially daos and data models packaged as a seperate Jar , without any external dependencies
This way i could use the same without any modifications be it a Web App , Stand Alone or in an EJB
This keeps your Dao independent of how/where the Company Code is fetched from
You do not use session variables in the DAO layer. Lack of business logic and user interface matters is exactly what makes it DAO: a layer responsible just for abstracting data access.
If you add session-dependent state, you will turn your DAO layer into DAAMUIS layer (the ubiquitous Data Access And Miscellaneous User Interface Stuff layer). I am not saying that DAAMUIS is wrong or evil, just that the question needs rephrasing.
How can I inject dependencies into objects that weren't created by a DI framework?
I am running an application on Google App Engine using Objectify, so POJOs are created by Objectify when data is fetched from the datastore. Personally i like having convenience methods to get related objects, like car.getOwner().getName() The car object is created by Objectify. The code of getOwner() owner would be something like
public Person getOwner(){
return PersonService.getById(this.ownerId);
}
I could improve it with a ServiceLocator
public Person getOwner(){
return ServiceLocator.getService(PersonService.class).getById(this.ownerId);
}
But how would I do this with DI?
I looked at Guice, but i can only think of putting the Injector in a singleton and access it from the getOwner method.
Is my thinking flawed?
If you are using Objectify4 you can subclass ObjectifyFactory and override the construct() method. This will allow you to inject your entity classes.
You can see an example here: https://github.com/stickfigure/motomapia/blob/master/java/com/motomapia/OfyFactory.java
The only solution I can think of is load time weaving, I quote:
The context:load-time-weaver registers AspectJ's Load-time Weaver to
the current classloader. So, not only Spring beans will be targeted,
but any class loaded in the classloader that match the defined
pointcuts.
But I think that will conflict with the GAE restrictions but I haven't tried this in GAE yet.