Convert existing Spring application to Spring-Boot - java

I have configured and working Spring-based REST application, but now I'd like to convert it to Spring-Boot.
My application uses Spring-Data-JPA on top of JPA datasource with Hibernate provider:
#Configuration
#EnableJpaRepositories("foo.bar.web.repository")
#EnableTransactionManagement
public class RepositoryConfig {
// properties ommited
#Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(className);
dataSource.setUrl(url);
dataSource.setUsername(userName);
dataSource.setPassword(password);
return dataSource;
}
#Bean
public EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
factory.setPackagesToScan("foo.bar.web.domain");
factory.setDataSource(dataSource());
factory.setJpaPropertyMap(new HashMap<String, Object>() {{
put("hibernate.dialect", dialect);
put("hibernate.hbm2ddl.auto", hbm2ddl);
}});
factory.afterPropertiesSet();
return factory.getObject();
}
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory());
return transactionManager;
}
}
My REST endpoints implemented using SpringMVC with following configuration:
#Configuration
#EnableWebMvc
#ComponentScan("foo.bar.web.controller")
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Bean
public MultipartResolver multipartResolver() {
return new CommonsMultipartResolver();
}
}
Web initializer:
public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{
ApplicationConfig.class,
RepositoryConfig.class
};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{MvcConfig.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
The problem is that I don't want to use Spring-Boot auto configuration because I'd like to reuse my existing configuration classes with minimal changes, but I cannot find correct way to do this. I tried to implement Spring-boot application class annotated with #SpringBootApplication, but I'm not 100% sure that my config classes is used, because in this case I get java.lang.ClassCastException: org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean$$EnhancerBySpringCGLIB$$ba21071f cannot be cast to javax.persistence.EntityManagerFactory.
Also I tried throw away #EnableAutoConfiguration annotation from application class and add TomcatEmbeddedServletContainerFactory bean to my context manually, but in this case the embedded tomcat is not configured properly.
It would be great if somebody can give me a hint how to solve my problem. I believe that all I need to do is somehow replace my WebInitilizer with Spring-Boot config.

After spending a day in a research, I finally found a solition of my problem.
First of all I had to modify my entityManagerFactory() and transactionManager() beans:
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
factory.setPackagesToScan("foo.bar.web.domain");
factory.setDataSource(dataSource());
factory.setJpaPropertyMap(new HashMap<String, Object>() {{
put("hibernate.dialect", dialect);
put("hibernate.hbm2ddl.auto", hbm2ddl);
}});
factory.afterPropertiesSet();
return factory;
}
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
Also I totally removed my WebInitializerclass and removed #EnableWebMvc annotation from MvcConfig. In Spring-Boot it's not possible to have class extended from WebMvcConfigurerAdapter in classpath because if Spring-Boot find it, all automatic configuration related to SpringMVC will be skipped. Here is the final version of my MvcConfig class:
#Configuration
#ComponentScan("foo.bar.web.controller")
public class MvcConfig {
#Bean
public MultipartResolver multipartResolver() {
return new CommonsMultipartResolver();
}
}
I used the version of Spring-Boot application class which shown in doc:
#SpringBootApplication(exclude = MultipartAutoConfiguration.class)
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
Note, that in my case I had to exclude MultipartAutoConfiguration from auto configuration because I've already have this feature configured in MvcConfig. Bun it is also possible to leave it autoconfigured, but in this case I had to tune allowed file size in application.properties config file or add a MultipartConfigElement bean to my classpath.

Related

Spring : Add properties file externally

I am working on a Spring-MVC application in which we are preparing to setup application on different servers. As each server can have it's own database related configuration, we are hoping to use an external properties file(outside the war file) which can be read while project is starting. How do I go about this approach?
For making it work, I have already moved application initialization code to Java, this way, static XML reading which we had before won't be required.
But, we are unsure how to create and add a properties file dynamically which atleast has these 3 values(JDBC URL containing DB name, username, password). All tables, other data will be created automatically.
Here is the class where app is initialized :
WebConfig.java :
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = {"com.ourapp.spring"})
#EnableTransactionManagement
#EnableCaching
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
}
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
}
#Bean
public ReloadableResourceBundleMessageSource messageSource(){
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("../resources/locale/messages.properties");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
#Bean
public LocaleChangeInterceptor localeInterceptor(){
LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
interceptor.setParamName("lang");
return interceptor;
}
#Bean
public MappingJackson2HttpMessageConverter converter() {
return new MappingJackson2HttpMessageConverter();
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/img/**").addResourceLocations("/img/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
}
#Bean
public InternalResourceViewResolver getInternalResourceViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("../webapp/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
#Bean
public DoNotTruncateMyUrls doNotTruncate(){
return new DoNotTruncateMyUrls();
}
#Bean
public MultipartResolver multipartResolver() {
return new StandardServletMultipartResolver();
}
#Bean
#Qualifier("primary_tx")
public HibernateTransactionManager getPrimaryTransactionManager() throws IOException {
HibernateTransactionManager txName= new HibernateTransactionManager();
txName.setSessionFactory(sessionFactory().getObject());
return txName;
}
#Bean
#Qualifier("extended_tx")
public HibernateTransactionManager txName() throws IOException {
HibernateTransactionManager txName= new HibernateTransactionManager();
txName.setSessionFactory(getExtendedSessionFactory().getObject());
return txName;
}
#Bean
#Qualifier("sessionFactory_origin")
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(new DataSourceConfig().primaryDataSource());
sessionFactory.setPackagesToScan("com.ourapp.spring");
return sessionFactory;
}
#Bean
#Qualifier("sessionFactory_extended")
public LocalSessionFactoryBean getExtendedSessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(new DataSourceConfig_Extended().secondaryDataSource());
sessionFactory.setPackagesToScan("com.ourapp.spring");
return sessionFactory;
}
}
Thank you. :-)
Probably what you are looking for is Profiles( #Profile or #Conditional )
Step1: Create a profile. The following is the example for prod profile. Similarly, you can create one for dev and qa
import javax.activation.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.jndi.JndiObjectFactoryBean;
#Configuration
#Profile("prod")
#PropertySource("classpath:/com/<SomePath>/app.properties")
public class ProductionProfileConfig {
#Autowired Environment env;
#Bean
public DataSource dataSource() {
JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();
jndiObjectFactoryBean.setJndiName(env.getProperty("dbName"));
jndiObjectFactoryBean.setResourceRef(true);
jndiObjectFactoryBean.setProxyInterface(javax.sql.DataSource.class);
return (DataSource) jndiObjectFactoryBean.getObject();
}
}
Step2 Activate profiles
Spring honors two separate properties when determining which profiles
are active: spring.profiles.active and spring.profiles.default. If
spring.profiles.active is set, then its value determines which
profiles are active. But if spring .profiles.active isn’t set, then
Spring looks to spring.profiles.default. If neither
spring.profiles.active nor spring.profiles.default is set, then there
are no active profiles, and only those beans that aren’t defined as
being in a profile are created
UPDATE
Use PropertyConfigurator.configure(Loader.getResource(<your-file-path>)); if the file is located outside the packaged war. Later you can simply inject values using #Value or SPel
Write a config manager, which will create configuration objects based on the name of properties file. For example,
Configuration config = ConfigurationManager.getConfig("dbConfig");
so, now your config object will contain all properties related to db. When you instantiate config object read all properties into this object.
Let's say your properties file contains following fields:
user.name = "Tom"
user.password = "pass"
Next time when you need "user.name", you would just do config.getString("user.name")
You can do this using PropertySourcesPlaceholderConfigurer
Create a bean like this
#Bean
public static PropertySourcesPlaceholderConfigurer devPropertyPlaceholderConfigurer() throws IOException {
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
configurer.setLocations(new PathMatchingResourcePatternResolver().getResources("file:pathtToFile"));
configurer.setIgnoreUnresolvablePlaceholders(true);
return configurer;
}
For example if you write file:/tmp/dev/*.properties . It will load all the properties file under /tmp/dev.
If you want to customize it based on differnt environment(dev, testing, production). then you can use #Profile and create multiple beans.
#Bean
#Profile("dev")
public static PropertySourcesPlaceholderConfigurer devPropertyPlaceholderConfigurer() throws IOException {
..... // give dev properties file path
}
#Bean
#Profile("testing")
public static PropertySourcesPlaceholderConfigurer testPropertyPlaceholderConfigurer() throws IOException {
.....// give test properties file path
}
#Bean
#Profile("prod")
public static PropertySourcesPlaceholderConfigurer prodPropertyPlaceholderConfigurer() throws IOException {
.....// give prod properties file path
}

spring boot swing application with multiple data sources

I am trying to build a standalone desktop spring application, the application should get the information from multiple data sources. The problem I facing is that #Autowired Repository is null Bellow is my project setup, I thinking because of the application is desktop I am missing some configuration
Main Class
#SpringBootApplication(exclude = HibernateJpaAutoConfiguration.class)
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class)
.headless(false)
.web(false)
.run(args);
}
#Bean
public Main frame() {
return new Main();
}
}
DB Config Second is configured the same way. Additionally here IntelliJ shows that EntityManagerFactoryBuilder builder bean cannot be autowired
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "notificationEntityManagerFactory",
basePackages = { "org.thebot.notification.repository" })
public class NotificationDBConfig {
#Primary
#Bean(name = "notificationDataSource")
#ConfigurationProperties(prefix="spring.notificationDatasource")
public DataSource notificationDataSource() {
return DataSourceBuilder.create().build();
}
#Primary
#Bean(name = "notificationEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean notificationEntityManagerFactory(
EntityManagerFactoryBuilder builder,
#Qualifier("notificationDataSource") DataSource dataSource) {
return builder
.dataSource(dataSource)
.packages("org.thebot.notification.domain")
.persistenceUnit("notification")
.build();
}
#Primary
#Bean(name = "notificationTransactionManager")
public PlatformTransactionManager notificationTransactionManager(
#Qualifier("notificationEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
}
Repository
#Repository
public interface NotificationRepository extends JpaRepository<Notification, Long> {
}
Place where the repository is needed
public class NotificationTab {
#Autowired
private PopulationRepository populationRepository;
private JPanel notificationPanel;
}

how can i parameterize datasource properties on Spring 4?

I am using Spring 4.16. I want to parameterize my persistence data. This is my config right now:
#Configuration
#EnableTransactionManagement
public class PersistenceConfiguration {
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
entityManager.setDataSource(this.dataSource());
entityManager.setPackagesToScan(new String[] {"com.example.movies.domain"});
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
entityManager.setJpaVendorAdapter(vendorAdapter);
entityManager.setJpaProperties(this.properties());
return entityManager;
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/sarasa_db");
dataSource.setUsername("root");
dataSource.setPassword("mypassword");
return dataSource;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
private Properties properties() {
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "update");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
properties.setProperty("hibernate.show_sql", "false");
return properties;
}
}
And i want to parameterize on my application.properties all things i can. First of all, i want to put in datasource properties (so as i was reading, is possible that spring builds my datasource automatically, but apparently that is only using JdbcTemplate...):
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/sarasa_db
spring.datasource.username=root
spring.datasource.password=mypassword
And, if it's possible, all the Properties's properties, which i couldn't find nothing in doc
Do you know how could i do it ?
EDIT
This is my DAO implementation
#Configuration
#Import(PersistenceConfiguration.class)
public class DAOConfiguration {
#PersistenceContext
private EntityManager entityManager;
#Bean
public ClientDAO clientDAO() {
SimpleJpaRepository<Client, String> support = this.getSimpleJpaRepository(Client.class);
return new MySQLClientDAO(support);
}
#Bean
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
#Description("Hibernate repository helper")
protected <T> SimpleJpaRepository<T, String> getSimpleJpaRepository(Class<T> domainClass) {
return new SimpleJpaRepository<T, String>(domainClass, this.entityManager);
}
}
You could do something like this:
First define PropertySourcesPlaceholderConfigurer bean somewhere in your Spring configuration:
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer();
ppc.setLocation(new ClassPathResource("application.properties"));
return ppc;
}
This configuration assumes that application.properties file is placed at the root of your classpath.
After setting up the property placeholder configurer you can access the properties in your database configuration class like so:
#Configuration
#EnableTransactionManagement
public class PersistenceConfiguration {
#Value("${spring.datasource.url}")
private String jdbcUrl;
// ...
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(jdbcUrl);
// ...
}
}
If you want an easy way to parametrize all properties, you should take a look at Spring Boot. It uses the application.properties file to automatically create data source with those properties, and many other things. This is probably the automatic datasource creation you mentioned in your question.

Different PersistenceConfig.java for development and production

Below is the PersistenceConfig.java file which I use for development. However in production, that would look quite different since I'm using postgresql there. What is a good way to deal with that? So I'm not forced into a if-else hell.
import ...;
#Configuration
#EnableJpaRepositories
public class PersistenceConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setDataSource(dataSource());
factory.setPackagesToScan(packagesToScan);
factory.setJpaVendorAdapter(jpaVendorAdapter());
// factory.setJpaProperties(additionalProperties());
return factory;
}
#Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
hibernateJpaVendorAdapter.setShowSql(true);
hibernateJpaVendorAdapter.setGenerateDdl(true);
hibernateJpaVendorAdapter.setDatabase(Database.H2);
return hibernateJpaVendorAdapter;
}
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
}
Use Spring Profiles to differentatie between environments. I would configure everything for production and just override for dev. Also move some properties to a properties file.
#Configuration
#EnableJpaRepositories
#PropertySource("classpath:application.properties")
public class PersistenceConfig {
#Autowired
private Environment env;
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean
public DataSource dataSource() {
// Production configuration
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setDataSource(dataSource);
factory.setPackagesToScan(packagesToScan);
factory.setJpaVendorAdapter(jpaVendorAdapter());
// factory.setJpaProperties(additionalProperties());
return factory;
}
#Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
hibernateJpaVendorAdapter.setShowSql(env.getProperty("hibernate.show-sql", Boolean.class, false));
hibernateJpaVendorAdapter.setGenerateDdl(env.getProperty("hibernate.generate-schema", Boolean.class, false));
hibernateJpaVendorAdapter.setDatabasePlatform(env.getProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQL82Dialect" );
return hibernateJpaVendorAdapter;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
#Configuration
#Profile("dev")
public static class DevPersistenceConfig {
#Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();
}
}
}
Something like that should work. The defaults are configured for production and when the profile dev is active (can be set using the spring.profiles.active property as environment variable) then the datasource will be overridden by the one in the DevPersistenceConfig class.
The dialect can be set using an entry in the application.properties file (or whatever you like to name it).

Spring Data CrudRepository on java based configuration - EntityManager - no transaction is in progress

I've read I believe tried all of the posts on this, but no luck in finding the right answer.
I am using java based configuration with my spring mvc project, and wanted to try Spring CrudRepository, to get away from DAOs, and that is when the whole hell broke loose:
started with "no transaction is in progress" on flush after persist:
- tried adding #Transactional to the method - none of the variations found here worked
- tried changing configuration, but since it is java based, most of the answers are xml based. no luck either.
So finally I have to ask:
How to configure my project to make CrudRepository persist, or how to create Spring EntityManager using java configuration.
This is the last version of my configuration file:
#Configuration
#ComponentScan(basePackages = { "ba.fit.vms" })
#ImportResource(value = "classpath:spring-security-context.xml")
#EnableTransactionManagement
#EnableJpaRepositories
public class AppConfig {
#Bean
public static PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() {
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.setLocation(new ClassPathResource("/persistence.properties"));
return ppc;
}
// Security Configuration
#Bean
public KorisnickiServis korisnickiServis(){
return new KorisnickiServis();
}
#Bean
public TokenBasedRememberMeServices rememberMeServices() {
return new TokenBasedRememberMeServices("remember-me-key", korisnickiServis());
}
#Bean
public PasswordEncoder passwordEncoder() {
return new StandardPasswordEncoder();
}
// Jpa Configuration
#Value("${dataSource.driverClassName}")
private String driver;
#Value("${dataSource.url}")
private String url;
#Value("${dataSource.username}")
private String username;
#Value("${dataSource.password}")
private String password;
#Value("${hibernate.dialect}")
private String dialect;
#Value("${hibernate.hbm2ddl.auto}")
private String hbm2ddlAuto;
#Bean
public DataSource configureDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean configureEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(configureDataSource());
entityManagerFactoryBean.setPackagesToScan("ba.fit.vms");
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
Properties jpaProperties = new Properties();
jpaProperties.put(org.hibernate.cfg.Environment.DIALECT, dialect);
jpaProperties.put(org.hibernate.cfg.Environment.HBM2DDL_AUTO, hbm2ddlAuto);
//jpaProperties.put(org.hibernate.cfg.Environment.SHOW_SQL, true);
entityManagerFactoryBean.setJpaProperties(jpaProperties);
return entityManagerFactoryBean;
}
#Bean
public PlatformTransactionManager transactionManager() {
final JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(configureEntityManagerFactory().getObject());
return transactionManager;
}
}
I've tried number of variations, but was always receiving same "no transaction is in progress" error.
Also, just a glimpse at the repos:
LokacijaRepository:
#Transactional
public interface LokacijaRepository extends CrudRepository<Lokacija, Long> {
}
And LokacijaRepositoryImpl:
#Repository
public class LokacijaRepositoryImpl implements LokacijaRepository {
protected static Logger logger = Logger.getLogger("repo");
#PersistenceContext // tried this as well(type= PersistenceContextType.EXTENDED)
private EntityManager entityManager;
#Override
#Transactional// tried number of variations here as well, like REQUIRED...
public <S extends Lokacija> S save(S entity) {
logger.debug("trying to save!");
try {
entityManager.persist(entity);
entityManager.flush();
return entity;
} catch (Exception e) {
logger.debug("error: "+ e.toString());
return null;
}
}
If you need anything else to help me figure this one out, let me know.
The problem is that you are attempting to create an implementation of LokacijaRepository (in LokacijaRepositoryImpl) while Spring Data JPA (which you have configured) is trying to do the same.
What you need to do is:
totally remove LokacijaRepositoryImpl
Either change configureEntityManagerFactory to entityManagerFactory or add entityManagerFactoryRef=configureEntityManagerFactory to #EnableJpaRepositories

Categories