Annotations #ActiveProfile doesn't work in a Spring app - java

I'm not using spring-boot in this app.
I'm testing profiles to use different datasource in integration tests.
I have entity User as follow:
#Table(name = "user_inf")
#Entity
#NamedQuery(name="User.findById", query="select u from User u where u.id=:id")
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
#Column(name = "userName", length = 25)
private String userName;
#Column(name = "userEmail", unique = true, length = 320)
private String userEmail;
}
for that entity I have the service and dao(Service only invokes dao method)
UserDao :
#Repository
#Transactional
public class UserDaoImpl implements UserDao {
#PersistenceContext
private EntityManager entityManager;
#Override
public User findById(Long id) {
TypedQuery<User> query = entityManager.createNamedQuery("User.findById", User.class);
query.setParameter("id", id);
return query.getSingleResult();
}
}
User service :
#Service
public class UserServiceImpl implements UserService{
#Autowired
private UserDao userDao;
#Override
public User getUser(Long id) {
return userDao.findById(id);
}
}
#Configuration
#PropertySource(value = {"classpath:database/jdbc.properties"})
#EnableTransactionManagement
#ComponentScan({"com.example.test.repository", "com.example.test.service"})
public class SpringConfig {
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
private static final String PROPERTY_NAME_HIBERNATE_MAX_FETCH_DEPTH = "hibernate.max_fetch_depth";
private static final String PROPERTY_NAME_HIBERNATE_JDBC_FETCH_SIZE = "hibernate.jdbc.fetch_size";
private static final String PROPERTY_NAME_HIBERNATE_JDBC_BATCH_SIZE = "hibernate.jdbc.batch_size";
private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
private static final String ENTITY_MANAGER_PACKAGES_TO_SCAN = "com.example.test.entity";
#Autowired
private Environment env;
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
dataSource.setUrl(env.getProperty("jdbc.url"));
dataSource.setUsername(env.getProperty("jdbc.username"));
dataSource.setPassword(env.getProperty("jdbc.password"));
return dataSource;
}
#Bean
#Profile("test")
public DataSource dataSourceForTest() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
dataSource.setUrl(env.getProperty("jdbc.test.url"));
dataSource.setUsername(env.getProperty("jdbc.username"));
dataSource.setPassword(env.getProperty("jdbc.password"));
return dataSource;
}
#Bean
public PlatformTransactionManager jpaTransactionManager(LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactoryBean.getObject());
return transactionManager;
}
private HibernateJpaVendorAdapter vendorAdaptor() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setShowSql(true);
return vendorAdapter;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(DataSource mainDataSource) {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setJpaVendorAdapter(vendorAdaptor());
entityManagerFactoryBean.setDataSource(mainDataSource);
entityManagerFactoryBean.setPackagesToScan(ENTITY_MANAGER_PACKAGES_TO_SCAN);
entityManagerFactoryBean.setJpaProperties(jpaHibernateProperties());
return entityManagerFactoryBean;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
private Properties jpaHibernateProperties() {
Properties properties = new Properties();
properties.put(PROPERTY_NAME_HIBERNATE_MAX_FETCH_DEPTH, env.getProperty(PROPERTY_NAME_HIBERNATE_MAX_FETCH_DEPTH));
properties.put(PROPERTY_NAME_HIBERNATE_JDBC_FETCH_SIZE, env.getProperty(PROPERTY_NAME_HIBERNATE_JDBC_FETCH_SIZE));
properties.put(PROPERTY_NAME_HIBERNATE_JDBC_BATCH_SIZE, env.getProperty(PROPERTY_NAME_HIBERNATE_JDBC_BATCH_SIZE));
properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
properties.put("hibernate.hbm2ddl.auto", "none");
return properties;
}
}
Property file which is used for datasource and hibernate (jdbc.properties) contains following :
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/testdatabase
jdbc.username=Bruce
jdbc.password=givanchy
jdbc.test.url=jdbc:mysql://localhost:3306/testdatabase1
hibernate.max_fetch_depth = 3
hibernate.jdbc.fetch_size = 50
hibernate.jdbc.batch_size = 10
hibernate.show_sql = true
hibernate.dialect = org.hibernate.dialect.MySQL8Dialect
Entry point for application :
public class EntryClass {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = applicationContext.getBean("userServiceImpl", UserServiceImpl.class);
User user =userService.getUser(1L);
System.out.println("userName is "+user.getUserName());
}
}
It works as it should.
But in test source
I have only one test for service to understand how profiles work
#SpringJUnitConfig(SpringConfig.class)
#ActiveProfiles("test")
class UserServiceImplTest {
#Autowired
private UserService userService;
#Test
void getUser() {
User user = userService.getUser(5L);
Assertions.assertEquals("Vector", user.getUserName());
}
}
And I get "No qualifying bean" exception because there are two beans of datasource type, but I set which profile it should use?Can you explain why It doesn't work?

When you launch it normally, the datasource bean with 'test' profile is not created. (becasue there is no test profile set.)
When you run it as a test, then both datasource beans are created. The default is created because there is no any condition on it, and the other is becasue its annotated with the test profile.
Simply add #Profile("!test") to the default bean. This way it will be created only if the test profile is NOT active.

Related

Spring Data JPA: very slow insert and select queries

I have a pretty simple spring-data-jpa + Hibernate application, which stores customers data in MySql Database (the full source code is posted here).
The problem is that it runs insert and select queries very slowly, comparing to what I have through mysql CLI:
insert one row takes ~3600ms,
select all (just 2 rows) takes ~1700ms
both queries take in mysql CLI about 0.12s.
There is a similar problem discussed here, however in my case the measurements are way worse (even though I don't insert batch, it's just one simple row in DB). Is there any way to improve performance in Spring JPA/Hibernate?
Another question, is there any way to reduce size of spring-data-jpa and hibernate-entitymanager? I was able to exclude byte-buddy and jandex dependencies without harm to the program, but that's only couple Mbs (the shaded jar size is down from 19.6Mb to 16.6Mb)?
UPDATE
As per request here is the code (the all sources are here):
#Entity
#AttributeAccessor("field")
#Table(name = "customer")
public class Customer implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="id",unique=true, nullable=false, insertable=true, updatable=true)
#Type(type="long")
private Long id;
#Column(name = "name")
private String name;
//+ constructors, getters/setters
}
Here is Spring application and also saving (insert) customer:
public class Application {
private static ApplicationContext applicationContext;
static CustomerRepository customerRepository;
public static void main(String[] args) throws InterruptedException {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MySQLAutoconfiguration.class);
customerRepository = ctx.getBean(CustomerRepository.class);
runTest();
}
private static void runTest () throws {
...
//insert
Customer customerJohn = customerRepository.save(new Customer("John"));
//select
Customer foundEntity = customerRepository.findOne(customerJohn.getId());
...
}
And configuration:
#Configuration
#ComponentScan
#EnableJpaRepositories (basePackages = "com.vk.dal.repository")
#PropertySource("classpath:mysql.properties")
public class MySQLAutoconfiguration {
#Autowired
private Environment env;
#Bean
public DataSource dataSource() {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));
dataSource.setUrl(env.getProperty("spring.datasource.url"));
dataSource.setUsername(env.getProperty("spring.datasource.username") != null ? env.getProperty("spring.datasource.username") : "");
dataSource.setPassword(env.getProperty("spring.datasource.password") != null ? env.getProperty("spring.datasource.password") : "");
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource);
em.setPackagesToScan("com.vk.dal.domain");
em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
Properties properties = additionalProperties();
if (properties != null) {
em.setJpaProperties(properties);
}
return em;
}
#Bean
JpaTransactionManager transactionManager(final EntityManagerFactory entityManagerFactory) {
final JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
final Properties additionalProperties() {
final Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("mysql-hibernate.hbm2ddl.auto"));
hibernateProperties.setProperty("hibernate.dialect", env.getProperty("mysql-hibernate.dialect"));
hibernateProperties.setProperty("hibernate.show_sql", env.getProperty("mysql-hibernate.show_sql") != null ? env.getProperty("mysql-hibernate.show_sql") : "false");
return hibernateProperties;
}
}
Appreciate any help.

hibernate didn't auto update the #ElementCollection

According to the book when i update a ElementCOllection List , i do not do the Transection.begin, the hibernate will auto commit, but i made a test on it, the result has something wrong
My Main.java is
public class Main {
private static UserService userService;
private static Logger logger = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(RootConfig.class);
userService = applicationContext.getBean(UserService.class);
User user = new User("qwerty");
user.getMessages().add("hello,world");
userService.save(user);
User user1 = userService.findByName("qwerty");
user1.getMessages().add("ncjdksckds");
System.out.println(user);
}
}
and my configuration is here , coding according the book
#Configuration
#ComponentScan(basePackages = {"org.zhy"})
#EnableJpaRepositories(basePackages = {"org.zhy.repository"})
#EnableTransactionManagement
public class RootConfig {
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter ) {
LocalContainerEntityManagerFactoryBean emfb =
new LocalContainerEntityManagerFactoryBean();
emfb.setDataSource(dataSource);
emfb.setJpaVendorAdapter(jpaVendorAdapter);
emfb.setPersistenceUnitName("demo");
Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", "create-drop");
emfb.setJpaProperties(hibernateProperties);
emfb.setPackagesToScan("org.zhy.domain");
return emfb;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
// some setting here such as url...
return ds;
}
#Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setGenerateDdl(false);
adapter.setDatabase(Database.MYSQL);
adapter.setShowSql(true);
adapter.setDatabasePlatform("org.hibernate.dialect.MySQLDialect");
return adapter;
}
}
the Entity is here
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#ElementCollection(fetch = FetchType.EAGER)
private List<String> messages = new ArrayList<String>();
//getter and setter
when i use user1.getMessages().add("ncjdksckds");
the database did not auto flush the new message into it , i want to know why????
Not sure which book you are referring to but the key about #ElementCollection in your case is that all operations are cascaded by default.
Assuming your service has all public methods marked as transactional, after you query for the user, it is a detached entity.. as it is from now on outside of any transactional scope.
In your code:
User user = new User("qwerty");
user.getMessages().add("hello,world");
userService.save(user); // new transaction start and finish
User user1 = userService.findByName("qwerty"); // new transaction start and finish
user1.getMessages().add("ncjdksckds"); // this change is outside of a transaction
in order to make that change persistend you would need to merge the user1 entity back into the persistence context:
userService.merge(user1);
Inside you would call:
entityManager.merge(user);

HibernateException: createQuery is not valid without active transaction

The programmatic configuration seems in place but for some reason the application throws exception:
org.springframework.orm.jpa.JpaSystemException: createQuery is not valid without active transaction; nested exception is org.hibernate.HibernateException: createQuery is not valid without active transaction
Code:
#Repository
public class FilmDAOImpl implements FilmDAO {
#Autowired
private HibernateUtil hibernateUtil;
#Autowired
private SessionFactory sessionFactory;
#Override
public List<Film> findFilms(int actorId, int categoryId, int languageId, int releaseYear) {
Query searchQuery = sessionFactory.getCurrentSession().createQuery("from Film " +
"join Actor " +
"join Category " +
"where Category.categoryId=:categoryId " +
"and Film.language.id=:languageId " +
"and Film.releaseYear=:releaseYear " +
"and Actor.actorId=:actorId");
searchQuery.setParameter("categoryId", categoryId);
searchQuery.setParameter("languageId", languageId);
searchQuery.setParameter("releaseYear", releaseYear);
searchQuery.setParameter("actorId", actorId);
return (List<Film>)searchQuery.list();
}
}
Configuration:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories (basePackages = { "com.hibernate.query.performance.persistence" }, transactionManagerRef = "jpaTransactionManager")
#EnableJpaAuditing
#PropertySource({ "classpath:persistence-postgresql.properties" })
#ComponentScan(basePackages = { "com.hibernate.query.performance" })
public class ApplicationConfig {
#Autowired
private Environment env;
public ApplicationConfig() {
super();
}
#Bean
public LocalSessionFactoryBean sessionFactory() {
final LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(applicationDataSource());
sessionFactory.setPackagesToScan(new String[] { "com.hibernate.query.performance.persistence.model" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
final LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(applicationDataSource());
emf.setPackagesToScan(new String[] { "com.hibernate.query.performance.persistence.model" });
final JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
emf.setJpaVendorAdapter(vendorAdapter);
emf.setJpaProperties(hibernateProperties());
return emf;
}
#Primary
#Bean
public DriverManagerDataSource applicationDataSource() {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(Preconditions.checkNotNull(env.getProperty("jdbc.driverClassName")));
dataSource.setUrl(Preconditions.checkNotNull(env.getProperty("jdbc.url")));
dataSource.setUsername(Preconditions.checkNotNull(env.getProperty("jdbc.user")));
dataSource.setPassword(Preconditions.checkNotNull(env.getProperty("jdbc.pass")));
return dataSource;
}
#Bean
#Primary
public PlatformTransactionManager hibernateTransactionManager() {
final HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
transactionManager.setDataSource(applicationDataSource());
return transactionManager;
}
#Bean
public PlatformTransactionManager jpaTransactionManager() {
final JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
private final Properties hibernateProperties() {
final Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
hibernateProperties.setProperty("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
hibernateProperties.setProperty("hibernate.format_sql", env.getProperty("hibernate.format_sql"));
hibernateProperties.setProperty("hibernate.generate_statistics", env.getProperty("hibernate.generate_statistics"));
hibernateProperties.setProperty("hibernate.cache.use_second_level_cache", env.getProperty("hibernate.cache.use_second_level_cache"));
hibernateProperties.setProperty("hibernate.cache.region.factory_class", env.getProperty("hibernate.cache.region.factory_class"));
hibernateProperties.setProperty("hibernate.cache.use_query_cache", env.getProperty("hibernate.cache.use_query_cache"));
hibernateProperties.setProperty("hibernate.current_session_context_class", "managed");
hibernateProperties.setProperty("hibernate.current_session_context_class", "org.hibernate.context.internal.ThreadLocalSessionContext");
return hibernateProperties;
}
}
UPDATE
#Service
#Transactional
public class FilmServiceImpl implements FilmService {
#Autowired
private FilmDAO filmDAO;
#Override
public int createFilm(Film film) {
return filmDAO.createFilm(film);
}
#Override
public Film updateFilm(Film film) {
return filmDAO.updateFilm(film);
}
#Override
public void deleteFilm(int id) {
filmDAO.deleteFilm(id);
}
#Override
public List<Film> getAllFilms() {
return filmDAO.getAllFilms();
}
#Override
public Film getFilm(int id) {
return filmDAO.getFilm(id);
}
#Override
public List<Film> findFilms(int actorId, int categoryId, int languageId, int releaseYear) {
return filmDAO.findFilms(actorId, categoryId, languageId, releaseYear);
}
}
Try using openSession() as below, Since getCurrentSession() just attaches to the current session:
Query searchQuery = sessionFactory.openSession().createQuery(...
Also, you need to surround code with proper try..catch..finally block and in finally close the session using session.close()

NO XML Spring-data-jpa datasources and Junit tests (ManagedType fail)

I have the following classes working as intended if the project is run under "spring-boot:run" maven directive.
But now I'm trying to create a few test-cases just as good practice and I'm struggling to make JUnit understand my XML-less configuration... Here's the relevant code:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef = "emfIntranet", transactionManagerRef = "tmIntranet", basePackages = {"com.vnt.intranet.repositories"})
#ConfigurationProperties(prefix = "databases.sistemas")
public class IntranetPersistence {
private String address;
private String schema;
private String username;
private String password;
private String eclipselinklog;
private Boolean sqllog;
#Primary
#Bean(name = "dsIntranet")
DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setUrl("jdbc:postgresql://" + address + "/" + schema);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setInitialSize(3);
dataSource.setMaxIdle(3);
dataSource.setMaxTotal(10);
return dataSource;
}
private EclipseLinkJpaVendorAdapter getEclipseLinkJpaVendorAdapter() {
EclipseLinkJpaVendorAdapter vendorAdapter = new EclipseLinkJpaVendorAdapter();
vendorAdapter.setDatabasePlatform("org.eclipse.persistence.platform.database.PostgreSQLPlatform");
vendorAdapter.setShowSql(sqllog);
return vendorAdapter;
}
#Primary
#Bean(name = "emfIntranet")
EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setJpaVendorAdapter(getEclipseLinkJpaVendorAdapter());
factoryBean.setDataSource(dataSource());
factoryBean.setPackagesToScan("com.vnt.intranet.entities");
Properties jpaProperties = new Properties();
jpaProperties.put("eclipselink.weaving", "false");
jpaProperties.put("eclipselink.logging.level", eclipselinklog);
factoryBean.setJpaProperties(jpaProperties);
factoryBean.afterPropertiesSet();
return factoryBean.getObject();
}
#Primary
#Bean(name = "tmIntranet")
PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory());
return transactionManager;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSchema() {
return schema;
}
public void setSchema(String schema) {
this.schema = schema;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEclipselinklog() {
return eclipselinklog;
}
public void setEclipselinklog(String eclipselinklog) {
this.eclipselinklog = eclipselinklog;
}
public Boolean getSqllog() {
return sqllog;
}
public void setSqllog(Boolean sqllog) {
this.sqllog = sqllog;
}
}
Testcase:
#ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = {Application.class}, initializers = ConfigFileApplicationContextInitializer.class)
#RunWith(SpringJUnit4ClassRunner.class)
public class ServiceOrderRepositoryTest {
private static Logger logger = LoggerFactory.getLogger(ServiceOrderRepositoryTest.class);
#Autowired
ServiceOrderRepository serviceOrderRepository;
#Test
public void serviceOrderTest() {
ServiceOrder serviceOrderList = serviceOrderRepository.findOne(51152L);
logger.debug("{}", serviceOrderList);
assertThat(serviceOrderList, is(not(nullValue())));
}
}
The error:
Caused by: java.lang.IllegalArgumentException: No [ManagedType] was found for the key class [com.vnt.mkdata.entities.ServiceOrder] in the Metamodel - please verify that the [Managed] class was referenced in persistence.xml using a specific <class>com.vnt.mkdata.entities.ServiceOrder</class> property or a global <exclude-unlisted-classes>false</exclude-unlisted-classes> element.
This test-case will work, of course, if I create a persistence.xml file but that's exactly the point, I don't want one...
Can anybody help me?
Turns out one needs to provide an unique PersistenceUnitName for the datasource... Apparently something is more automated when running from "spring-boot:run" and it's created auto-magically.
So, I just added "factoryBean.setPersistenceUnitName("some-unique-name");" to each DataSource
factoryBean.setPackagesToScan("com.vnt.intranet.entities");
factoryBean.setPersistenceUnitName("intranet");

Get SessionFactory on Java based configured Spring App

I need to upload an image to a database (not sure yet if is a good idea to do this or upload the file and reference it from the database) and I've defined a form and a controller to do that. The problem is that I need to convert the MultipartFile to a Blob object and for that I need to use Hibernate.getLobCreator who needs a Session object.
This is the first time using Java based config and I have the next class to define the persistence context:
#Configuration
#EnableJpaRepositories(basePackages = {
"com.davidmogar.alsa"
})
#EnableTransactionManagement
public class PersistenceContext {
private static final String[] ENTITY_PACKAGES = {
"com.davidmogar.alsa.domain"
};
private static final String PROPERTY_NAME_DB_DRIVER_CLASS = "db.driver";
private static final String PROPERTY_NAME_DB_PASSWORD = "db.password";
private static final String PROPERTY_NAME_DB_URL = "db.url";
private static final String PROPERTY_NAME_DB_USER = "db.username";
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
private static final String PROPERTY_NAME_HIBERNATE_FORMAT_SQL = "hibernate.format_sql";
private static final String PROPERTY_NAME_HIBERNATE_HBM2DDL_AUTO = "hibernate.hbm2ddl.auto";
private static final String PROPERTY_NAME_HIBERNATE_NAMING_STRATEGY = "hibernate.ejb.naming_strategy";
private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
#Bean(destroyMethod = "close")
DataSource dataSource(Environment environment) {
HikariConfig dataSourceConfig = new HikariConfig();
dataSourceConfig.setDriverClassName(environment.getRequiredProperty(PROPERTY_NAME_DB_DRIVER_CLASS));
dataSourceConfig.setJdbcUrl(environment.getRequiredProperty(PROPERTY_NAME_DB_URL));
dataSourceConfig.setUsername(environment.getRequiredProperty(PROPERTY_NAME_DB_USER));
dataSourceConfig.setPassword(environment.getRequiredProperty(PROPERTY_NAME_DB_PASSWORD));
return new HikariDataSource(dataSourceConfig);
}
#Bean(name = "entityManagerFactory")
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(DataSource dataSource, Environment environment) {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource);
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
entityManagerFactoryBean.setPackagesToScan(ENTITY_PACKAGES);
Properties jpaProperties = new Properties();
jpaProperties.put(PROPERTY_NAME_HIBERNATE_DIALECT, environment.getRequiredProperty
(PROPERTY_NAME_HIBERNATE_DIALECT));
jpaProperties.put(PROPERTY_NAME_HIBERNATE_HBM2DDL_AUTO, environment.getRequiredProperty
(PROPERTY_NAME_HIBERNATE_HBM2DDL_AUTO));
jpaProperties.put(PROPERTY_NAME_HIBERNATE_NAMING_STRATEGY, environment.getRequiredProperty
(PROPERTY_NAME_HIBERNATE_NAMING_STRATEGY));
jpaProperties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, environment.getRequiredProperty
(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
jpaProperties.put(PROPERTY_NAME_HIBERNATE_FORMAT_SQL, environment.getRequiredProperty
(PROPERTY_NAME_HIBERNATE_FORMAT_SQL));
entityManagerFactoryBean.setJpaProperties(jpaProperties);
return entityManagerFactoryBean;
}
#Bean
JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
}
How can I get the Session in the controller to convert the MultipartFile?
You can get an instance of Hibernate Session via EntityManager.
#Autowired
private EntityManagerFactory emf;
public void foo(){
EntityManager em = emf.createEntityManager();
Session session = em.unwrap(Session.class);
LobCreator lob = getLobCreator(session);
...
}

Categories