Availability | Confluence 7.17 or later |
In Confluence 8.0, we will remove support for Hibernate2 across Confluence. This will allow us to upgrade Hibernate more frequently without breaking your app, or requiring you to do significant testing and rework when things change.
For apps this means:
Your app uses Hibernate2 if:
net.sf.hibernate.*
packages.When testing your app in Confluence, you can also set the following system property. It will log warnings if your app makes use of PluginHibernateSessionFactory
to use Hibernate sessions directly. This property is available from Confluence 7.18.
1 2-Dcheck-confluence8-compatibility=true
Check your app's pom.xml
, look for any dependencies on Hibernate 2 packages, and remove them.
You should also remove any occurrences of net.sf.hibernate.*
.
1 2<build> <plugins> <plugin> ... <configuration> <instructions> <Import-Package> ... net.sf.hibernate, net.sf.hibernate, net.sf.hibernate.cache, net.sf.hibernate.collection, net.sf.hibernate.connection, net.sf.hibernate.dialect, net.sf.hibernate.engine, net.sf.hibernate.exception, net.sf.hibernate.metadata, net.sf.hibernate.persister, net.sf.hibernate.type, ... </Import-Package> ... </build>
If your app uses any Custom Hibernate queries, there is a new way of using custom queries. You should use content-custom-query
over content-hibernate-2-query
.
If your code uses any implementations of com.atlassian.confluence.content.persistence.hibernate.HibernateContentQueryFactory
make sure you remove the override of the deprecated method public Query getQuery(Session session, Object... parameters)
, as it will be deleted in Confluence 8.0. Use the non-deprecated method public Query getQuery(EntityManager entityManager, Object... parameters)
and override it instead. For example:
1 2public class FindInSpaceByMessageIdQueryFactory implements HibernateContentQueryFactory { @Override public Query getQuery(Session session, Object... parameters) throws HibernateException { long spaceId = (Long) parameters[0]; String messageId = (String) parameters[1]; Query query = session.createQuery("from CustomContentEntityObject content " + "left join content.contentProperties as props " + "where content.originalVersion is null and " + "content.space.id = :spaceId and " + "props.name = 'messageId' and " + "props.stringValue = :messageId "); query.setParameter("spaceId", spaceId, Hibernate.LONG); query.setParameter("messageId", messageId, Hibernate.STRING); return query; } }
1 2public class FindInSpaceByMessageIdQueryFactory implements HibernateContentQueryFactory { @Override public Query getQuery(EntityManager entityManager, Object... parameters) throws PersistenceException { long spaceId = (Long) parameters[0]; String messageId = (String) parameters[1]; Query query = entityManager.createQuery("from CustomContentEntityObject content " + "left join content.contentProperties as props " + "where content.originalVersion is null and " + "content.space.id = :spaceId and " + "props.name = 'messageId' and " + "props.stringValue = :messageId "); query.setParameter("spaceId", spaceId); query.setParameter("messageId", messageId); return query; } }
The tag content-custom-query
was introduced in Confluence 7.17. We recommended you use content-custom-query
over content-hibernate-2-query
as content-hibernate-2-query
may be removed in future.
In the meantime, you can use both to define your custom queries with two modules having version restrictions as in the example below.
1 2<content-hibernate-2-query query-name="query-name" key="legacy-query-name" class="com.test.MyQueryFactory"> <restrict application="confluence" version="(,7.17.0)" /> </content-hibernate-2-query> <content-custom-query query-name="query-name" key="my-query-name" class="com.test.MyQueryFactory"> <restrict application="confluence" version="[7.17.0,)" /> </content-custom-query>
PluginHibernateSessionFactory
usage is no longer supported. If your code uses the com.atlassian.hibernate.PluginHibernateSessionFactory
class to get sessions you should remove the component-import
for this class from atlassian-plugin.xml
(if present) and use the EntityManagerProvider
instead.
1 2<component-import key="pluginHibernateSessionFactory" interface="com.atlassian.hibernate.PluginHibernateSessionFactory"/>
1 2<component-import key="entityManagerProvider" interface="com.atlassian.confluence.persistence.EntityManagerProvider"/>
You should also remove the component-import
annotations for this class from your java code (if present) and use the EntityManagerProvider
instead.
1 2@ComponentImport PluginHibernateSessionFactory pluginHibernateSessionFactory
1 2@ComponentImport EntityManagerProvider entityManagerProvider,
The EntityManagerProvider
can be used to replace the corresponding methods from Session
.
1 2Session session = pluginHibernateSessionFactory.getSession(); session.save(someObject); session.delete(someObject); Query titleQuery = hibernateSession.createQuery(queryString); List<String> titles = (List<String>) titleQuery.list();
1 2EntityManager entityManager = entityManagerProvider.getEntityManager(); entityManager.persist(propertySetItem); entityManager.remove(propertySetItem); Query titleQuery = entityManager.createQuery(queryString); List<String> titles = (List<String>) titleQuery.getResultList();
We strongly recommend you use EntityManagerProvider
to execute the database queries. In some cases getting a JDBC connection may be required.
TransactionalExecutorFactory
provides the ability to execute a block of code/lambda with a JDBC connection.
1 2PluginHibernateSessionFactory pluginHibernateSessionFactory; Connection connection = pluginHibernateSessionFactory.getSession().getConnection(); doSomethingUsingConnection(connection);
1 2TransactionalExecutorFactory transactionalExecutorFactory; transactionalExecutorFactory.create().execute(connection -> { doSomethingUsingConnection(connection); });
In this example, your class has a constructor parameter of type EntityMangerProvider
which needs to be injected by the framework as below:
1 2public Example(final @ComponentImport EntityManagerProvider entityManagerProvider) { this.entityManagerProvider = entityManagerProvider; }
You want to write integration tests for your above class Example
, but you realise that in your test environment the EntityManagerProvider
bean is not available and can't be injected.
Our suggestion in this situation is to mock EntityManagerProvider
and create a concrete EntityManager
instance to carry on your integration test because EntityManager
instance is the main one that does actual job. Here's an example using a MySQL database:
1 2@Mock protected EntityManagerProvider entityManagerProvider; @Mock protected EntityManager entityManager; public void setUp() throws Exception { final EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("testconfig", getTestConnectionProperty()); entityManager = entityManagerFactory.createEntityManager(); when(entityManagerProvider.getEntityManager()).thenReturn(entityManager); } private Map<String, Object> getTestConnectionProperty() { final Map<String, Object> connectionProperties = new HashMap<>(); connectionProperties.put("provider", org.hibernate.jpa.HibernatePersistenceProvider.class); connectionProperties.put("javax.persistence.jdbc.url", "url"); connectionProperties.put("javax.persistence.jdbc.user", "username"); connectionProperties.put("javax.persistence.jdbc.password", "password"); connectionProperties.put("javax.persistence.jdbc.driver", mysql.getJdbcDriverInstance().getClass().getName()); return connectionProperties; }
From the above code you can see we have passed testconfig
as persistanceUnitName
parameter in the createEntityManagerFactory
method. To do this you need to create a persistence.xml
file under your test/resources/META-INF
folder, as shown below:
In the image above you can see we've used persistence header version 2.0. You may need to change it depending on your environment otherwise you may get a parser error.
Rate this page: