My problem statement is as follows :
I want to connect to db and from a table get certain values and assign those to a bean. In current spring project, it is done as follows :
The class com.some.DbPropertyPlaceholderConfigurer is in a jar file.
<bean id="propertyConfigurer"
class="com.some.DbPropertyPlaceholderConfigurer">
<property name="dataSourceName" value="dataSource" />
<property name="locations">
<list>
<value>classpath:resources/context.properties</value>
</list>
</property>
</bean>
<bean id="someObject" class="com.some.beans.SomeObject">
<property name="someprop" value="${prefix.someprop}" />
<property name="someprop1" value="${prefix.someprop1}" />
<property name="someprop2" value="${prefix.someprop2}" />
....
</bean>
DbPropertyPlaceholderConfigurer is in a jar file, it reads from a db table.
The Db table has key value columns.
The key contains "prefix.someprop" and it has some value.
Now, I am working on converting spring beans into spring boot beans using annotations.
Following is the bean in spring.
I came up with following for spring boot but bean it is not getting initialized.
I am not sure how to map properties "dataSourceName" and "locations"
#Configuration
public class AppConfig {
#Bean
public DbPropertyPlaceholderConfigurer propertyConfigurer() {
return new DbPropertyPlaceholderConfigurer();
}
#Bean
public SomeObject someObject() {
return new SomeObject();
}
}
It throws following exception :
[localhost-startStop-1] ERROR org.springframework.boot.SpringApplication - Application run failed
org.springframework.beans.factory.BeanInitializationException: Could not load properties; nested exception is java.lang.NullPointerException
at com.some.configuration.DbPropertyPlaceholderConfigurer.processProperties(DbPropertyPlaceholderConfigurer.java:130)
Also if it gets initialzed, how will I actually use it ?
Related
>
Hi, I am new to Spring and Hibernate and require a positive response. As per my project requirement , I have a spring boot application and want to load Hibernate Configuration like datasource bean , session factory bean on demand when get the values from user . Based on users database specification values it will create connection there and create tables and perform further tasks . Here is my sample code in which I am excluding the db configuration on initial run and after that when call the hibernate configure method it creates separate context and connection with db .The problem is that it is not able to save user values in db and unable to have session factory object autowired in application
Main Application
#SpringBootApplication
#EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
public class TestApplication extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
}
Hibernate Persistence.XMl This are the four beans that i want to load on demand
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
p:driverClassName="${spring.datasource.driver-class-name}" p:url="${spring.datasource.url}"
p:username="${spring.datasource.username}"
p:password="${spring.datasource.password}"
p:initialSize="1" p:maxActive="2"
destroy-method="close">
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"
p:dataSource-ref="dataSource">
<property name="hibernateProperties">
<value>
hibernate.dialect=${spring.jpa.properties.hibernate.dialect}
hibernate.format_sql=true
hibernate.show_sql=false
hibernate.hbm2ddl.auto=update
</value>
</property>
<property name="mappingResources">
<list>
<value>entity-schema-hbm.xml</value>
</list>
</property>
</bean>
<bean id="testDao" class="com.app.dao.AbstractGenericDao" abstract="true">
<property name="entityManager">
<bean class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="persistenceUnitName" value="persistence-test-unit" />
</bean>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven />
Defined method in util for initializing beans it is able to create the separate context and connection with db but not merged with the current application and communicate with db . I want to create connection later on and will be available to spring boot application
public static EntityManager configureHibernate() {
ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
"hibernate-persistence.xml");
dataSource = (DataSource) appContext.getBean("dataSource");
sessionFactory = (SessionFactory) appContext.getBean("sessionFactory");
transactionManager = (TransactionManager) appContext.getBean("transactionManager");
entityManager = (EntityManager) appContext.getBean("testDao");
UserEntity userEntity=new UserEntity("admin","secret","admin#gmail.com");
sessionFactory.getCurrentSession().saveOrUpdate(userEntity);
try{
transactionManager.commit();
}catch (Exception e){
}
return entityManager;
}
I am working on a migration project which involves upgrading the platform to Spring 4 with MyBatis. In the legacy code, transactions are handled at a central locations wherein call to start/end transactions are spread across various classes like service class, helper class and DAO class.
I managed to convert all service classes to spring managed component and DAO classes to support MyBatis-spring API. Problem is my service class use several other classes to perform a function and those classes are all instantiated manually and used. Now if i start a transaction on service class methods and perform database transactions inside other helper or DAO classes which are not spring managed, my transaction handling doesn't work correctly. I have illustrated this problem in the below code. Could you tell what are the ways to acheive transaction handling without modifying the code?
Example :
package com.service;
#Service
class MyService {
#Transactional( propagation=Propagation.REQUIRED)
public void processRequest () {
HelperClass helper = new HelperClass();
helper.performOperation();
}
}
package com.helper;
// this class is not spring bean
class HelperClass {
// MyBatis mapper class
private EmployeeMapper mapper;
public HelperClass () {
mapper = // retrieve mapper class bean from spring context
}
public performOperation () {
// call to mapper class insert operation
// call to mapper class update operation
}
}
package com.dao;
#Component
interface EmployeeMapper {
// method definition to perform database operation
}
Spring configuration details:
<context:component-scan base-package="com" />
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
....
....
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" mode="aspectj" />
<mybatis:scan base-package="com.dao" />
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations"
value="classpath*:mybatis/*.xml" />
</bean>
In the above code HelperClass.performOperation() method is doing 2 database operations (insert,update). Say if insert succeeds and update fails, my database transaction doesn't get rollback. Since I already started the transaction at MyService.processRequest() should this not rollback the operations that are carried inside that method call? Correct me if my understanding is wrong.
I'm new to Spring development.And right now,i'm really facing a problem.Here are the code snippets to make you realize my problem clearly.............
Here is my DAO class:
public class LoginDaoImpl {
private DataSource dataSource;
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public int checkLoginDetails(LoginVo loginVo){
String sql = "select count(*) from empsctygrp where username=? and password=?";
jdbcTemplate = new JdbcTemplate(dataSource);
int count = jdbcTemplate.queryForObject(sql,new Object[]{loginVo.getUserName(),loginVo.getPassword()},Integer.class);
return count;
}
}
Now here is my Business-Object(BO) class:
public class LoginBo {
LoginDaoImpl loginDaoImpl = new LoginDaoImpl();
public int checkLoginDetails(LoginVo loginVo){
return loginDaoImpl.checkLoginDetails(loginVo);
}
}
Now,here is my dispatcher-servlet xml code:
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:#117.194.83.9:1521:XE"/>
<property name="username" value="system"/>
<property name="password" value="password1$"/>
</bean>
<bean id="loginDaoImpl" class="com.abhinabyte.dao.LoginDaoImpl">
<property name="dataSource" ref="dataSource" />
</bean>
Now whenever i'm trying to run this on server the following exception is given:
SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/A] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: Property 'dataSource' is required] with root cause
java.lang.IllegalArgumentException: Property 'dataSource' is required
Please help me solve this problem.............:(
Try this in LoginBo class:
#Autowired
LoginDaoImpl loginDaoImpl;
instead of
LoginDaoImpl loginDaoImpl = new LoginDaoImpl();
The problem is that you manually instantiate LoginDaoImpl.
I was having the same problem and could not find a comprehensive answer on the web, so I decided to post one here for anyone else, or for future me.
I'm still learning so if you think I have made a mistake below, please feel free to edit.
Summary:
Include <integration:annotation-config/> <context:component-scan base-package="myproject"/> in your servlet to pick up annotations
Configure JUnit tests with #RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("file:WEB-INF/FinanceImportTool-servlet.xml")
Don't autowire dataSource or jdbcTemplate if these fields are already provided by a parent class e.g. StoredProcedure
Don't use new() as this initializes classes outside the applicationContext
Beware of using properties in your constructor which have not yet been set - obvious but embarrassingly easy to do
My original class (now altered):
public class MyDAOImpl extends StoredProcedure implements MyDAO {
private static final String SPROC_NAME = "dbo.MySP";
public MyDAOImpl(DataSource dataSource) {
super(dataSource, SPROC_NAME);
// ...declared parameters...
compile();
}
}
MyProject-servlet.xml file (only relevant bits included):
<!-- Used by Spring to pick up annotations -->
<integration:annotation-config/>
<context:component-scan base-package="myproject"/>
<bean id="MyDAOBean" class="myproject.dao.MyDAOImpl" >
<constructor-arg name="dataSource" ref="myDataSource"/>
</bean>
<!-- properties stored in a separate file -->
<bean id="myDataSource" class="com.microsoft.sqlserver.jdbc.SQLServerDataSource">
<property name="databaseName" value="${myDataSource.dbname}" />
<property name="serverName" value="${myDataSource.svrname}" />
<!-- also loaded portNumber, user, password, selectMethod -->
</bean>
Error: property 'dataSource' is required, or NullPointerException (1)
Other answers say make sure you have passed dataSource as a <property> for your bean in the servlet, etc.
I think #Abhinabyte the OP needed to annotate his setDataSource() method with #Annotation, and use <integration:annotation-config/> <context:component-scan base-package="myproject"/> in his servlet to successfully pass in dataSource as a dependency to LoginDaoImpl.
In my case, I tried adding 'dataSource' as a property and autowiring it. The "dataSource is required" error message became a NullPointerException error.
I realised after far too long that MyDAOImpl extends StoredProcedure.
dataSource was already a property of StoredProcedure. By having a dataSource property for MyDAOImpl, the autowiring was not picking up and setting the dataSource property of StoredProcedure, which left dataSource for StoredProcedure as null.
This was not picked up when I tested the value of MyDAOImpl.dataSource, as of course by now I had added a MyDAOImpl.dataSource field that had been autowired successfully. However the compile() method inherited from StoredProcedure used StoredProcedure.dataSource.
Therefore I didn't need public DataSource dataSource; property in MyDAOImpl class. I just needed to use the StoredProcedure constructor with super(dataSource, sql); in the constructor for MyDAOImpl.
I also didn't need a MyDAOImpl.jdbcTemplate property. It was set automatically by using the StoredProcedure(dataSource, sql) constructor.
Error: NullPointerException (2)
I had been using this constructor:
private static final String SPROC_NAME = "dbo.MySP";
public MyDAOImpl(DataSource dataSource) {
super(dataSource, SPROC_NAME);
}
This caused a NullPointerException because SPROC_NAME had not been initialized before it was used in the constructor (yes I know, rookie error). To solve this, I passed in sql as a constructor-arg in the servlet.
Error: [same error message appeared when I had changed file name]
The applicationContext was referring to the bin/ instances of my beans and classes. I had to delete bin/ and rebuild the project.
My new class:
public class MyDAOImpl extends StoredProcedure implements MyDAO {
#Autowired // Necessary to prevent error 'no default constructor found'
public MyDAOImpl(DataSource dataSource, String sql) {
super(dataSource, sql);
// ...declared parameters...
compile();
}
New MyProject-servlet.xml file (only relevant bits included):
<!-- Used by Spring to pick up annotations -->
<integration:annotation-config/>
<context:component-scan base-package="myproject"/>
<bean id="myDAOBean" class="org.gosh.financeimport.dao.MyDAOImpl" >
<constructor-arg name="dataSource" ref="reDataSource"/>
<constructor-arg name="sql" value="dbo.MySP" />
</bean>
<!-- properties stored in a separate file -->
<bean id="myDataSource" class="com.microsoft.sqlserver.jdbc.SQLServerDataSource">
<property name="databaseName" value="${myDataSource.dbname}" />
<property name="serverName" value="${myDataSource.svrname}" />
<!-- also loaded portNumber, user, password, selectMethod -->
</bean>
Helpful places:
If you can get past the rage, this answer on Spring forums might help too
This answer gives a broad introduction to Spring configuration
This answer has simple but useful suggestions
You should annotate that beans that will suffer IoC. Like
#Bean public class LoginDAOImpl { #Inject DataSource dataSource;......}
You set up in spring context this beans, but, you're not using them.
OBS:
When I use the JDBCTemplate I configure de IoC of JDBC like
<bean id="dataSourcePerfil" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${br.com.dao.jdbc.driver}" />
<property name="url" value="${br.com.dao.jdbc.url}" />
<property name="username" value="${br.com.dao.jdbc.user}" />
<property name="password" value="${br.com.dao.jdbc.pass}" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSourcePerfil" />
</bean>
then.... after at all
#Bean
public class LoginDAOImpl {
#Autowired
private JdbcTemplate jdbcTemplate;
#Override
public List<ClienteReport> getClientes() {
return Collections<ClienteReport>. emptyList();
}
}
I need an ANT task to validate spring configuration. I need to find problems at build time before runtime ? For example, In spring context file contains a property a bean, but this bean doesnt have this property.
In eclipse, there is a tool Spring Explorer that do this validation.
thanks,
org.springframework.web.context.ContextLoaderListener failed: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'readController' defined in class path resource [applicationContext.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'productOperations' of bean class [com.bee.view.json.ReadController]: Bean property 'productOperations' is not writable or has an invalid setter method.
Does the parameter type of the setter match the return type of the getter?.
An easy way to ensure that your context is valid would be to create a JUnit test, which loads the context. Using the spring-test.jar support classes makes that easy:
public class MyTest extends AbstractDependencyInjectionSpringContextTests {
// this will be injected by Spring
private QueryDao queryDao;
private MyBusinessObject myBusinessObject;
// ensure that spring will inject the objects to test by name
public MyTest () {
setAutowireMode(AUTOWIRE_BY_NAME);
}
#Override
protected String[] getConfigLocations() {
return new String[] { "applicationContextJUnit.xml" };
}
public void testQueryDao() {
List<SomeData> list = queryDao.findSomeData();
assertNotNull(list);
// etc
}
public void testMyBusinessObject() {
myBusinessObject.someMethod();
}
public void setQueryDao(QueryDao queryDao) {
this.queryDao = queryDao;
}
}
The problem with loading a context that is used in a web application is that JUnit does not necessarily have access to the same resources (e.g. JNDI data sources), so if you've got the following in your "applicationContext.xml":
<beans ...>
<bean id="myBusinessObject" class="com.test.MyBusinessObject">
<property name="queryDao" ref="queryDao"/>
</bean>
<bean id="queryDao" class="com.test.QueryDao">
<property name="dataSource" ref="dataSource"/>
</bean>
<jee:jndi-lookup
id="dataSource"
jndi-name="jdbc/mydatasource"
resource-ref="true"
cache="true"
lookup-on-startup="false"
proxy-interface="javax.sql.DataSource"/>
</beans>
and your "applicationContextJUnit.xml" would import your "real" application context and redefine resources:
<beans ...>
<import resource="classpath:applicationContext.xml"/>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:..."/>
<property name="username" value="scott"/>
<property name="password" value="tiger"/>
</bean>
</beans>
That way your unit tests will load the application context (even the ones that you don't explicitly test in your unit test), and you can have the confidence that your context is correct, because Spring itself loaded it. If you have an error, then the unit tests will fail.
I'm trying to load an XSD file as a Schema instance in my application context XML file. We're building it in java code, but I'd like to be injecting it.
Here's what the user class looks like if that'll clarify things.
class XmlBuilder {
...
Schema schema; // set by spring
public String createXml(Object param1) {
// create xml
Validator validator = schema.newValidator();
try {
validator.validate(documentSS);
} catch (SAXException e) {
// log and convert to a proper exception
}
return xml;
}
}
The schema is in the app's classpath, I'm just having trouble loading it and creating the schema object. I can get this far
<bean id="schemaFactory" class="javax.xml.validation.SchemaFactory" factory-method="newInstance">
<constructor-arg value="http://www.w3.org/2001/XMLSchema"/>
</bean>
<bean id="xmlBuilder" class="XmlBuilder">
<property name="schema">
<bean factory-bean="schemaFactory" factory-method="newSchema">
<!-- missing bit -->
</bean>
</property>
</bean>
But I'm stuck on loading the file and passing it into the factory method.
I ended up using the ResourceSource class in 'org.springframework.ws:spring-xml'
<property name="schema">
<bean class="org.springframework.xml.transform.ResourceSource">
<constructor-arg value="classpath:/schema.xsd"/>
</bean>
</property>