I'm currently learning Spring and Hibernate. I have a StudentDAOImpl class that contains all my database queries. I want to get an instance of this bean in my main function and run the query methods there all in my main function for testing. I'm trying to do this by calling the getBean() method because the name of the bean is the class but first letter is lowercase if I'm not mistaken. The compiler is giving me this error
Exception in thread "main org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'studentDAOImpl' available**
Why can't Spring find my StudentDAOImpl bean? Thank you for your time in reading this post.
Here's my code
Main Function
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AnimalConfig.class,HibernateConfig.class); // Makes the sessionFactory bean known to the IOC
StudentDAOImpl student = (StudentDAOImpl)ctx.getBean("studentDAOImpl");
Student aStudent = new Student("dasdasdas","dasdadas","dsadasdasda#gmail.com");
student.addStudent(aStudent);
(( ConfigurableApplicationContext )ctx).close(); //Close the applicationContext
SpringApplication.run(DemoApplication.class, args);
}
StudentDAOImpl Class
#Repository //Sets up componenent scanning for DI for our services
public class StudentDAOImpl implements StudentDAO{
#Autowired
SessionFactory sessionFactory;
//Queries Ommited from post for space saving purposes
}
HibernateConfiguration File
#Configuration
#EnableTransactionManagement
public class HibernateConfig {
#Bean(name = "sessionFactory")
#Scope("singleton")
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(packagesToScan());
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/demo");
dataSource.setUsername("root");
dataSource.setPassword("danielL45");
return dataSource;
}
#Bean
public PlatformTransactionManager hibernateTransactionManager() {
HibernateTransactionManager transactionManager
= new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
}
private String[] packagesToScan(){
return new String[] {
"com.example.demo.Entities.Student"
};
}
private final Properties hibernateProperties() {
Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", "update");
hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
hibernateProperties.setProperty("current_session_context_class", "thread");
return hibernateProperties;
}
}
Use this:
StudentDAOImpl student = ctx.getBean(StudentDAOImpl.class)
This is a more secure way to get the bean that we need, since we may have only one bean with this class, using a string to select a Spring Bean has a propability of not working when not writing the name correctly.
Related
When I inject my sessionFactory Bean using Java based configuration for Hibernate my bean is null and I don't know why. I've scoured the internet for answers but couldn't find any. I've looked over my configuration and compared it against guides online. Any answers are greatly appreciated.
Here's the exact error
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "org.hibernate.SessionFactory.getCurrentSession()" because "com.example.demo.DemoApplication.sessionFactory" is null
Here's my code
HibernateConfiguration File, Annotation based.
#Configuration
#EnableTransactionManagement
public class HibernateConfig {
#Bean
#Scope //By default the scope is singleton which means that the IOC will only create a single instance of the bean and return that one reference for subsequent calls for that bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan( packagesToScan()); //Model packages to scan
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
//Direct Physical Connection Information
#Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/demo");
dataSource.setUsername("root");
dataSource.setPassword("password");
return dataSource;
}
#Bean
public PlatformTransactionManager hibernateTransactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
}
//List of Entities to scan
#Bean
public String [] packagesToScan() {
return new String [] { "com.example.demo.Entities.Student" };
}
//Configures properties of our hibernate configuration, dialect,
private final Properties hibernateProperties() {
Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", "create");
hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
hibernateProperties.setProperty("show_sql", "true");
hibernateProperties.setProperty("current_session_context_class", "thread");
return hibernateProperties;
}
}
My Main application where I'm attempting to inject my Session Factory singleton bean for use.
#SpringBootApplication
public class DemoApplication {
#Autowired
static SessionFactory sessionFactory;
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AnimalConfig.class, HibernateConfig.class); // Makes the sessionFactory bean known to the IOC
Session currentSession = sessionFactory.getCurrentSession();
(( ConfigurableApplicationContext )ctx).close(); //Close the applicationContext
SpringApplication.run(DemoApplication.class, args);
}
}
The container gets started when SpringApplication.run invokes. I think before all of this an injection and the usage of that bean does not makes sense. First you need to fire Springapplication and then the rest of the business logic.
Your bean isn't scanned and initialize at the moment of the injection.
Possible solution :
#Component
public class IOCAfterInitializationListener implements ApplicationListener<ContextRefreshedEvent> {
#Autowired
static SessionFactory sessionFactory;
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
Session currentSession = sessionFactory.getCurrentSession();
//do whatever you want
}
}
Good evening,
what is the correct and common approach of handling two or more databases?
Consider this HibernateConfiguration class configuring only one datasource:
#Configuration #EnableTransactionManagement
#PropertySource(value = { "classpath:hibernate.properties" })
public class HibernateConfiguration {
#Autowired
private Environment env;
#Bean
public DataSource getDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
// ... setting data source
return dataSource;
}
private Properties getHibernateProperties() {
Properties properties = new Properties();
// ... setting Hibernate properties
return properties;
}
#Bean
public LocalSessionFactoryBean getSessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(getDataSource());
sessionFactory.setPackagesToScan(new String[] { "POJOs'" });
sessionFactory.setHibernateProperties(getHibernateProperties());
return sessionFactory;
}
#Bean public HibernateTransactionManager transactionManager(SessionFactory sf) {
HibernateTransactionManager htm = new HibernateTransactionManager();
htm.setSessionFactory(sf);
return htm;
}
}
Is recommended to let one class configure one datasource? Or is enough to configure all at once? How do I specify in Dao class which SessionFactory will be used and what is the recommended approach in case of switching two exact same databases on two different hosting servers?
The example DAOs. First I need to switch between Foo and Bar.
#Repository
public class RepositoryImpl implements RepositoryDao {
#Autowired // Here I need to switch between databases "foo" and "bar"
private SessionFactory sessionFactory;
...
The second one I need fixed on example database Foo.
#Repository
public class FooImpl implements FooDao {
#Autowired // Here I need fixed on "Foo"
private SessionFactory sessionFactory;
One approach
#Bean
#Primary
#ConfigurationProperties("app.datasource.foo")
public DataSourceProperties fooDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#Primary
#ConfigurationProperties("app.datasource.foo")
public DataSource fooDataSource() {
return fooDataSourceProperties().initializeDataSourceBuilder().build();
}
#Bean
#ConfigurationProperties("app.datasource.bar")
public BasicDataSource barDataSource() {
return (BasicDataSource) DataSourceBuilder.create()
.type(BasicDataSource.class).build();
}
Spring multiple datasources config
Other approach could be : loading different mapping (orm.xml) from persistence.xml or refer to different schemas in Entity classes.
I m newbie on the spring and I m just testing some utilities to learn java configuration on the spring framework,so question is
I have two configuration as seen below and I want to extend one configuration to another and use sub java configuration with appconfig so I did this way and working everything good but I m still feeling its not good approach for me ,could you give me correct way on this or alternative of this thanks
Hibernate Configuration
**package configuration**
#Configuration
#EnableTransactionManagement
#ComponentScan({"configuration"})
#PropertySource(value={"classpath:application.properties"})
public class HibernateConfiguration {
#Autowired
Environment environment;
#Bean
public LocalSessionFactoryBean sessionFactory(){
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(generateDataSource());
sessionFactoryBean.setPackagesToScan(new String[]{"whateverpackage.model"});
sessionFactoryBean.setHibernateProperties(generateProperties());
return sessionFactoryBean;
}
#Bean
public DataSource generateDataSource() {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverclassname"));
driverManagerDataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
driverManagerDataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
driverManagerDataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
return driverManagerDataSource;
}
public Properties generateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
return properties;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
HibernateTransactionManager transactionManager = new HibernateTransactionManager(sessionFactory); //constructor-arg can be use in xml
return transactionManager;
}
}
SubConfiguration
package another.configuration
#Configuration
#ComponentScan({"another.configuration"})
#EnableTransactionManagement
#PropertySource(value={"classpath:application.properties"})
public class SubConfiguration extends HibernateConfiguration{
}
AppConfig
package another.configuration
#Configuration
#ComponentScan(basePackages="root package")
#Import(SubConfiguration.class)
public class AppConfig {
}
For my new project I plan to use Hibernate 5 and Spring 4 and as always like to separate into different layers / projects.
Gradle dependencies:
"org.springframework:spring-webmvc:4.2.1.RELEASE",
"org.springframework:spring-orm:4.2.1.RELEASE",
'org.hibernate:hibernate-core:5.0.2.Final',
'mysql:mysql-connector-java:5.1.36'
There is an API project, that contains a User.class. From my opinion this user class must not use any annotations for a database layer. It must not specify #Table(name = "users") or other things. It should be a simple Objects with getters and setters.
The database layer should decide how to store the data and this depends strongly on the database (e.g. MongoDB or MySQL).
I followed some tutorials for Hibernate and ended up with the following #Configuration class
#Configuration
#ComponentScan("de.pentos.proto")
#EnableWebMvc
#EnableTransactionManagement
public class AppConfig {
private static final Logger log = LoggerFactory.getLogger(AppConfig.class);
private static Properties getHibernateProperties() {
final Properties properties = new Properties();
properties.put("hibernate.show_sql", "true");
// properties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
properties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
properties.put("hbm2ddl.auto", "create");
return properties;
}
{
log.debug("Here am I: {}");
}
#Bean(name = "dataSource")
public DataSource getDataSource() {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/myschema");
dataSource.setUsername("user");
dataSource.setPassword("password");
return dataSource;
}
#Inject
#Bean(name = "sessionFactory")
public SessionFactory getSessionFactory(final DataSource dataSource) {
final LocalSessionFactoryBuilder sessionBuilder = new LocalSessionFactoryBuilder(dataSource);
sessionBuilder.addAnnotatedClasses(User.class);
sessionBuilder.addProperties(getHibernateProperties());
return sessionBuilder.buildSessionFactory();
}
#Inject
#Bean(name = "transactionManager")
public HibernateTransactionManager getTransactionManager(final SessionFactory sessionFactory) {
final HibernateTransactionManager transactionManager = new HibernateTransactionManager(
sessionFactory);
return transactionManager;
}
}
It works very well, except it uses an annotated class.
How can I add my hbm/user.xml to the sessionBuilder?
I tried with Configuration class, that I found in some examples, but the Method buildSessionFactory() is deprecated.
I also tried the ServiceRegistry described here but then lost my datasource approach and without the datasource the system was not able to setup the HibernateTransactionManager.
Without HibernateTransactionManager I was not able to use #Transactional and I don't like to open and close me transactions manually.
Currently I'm spinning in circles and really need help to get it to work. I already thought about throwing Hibernate away and use my good old MyBatis approach, but you know, I like to learn something new...
Add xml files as a resource to SessionFactory, as follows:
#Inject
#Bean(name = "sessionFactory")
public SessionFactory getSessionFactory(final DataSource dataSource) {
final LocalSessionFactoryBuilder sessionBuilder = new LocalSessionFactoryBuilder(dataSource);
sessionBuilder.addResource("/path-to-/hbm/user.xml");
sessionBuilder.addAnnotatedClasses(User.class);
sessionBuilder.addProperties(getHibernateProperties());
return sessionBuilder.buildSessionFactory();
}
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.