Programmatically loading Entity classes with JPA 2.0? - java

With Hibernate you can load your Entity classes as:
sessionFactory = new AnnotationConfiguration()
.addPackage("test.animals")
.addAnnotatedClass(Flight.class)
.addAnnotatedClass(Sky.class)
.addAnnotatedClass(Person.class)
.addAnnotatedClass(Dog.class);
Is there a way to do the same thing - programmatically loading your Entity classes - in a JPA 2.0 compliant way?
The reason for this question is because I'd like to dynamically load my Entity classes, thus not necessarily programmatically.

With the help of Spring I did this in a JPA compliant way.
My "persistence.xml" looks empty, with no entities listed within the <persistence-unit> element.
I then wrote a class that implemented PersistenceUnitPostProcessor like so:
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.MappedSuperclass;
import org.reflections.Reflections;
import org.reflections.scanners.TypeAnnotationsScanner;
import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo;
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor;
public class ReflectionsPersistenceUnitPostProcessor implements PersistenceUnitPostProcessor {
private String reflectionsRoot;
private Logger log = LoggerFactory.getLogger(ReflectionsPersistenceUnitPostProcessor.class);
#Override
public void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui) {
Reflections r = new Reflections(this.reflectionsRoot, new TypeAnnotationsScanner());
Set<String> entityClasses = r.getStore().getTypesAnnotatedWith(Entity.class.getName());
Set<String> mappedSuperClasses = r.getStore().getTypesAnnotatedWith(MappedSuperclass.class.getName());
for (String clzz : mappedSuperClasses)
{
pui.addManagedClassName(clzz);
}
for (String clzz : entityClasses)
{
pui.addManagedClassName(clzz);
}
}
public String getReflectionsRoot() {
return reflectionsRoot;
}
public void setReflectionsRoot(String reflectionsRoot) {
this.reflectionsRoot = reflectionsRoot;
}
}
Then I adjusted my spring context xml like this:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="false" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
</bean>
</property>
<property name="persistenceUnitName" value="GenericPersistenceUnit"/>
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml"/>
<property name="persistenceUnitPostProcessors">
<list>
<bean class="com.austinmichael.core.repository.ReflectionsPersistenceUnitPostProcessor">
<property name="reflectionsRoot" value="com.austinmichael"/>
</bean>
</list>
</property>
</bean>
Note the registration of the ReflectionsPersistenceUnitPostProcessor in the persistenceUnitPostProcessors setting.
And that's it. Every class with a JPA Entity or MappedSuperclass annotation on the classpath is added to the classpath. I had to give reflections the prefix of a package name to scan through which is why com.austinmichael is there at all. You could register a second ReflectionsPersistenceUnitPostProcessor with a different package name prefix if you want if your entities don't share a common package name prefix.
But, this is now JPAVendor agnostic.

Is there a way to do the same thing - programmatically loading your Entity classes - in a JPA 2.0 compliant way?
No, this is not supported by JPA so you'll have to do this in a provider specific way. James Sutherland described the process for EclipseLink in this thread like this:
You can access the EclipseLink ServerSession from the EntityManagerFactoryImpl (getServerSession()), and use its' addDescriptor(ClassDescriptor) or addDescriptors() API to add EclipseLink ClassDescriptor. You will need to build the ClassDescriptor meta-data objects directly yourself (or use the Mapping Workbench to create them), as loading from JPA annotations or orm.xml would be more difficult.
Also have a look at this more recent thread for more code sample (the API looks like a bit verbose).
References
Re: [eclipselink-users] Close to get it. Just a little help
Re: JPA: adding entities to EntityManagerFactory programmatically

I don't think there is such option - JPA supports scanning the classpath for entities or explicitly listing the entity classes in the persistence.xml. Since you're using hibernate as the persistence provider however you can always resort to hibernate code. Have a look at the HibernateEntityManager and HibernateEntityManagerFactory classes. You can cast entity manager factories and entity managers to them and do the usual hibernate stuff.

Related

Spring/Hibernate data access concurrency problem

I've been given full responsibility for a bunch of large projects that I didn't write myself and I am hoping for some advice here because these projects have issues that are keeping me up at night and much of this is new to me.
I've noticed that database queries through the ORM will sometimes not find an entity that had requested to be saved already, causing invalid state and crashes. The problem becomes more apparent with more concurrent threads that access the database through the ORM.
All the assistance I can get with troubleshooting would be much appreciated.
Relevant dependencies
Web framework: Spring MVC
ORM: Hibernate
DBMS: MySQL 5.6
ehcache: 2.10.6
Hibernate: 5.1.17.Final
Hibernate validator: 5.4.3.Final
MySQL connector: 5.1.48
Spring: 4.3.29.RELEASE
Spring integration: 4.3.23.RELEASE
Spring security: 4.2.19.RELEASE
The web app runs under Tomcat 7 with Java 8 runtime.
We're behind on several dependencies and I want to tackle that another day.
Troubleshooting
I read that EntityManager by itself is not thread-safe and that #PersistenceContext turns it into a proxy that allows thread-safe access to the underlying EntityManager. I can also see that it's some sort of proxy in the debugger. Now I don't know exactly how that works and whether the way we use it is really safe.
Despite that, I notice the following:
An incoming HTTP request causes an entity to be saved to the database through the ORM.
Shortly afterwards, another incoming HTTP request wants to find the same entity through the ORM.
Most of the time the entity is as expected found, but sometimes it is not found despite the fact that it should have been saved already.
If I try to find the entity on the same thread right after saving it then it's always found, but if I launch a new thread right after saving it then the entity may not be found in that thread unless I Thread.sleep() before the lookup.
I can see in the debugger that the same instance of SomeService, SomeDaoImpl and the EntityManager proxy in the example code below is reused for multiple incoming HTTP requests and handled by different threads.
Even though our own classes are stateless, there is apparently a problem with data access through the ORM.
Greatly simplified pseudocode
interface Dao {
Entity save(entity);
};
abstract class AbstractDao implements Dao {
#PersistenceContext
private EntityManager em; // proxy
#Override
public Entity save(entity) {
return em.persist(entity); // or this.em.merge(entity)
}
protected EntityManager getEntityManager() {
return em;
}
}
abstract class AbstractUuidDao extends AbstractDao {
public Entity findByUuid(uuid) {
em = getEntityManager();
query = em.getCriteriaBuilder().createQuery(...);
// ...
return em.createQuery(query).setParameter(..., uuid).getSingleResult();
}
}
interface SomeDao extends Dao {};
#Repository
class SomeDaoImpl extends AbstractUuidDao implements SomeDao {}
#Service("someService")
#Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
class SomeService {
#Autowired
private SomeDao someDao;
// the first HTTP request calls this
#Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
void createSomething() {
uuid = "random uuid";
someDao.save(new SomeEntity(uuid));
someDao.findByUuid(uuid); // always returns non-null
}
// after createSomething() returns, the transaction is committed
// two HTTP requests can call this simultaneously but they come in after createSomething() has returned, and therefore after the transaction has already been committed
void getSomething(uuid) {
// uuid is the same "random uuid"
someDao.findByUuid(uuid); // can return either null or non-null
}
}
I believe this is the persistence configuration:
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="model" />
<property name="jpaDialect">
<bean class="custom class here" />
</property>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.connection.release_mode" value="after_transaction" />
<entry key="hibernate.current_session_context_class" value="org.springframework.orm.hibernate4.SpringSessionContext" /> <!-- also tried "org.springframework.orm.hibernate5.SpringSessionContext" -->
<entry key="hibernate.cache.use_query_cache" value="true" /> <!-- also tried "false" -->
<entry key="hibernate.cache.use_second_level_cache" value="true" /> <!-- also tried "false" -->
<entry key="hibernate.cache.use_minimal_puts" value="false" />
<entry key="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory" />
<entry key="hibernate.default_batch_fetch_size" value="8" />
<entry key="hibernate.jdbc.fetch_size" value="10" />
<entry key="hibernate.jdbc.batch_size" value="100" />
<entry key="hibernate.order_inserts" value="true" />
<entry key="hibernate.order_updates" value="true" />
<entry key="hibernate.format_sql" value="false" />
<entry key="hibernate.show_sql" value="false" />
</map>
</property>
</bean>
I'm sorry for the lack of real code and details but it is difficult for me to provide a working example without making the example more complex than needed.
Any ideas would be much appreciated.
Update 1
I revised the example code in my original post to more correctly reflect the real use case, but it does not change much.
I can see that everything happens in the expected sequence, i.e. the transaction is committed and subsequent queries only happen afterwards.
I replaced our custom JPA dialect with org.springframework.orm.jpa.vendor.HibernateJpaDialect since it seems like the custom class is no longer needed because it was meant to add support for custom isolation levels. That did not help.
I have upgraded Hibernate from version 5.1.17 to version 5.2.18 and reimplemented an incompatible third party Hibernate user type that prevented the upgrade.
I have not seen a single failure since that upgrade but I will keep testing.
Update 2
The issue does not seem to persist even with Hibernate version 5.2.0 either.
The following bugfix mentioned in the changelog looks very much related to my problem:
[HHH-10649] - When 2LC enabled, flush session and then refresh entity cause dirty read in another session / transaction
If "2LC" means "second-level cache" then I have as mentioned before had the problem even after turning this off.

Populate a datasource during the start of the spring application

I want to run some part of the code to populate the database with dummy data every time the server starts. I use Tomcat as my servlet container. My application is created using Spring. Is there a hook where I can run my code to populate the db just after my application is started?
You have two different alternatives.
The first one is using Spring's DataSourceInitializer. You can pass your initialisation query as a parameter and it executes that query. You can execute any command that you like.
Example:
<bean id="dbInitializer" class="org.springframework.jdbc.datasource.init.DataSourceInitializer">
<property name="dataSource" ref="myDataSourceRef"/>
<property name="enabled" value="true"/>
<property name="databasePopulator">
<bean class="org.springframework.jdbc.datasource.init.ResourceDatabasePopulator">
<property name="continueOnError" value="true"/>
<property name="ignoreFailedDrops" value="true"/>
<property name="sqlScriptEncoding" value="UTF-8"/>
<property name="scripts">
<array>
<value type="org.springframework.core.io.Resource">init.sql</value>
</array>
</property>
</bean>
</property>
</bean>
The second alternative is implementing a Spring ApplicationListener. Populate each datum from that listener to your database manually. It is a little harder to achieve.
Example:
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
public class ApplicationListenerBean implements ApplicationListener {
#Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ContextRefreshedEvent) {
ApplicationContext applicationContext = ((ContextRefreshedEvent) event).getApplicationContext();
// now you can do applicationContext.getBean(...)
// ...
}
}
}
This bean must be initialised by Spring. You can either define it in your applicationContext.xml or in your configuration class.
By the way, you can always listen for your ServletContext status by using a ServletContextListener. But if you are using Spring, there are easier methods.
You can use Liquibase, and if you're using Spring Boot all you have to do is add liquibase-core to your classpath, via maven or whatever build tool you're using is. Spring Boot uses YAML files by default. Spring Boot will then run Liquibase on every application startup.

How to contribute to a list property of a bean using Spring?

I have 3 projects:
framework
product-a
product-b
Each of the products depends on the framework, but they don't know each other.
I have 3 spring configuration files: one for each project. The configuration file of each product includes (with <import resource="classpath:/...) the configuration file of the framework.
In the framework there is a bean called "manager", which has a property List<AnInterface> theList. The "manager" has a addXxx(anImplementation), which adds elements to the list).
The framework, and each of the product provide implementations of AnInterface, which have to be added to theList.
So in the end, when product-a is running, the manager contains implementations from the framework, and from product-a, idem for product-b
What is the best practice to perform this initialization with Spring ?
The only solution I could think about is to create a dedicated class which contructor will take the manager and a list of contributions, and add them to the manager, but it's ugly because 1/ It manipulate external objects in the constructor, 2/ I have to create a dummy class just to initialize other classes... I don't like that.
I think that code should not know about Spring if it is not really needed. Therefore I would do all initialization in Spring config.
We can use bean definition inheritance and property overriding to do it.
Framework class
public class Manager {
private List<AnInterface> theList;
public void init() {
// here we use list initialized by product
}
}
Framework context
<bean id="manager"
init-method="init"
abstract="true"
class="Manager">
<property name="theList">
<list/> <!-- this will be overriden or extnded -->
</property>
</bean>
Product A context
<bean id="managerA"
parent="manager"
scope="singleton"
lazy-init="false">
<property name="theList">
<list>
<ref bean="impl1"/>
<ref bean="impl2"/>
</list>
</property>
</bean>
Watch out for parent and child properties in such configuration. Not all are inherited from parent. Spring documentation specifies:
The remaining settings are always taken from the child definition: depends on, autowire mode, dependency check, singleton, scope, lazy init.
Moreover, there is also collection merging in Spring so by specifing in child bean
<list merge="true">
you can merge parent and child lists.
I have observed this pattern in a number of projects and some extendable Web frameworks based on Spring.
I have accepted the answer of Grzegorz because it's a clean solution to my initial problem, but here as an alternate answer, the a technical solution to contribute to a list property of an existing bean.
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="manager"/>
<property name="targetMethod"><value>addXxx</value></property>
<property name="arguments"><list value-type="com.xxx.AnInterface">
<value ref="impl1" />
<value ref="impl2" />
...
</list></property>
</bean>

Linking Spring project to MySQl database

I have been trying to access MySQL routines from my Spring project using SimpleJdbcDaoSupport.
I have a class called 'AdminSimpleMessageManager', which implements the interface 'AdminMessageManager'.
'AdminSimpleMessageManager' has an instance of the class 'AdminSimpleJdbcMessageDao', which implements the interface 'AdminMessageDao'.
AdminSimpleJdbcMessageDao has the following method:
public class AdminSimpleJdbcMessageDao extends SimpleJdbcDaoSupport implements AdminMessageDao {
public int addMessage(String from, String message) {
return getJdbcTemplate().queryForInt("call insert_contact_message(?, ?)", from, message);
}
}
I have included the following in my application context:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/OctagonDB"/>
</bean>
<bean id="adminMessageManager" class="Managers.AdminSimpleMessageManager">
<property name="adminMessageDao" ref="adminMessageDao"/>
</bean>
<bean id="adminMessageDao" class="Managers.dao.AdminSimpleJdbcMessageDao">
<property name="dataSource" ref="dataSource"/>
</bean>
but I feel there are a few important lines missing. I get the error
FAIL - Deployed application at context path /NewWebsite but context failed to start
among other things.
You need to include a MySQL JDBC driver in your classpath. Furthermore you should update the config of the driver class name to com.mysql.jdbc.Driver. org.gjt.mm.mysql.Driver is only retained for backwards compatibility.
However, since you seem to be loading the datasource through JNDI I guess the driver JAR should be in your container (which provides the datasource through JNDI) rather than in your app's WEB-INF/lib?

Is it possible to have multiple PropertyPlaceHolderConfigurer in my applicationContext?

I need to load a specific applicationContext.xml file according to a given system property. This itself loads a file with the actual configuration. Therefore I need two PropertyPlaceHolderConfigurer, one which resolves the system param, and the other one within the actual configuration.
Any ideas how to do this?
Yes you can do more than one. Be sure to set ignoreUnresolvablePlaceholders so that the first will ignore any placeholders that it can't resolve.
<bean id="ppConfig1" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="locations">
<list>
<value>classpath*:/my.properties</value>
</list>
</property>
</bean>
<bean id="ppConfig2" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="false"/>
<property name="locations">
<list>
<value>classpath*:/myOther.properties</value>
</list>
</property>
</bean>
Depending on your application, you should investigate systemPropertiesMode, it allows you to load properties from a file, but allow the system properties to override values in the property file if set.
Another solution is to use placeholderPrefix property of PropertyPlaceholderConfigurer. You specify it for the second (third, fourth...) configurer, and then prefix all your corresponding placeholders, thus there will be no conflict.
<bean id="mySecondConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="classpath:/myprops.properties"
p:placeholderPrefix="myprefix-"/>
<bean class="com.mycompany.MyClass" p:myprop="${myprefix-value.from.myprops}"/>
Beware -- there might be a bug related to multiple configurers. See http://jira.spring.io/browse/SPR-5719 for more details.
I'm unable to get multiple to work locally... but I'm not yet blaming anyone but myself.
On my own side, playing with PropertyPlaceholderConfigurer both properties :
order (should be lower for first accessed/parsed PPC)
ignoreUnresolvablePlaceholders ("false" for first accessed/parsed PPC, "true" for next one)
and also give 2 distinct id(s) to both PPC (to avoid one to be overwritten by the other)
works perfectly
Hope it helps
You can't do this directly, and this JIRA issue from Spring explains why (check the comment from Chris Beams for a detailed explanation):
https://jira.springsource.org/browse/SPR-6428
However, he does provide a workaround using Spring 3.1 or later, which is to use the PropertySourcesPlaceholderConfigurer class instead of PropertyPlaceholderConfigurer class.
You can download a Maven-based project that demonstrates the problem and the solution from the Spring framework issues github:
https://github.com/SpringSource/spring-framework-issues
Look for the issue number, SPR-6428, in the downloaded projects.
We have the following approach working:
<util:properties id="defaultProperties">
<prop key="stand.name">DEV</prop>
<prop key="host">localhost</prop>
</util:properties>
<context:property-placeholder
location="file:${app.properties.path:app.properties}"
properties-ref="defaultProperties"/>
System property app.properties.path can be used to override path to config file.
And application bundles some default values for placeholders that cannot be defined with defaults in common modules.
Just giving 2 distinct ids worked for me. I am using spring 3.0.4.
Hope that helps.
In case, you need to define two PPC's (like in my situation) and use them independently. By setting property placeholderPrefix, you can retrieve values from desired PPC. This will be handy when both set of PPC's properties has same keys, and if you don't use this the property of ppc2 will override ppc1.
Defining your xml:
<bean name="ppc1"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties" ref="ref to your props1" />
<property name="placeholderPrefix" value="$prefix1-{" />
</bean>
<bean name="ppc2"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties" ref="ref to your props2" />
<property name="placeholderPrefix" value="$prefix2-{" />
</bean>
Retrieving during Run time:
#Value(value = "$prefix1-{name}")
private String myPropValue1;
#Value(value = "$prefix2-{name}")
private String myPropValue2;

Categories