Sorry for the silly question, but i can't find out why this code is not working with Spring.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader = AnnotationConfigContextLoader.class)
public class DBDumpTest {
#Autowired
private DataSource source;
#Configuration
static class ContextConfiguration {
#Bean
public DataSource dataSource() {
return Mockito.mock(DataSource.class);
}
}
#Test
public void testDump() throws Exception {
Assert.assertNotNull(source); //OK
Assert.assertNotNull(new DBDump().getDatasource()); //NULL NOT OK
}
}
With Class:
public class DBDump {
private static final Logger logger = LoggerFactory.getLogger(DBDump.class);
#Autowired
private DataSource datasource;
public DataSource getDatasource() {
return datasource;
}
}
So why does new DBDump().getDatasource() not return the Mocked Instance, while in the Test-Class the #Autowired Annotation seems to work?
Related
when i am using #autowire to inject my dependencies in Configuration
class its giving me as null please refer the code below .
#Configuration
public class DataSourceConfig {
#Autowired
AppService appService;
#Bean
public BeanDefinitionRegistryPostProcessor beanPostProcessor() {
return new BeanDefinitionRegistryPostProcessor() {
public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0) throws BeansException {
}
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanRegistry) throws BeansException {
createBeans(beanRegistry);
}
};
}
private void createBeans(BeanDefinitionRegistry beanRegistry,DataSourceConfigService ds) {
appService.getDbDetails();
appService is null here if i will call it using this way
BeanDefinitionRegistryPostProcessor beanPostProcessor(AppService
appService) then in AppServiceImpl class AppDao dependency will be null
}
}
//// Service
#Service
public class AppServiceImpl implements AppService{
#Autowired
AppDao ds;
#Override
public List<A> getDatabaseConfiguration() {
return ds.getDbDetails(); // here ds is null
}
}
//dao
#Repository
public class AppDaoImpl implements AppDao {
#Qualifier("nameParamJdbcTemplate")
#Autowired
public NamedParameterJdbcTemplate nameParamJdbcTemplate;
#Override
public List<A> getDbDetails() {
return nameParamJdbcTemplate.query(SELECT_QUERY, new DataSourceMapper()); // nameParamJdbcTemplate is null
}
// datasource config
#Configuration
public class DataSourceBuilderConfig {
#Bean(name = "dbSource")
#ConfigurationProperties(prefix = "datasource")
#Primary
public DataSource dataSource1() {
return DataSourceBuilder.create().build();
}
#Bean(name = "nameParamJdbcTemplate")
#DependsOn("dbSource")
#Autowired
public NamedParameterJdbcTemplate jdbcTemplate1(#Qualifier("dbSource") DataSource dbSource) {
return new NamedParameterJdbcTemplate(dbSource);
}
}
What i want is when ever my beanPostProcessor()
is executed i want all my dependent beans should be instantiated ie
#Autowired
AppService appService;
#Autowired
AppDao ds;
#Qualifier("nameParamJdbcTemplate")
#Autowired
public NamedParameterJdbcTemplate nameParamJdbcTemplate;
I am new to spring so any help or working examples would be great. Thanks
It is null because this #Configuration class also defines a BeanDefinitionRegistryPostProcessor that forces the context to create that bean very early on.
Because you are using field injection, the context has to resolve AppService bean but it can't yet because the post-processor have to be applied first.
Your configuration looks very complex so you may want to simplify it a bit:
Separate low-level infrastructure configuration from main configuration
Always define such post processor as public static method so that the context can invoke the #Bean method without having to construct the class first.
Hello everyone I wanted to tested the full validation of a Request in my Spring Boot application I mean no testing one validator at a time but all of them on the target object)
First I have my object :
public class UserCreationRequest {
#JsonProperty("profileId")
#NotNull
#ValidProfile
private Integer profileId;
}
Then my Validator (#ValidProfile):
#Component
public class ProfileValidator implements ConstraintValidator<ValidProfile, Integer> {
#Autowired
private IProfileService profileService;
#Autowired
private IUserRestService userRestService;
#Override
public void initialize(ValidProfile constraintAnnotation) {
}
#Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}
RestUser restUser = userRestService.getRestUser();
ProfileEntity profileEntity = profileService.getProfile(value, restUser.getAccountId());
return profileEntity != null;
}
}
Now I write my unit test :
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = {ValidationTestConfiguration.class})
public class UserCreationRequestValidationTest {
private static LocalValidatorFactoryBean localValidatorFactory;
#Autowired
private IUserService userService;
#Autowired
private IProfileService profileService;
#Autowired
private IUserRestService restService;
#BeforeClass
public static void createValidator() {
localValidatorFactory = new LocalValidatorFactoryBean();
localValidatorFactory.setProviderClass(HibernateValidator.class);
localValidatorFactory.afterPropertiesSet();
}
#AfterClass
public static void close() {
localValidatorFactory.close();
}
#Test
public void validateUserCreationRequestStringfields() {
UserCreationRequest userCreationRequest = new UserCreationRequest();
/* Here fill test object*/
when(userService.getUser(any(Integer.class), any(Integer.class))).thenReturn(new UserEntity());
when(profileService.getProfile(any(Integer.class), any(Integer.class))).thenReturn(new ProfileEntity());
when(restService.getRestUser()).thenReturn(new RestUser());
Set<ConstraintViolation<UserCreationRequest>> violations
= localValidatorFactory.validate(userCreationRequest);
assertEquals(violations.size(), 8);
}
}
and my TestConfiguration is like that :
#Configuration
public class ValidationTestConfiguration {
#Bean
#Primary
public IProfileService profileService() {
return Mockito.mock(IProfileService.class);
}
#Bean
#Primary
public IUserRestService userRestService() { return Mockito.mock(IUserRestService.class); }
}
On execution I can see that in the test itself the injection works :
restService is mapped to "Mock for IUserRestService"
But in my validator it is not injected, userRestService is null.
Same thing for ProfileService
I tried several things seen here, nothing works (code is running, only test conf is failing)
This is because you do not produce the Validator bean so it can be injected.
As you manually instantiate the LocalValidatorFactoryBean, it cannot access to the spring DI defined for this test.
You should produce instead a bean for the Validator, or even reference an existing spring configuration to do so.
I use #EntityListeners to make operations before I save in my Db and after I load.
Inside my Listener class I make a call to an Ecryptor (which needs to fetch info from configuration file), so the encryptor can't be called statically and need to be injected in my Listener. Right?
Well, injections in EntityListeners can't be done straight away, but you have some methods to do that, like using SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); or even the method showed here. https://guylabs.ch/2014/02/22/autowiring-pring-beans-in-hibernate-jpa-entity-listeners/
Cool, the problem is: None of the solutions support unit testing! When running tests that encryptor I had injected in my model Listener is always null.
Here SpringBeanAutowiringSupport does not inject beans in jUnit tests There is a solution to create this context and pass to a instantiated object, but it does not solve my problem since I have the "Injection" to add to it.
Any way to create a context in my tests and somehow pass it to my listeners?
If not, any way I can create a static method to my Encryptor and still have access to the Environment API to read my properties?
Package Listener:
public class PackageListener{
#Autowired
Encryptor encryptor;
#PrePersist
public void preSave(final Package pack){
pack.setBic(encryptor.encrypt(pack.getBic()));
}
...
My test
#Test
#WithuserElectronics
public void testIfCanGetPackageById() throws PackageNotFoundException{
Package pack = packagesServiceFactory.getPackageService().getPackage(4000000002L);
}
Package service
public Package getPackage(Long id) throws PackageNotFoundException{
Package pack = packageDao.find(id);
if (pack == null) {
throw new PackageNotFoundException(id);
}
return pack;
}
Encryptor:
public class Encryptor{
private String salt;
public Encryptor(String salt){
this.salt = salt;
}
public String encrypt(String string){
String key = this.md5(salt);
String iv = this.md5(this.md5(salt));
if (string != null) {
return encryptWithAesCBC(string, key, iv);
}
return string;
}
...
You can create a DemoApplicationContextInitializer class to store the appliationContext reference in a static property in your main class.
public class DemoApplicationContextInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext ac) {
Application.context = ac;
}
}
#SpringBootApplication
public class Application {
public static ApplicationContext context;
public static void main(String[] args) throws Exception {
new SpringApplicationBuilder(Application.class)
.initializers(new DemoApplicationContextInitializer())
.run(args);
}
}
Then you can access the context in your entity listener
public class PackageListener{
//#Autowired
Encryptor encryptor;
#PrePersist
public void preSave(final Package pack){
encryptor = Application.context.getBean(Encryptor.class);
pack.setBic(encryptor.encrypt(pack.getBic()));
}
}
And to make this work in your junit test, just add the initializer in your test like this ...
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT, classes = Application.class)
#ContextConfiguration(classes = Application.class, initializers = DemoApplicationContextInitializer.class)
public class MyTest {
...
}
It works without any issue in my environment. Hope it will be helpful to you too.
To answer what you need, you have to create 2 classes that will do all the configuration needed.
You have to create a testConfig with the next annotations:
#Configuration
#ComponentScan(basePackages = { "yourPath.services.*",
"yourPath.dao.*" })
#EnableAspectJAutoProxy
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = "yourPath.dao.entities",
entityManagerFactoryRef = "entityManagerFactory",
transactionManagerRef = "transactionManager",
repositoryBaseClass = Dao.class)
#Import({ DataSourceConfig.class }) //Explained below
public class TestConfig {
#Autowired
private DataSource dataSource;
#Bean
public List<String> modelJPA() {
return Collections.singletonList("es.carm.sms.ortopedia.entities");
}
#Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
#Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setPackagesToScan(modelJPA().toArray(new String[modelJPA().size()]));
entityManagerFactory.setDataSource(this.dataSource);
JpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
entityManagerFactory.setJpaVendorAdapter(jpaVendorAdapter);
return entityManagerFactory;
}
}
Then if you want to connect with your database:
#Configuration
public class DataSourceConfig {
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("oracle.jdbc.OracleDriver");
dataSource.setUrl("jdbc:oracle:thin:#ip:port:sid");
dataSource.setUsername("name");
dataSource.setPassword("pass");
return dataSource;
}
}
Now you have it all set up, you just need to create your test importing your configurations:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = TestConfig.class)
public class TestCase {...}
You will get your spring context initialized with access to all your resources (MVC) Services, DAO and Model.
I am trying to build a new annotation based spring boot application.
On the DAO-level I have a configuration class with Dao beans:
#Configuration
#EnableTransactionManagement
public class DatabaseConfig {
#Bean
public DataSource dataSource(){
...
return dataSource;
}
#Bean
public JdbcTemplate jdbcTemplate(){
JdbcTemplate template = new JdbcTemplate();
template.setDataSource(dataSource());
return template;
}
#Bean
public DataSourceInitializer dataSourceInitializer(DataSource dataSource)
{
....
}
#Bean
public PersonDao personDao(){
return new PersonDao();
}
}
On the server level a controller and a Mein class.
#SpringBootApplication (exclude = SecurityAutoConfiguration.class)
#ComponentScan("my.package")
#Import(DataBaseConfig.class)
public class Main {
private static Logger log = Logger.getLogger(Main.class);
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
The problem is that the main class does not see the beans got from the DatabaseConfig and that's why cannot start the application (because they are user in the controller). How can I correctly import them?
I am getting the error as in the question. My Dao Implement Class is as follows :
package com.argus.intenew;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
#Autowired
AnnotationSessionFactoryBean sessionFactory;
public UserDaoImpl() {
}
public AnnotationSessionFactoryBean getCurrentSessionFactory() {
return sessionFactory;
}
public void setCurrentSessionFactory(AnnotationSessionFactoryBean sessionfactory) {
this.sessionFactory = sessionfactory;
}
#Override
public void addUser(UserMap userMap) {
System.out.println("33333333333333333333");
getHibernateTemplate().save(userMap);
}
#Override
public List<User> findAllUser() {
return getHibernateTemplate().find("from User");
}
#Override
public void deleteUser(UserMap user) {
getHibernateTemplate().delete(user);
}
#Override
public void updateUser(UserMap user) {
getHibernateTemplate().update(user);
}
}
And my configuration class is as follows:
package com.argus.intenew;
import java.util.Properties;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate3.HibernateTransactionManager;
import org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean;
#Configuration
#ComponentScan(basePackages = {"com.argus.intenew"})
public class Webconfig {
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "org.hibernate.dialect.MySQLDialect ";
private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "true";
#Bean
public DataSource dataSource() {
System.out.println("----------InDATAsource------------");
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/MyUser");
dataSource.setUsername("root");
dataSource.setPassword("XXX");
System.out.println("----------OutofDATAsource------------");
return dataSource;
}
#Bean
public AnnotationSessionFactoryBean sessionFactory() {
System.out.println("----------InsessionFactory------------");
AnnotationSessionFactoryBean sessionFactory = new AnnotationSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
String[] pckage={"com.argus.intenew"};
sessionFactory.setPackagesToScan(pckage);
sessionFactory.setHibernateProperties(hibProperties());
System.out.println("----------Outof session------------");
return sessionFactory;
}
private Properties hibProperties() {
System.out.println("----------InhipProp------------");
Properties properties = new Properties();
properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, "org.hibernate.dialect.MySQLDialect ");
properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, "true");
System.out.println("----------outofhip------------");
return properties;
}
#Bean
public HibernateTransactionManager transactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager(sessionFactory().getObject());
return transactionManager;
}
#Bean
public UserBoImpl userBo() {
System.out.println("----------InUserBo------------");
UserBoImpl userBo= new UserBoImpl();
userBo.setUserDao(userDao());
System.out.println("----------OutofUserbo------------");
return userBo;
}
#Bean
public UserDaoImpl userDao() {
System.out.println("----------InUserDao------------");
UserDaoImpl userDao=new UserDaoImpl();
userDao.setCurrentSessionFactory(sessionFactory());
System.out.println("----------OutofUserDao------------");
return userDao;
}
}
Anyone please help and tell me what is the correct way to do this with annotations.
Here I am not using any xml file.
Your DAO implementation is not leveraging its superclass correctly.
You're injecting a Spring FactoryBean<SessionFactory> when it really needs a Hibernate SessionFactory.
It's not actually using the injected dependency.
You're attempting to use HibernateDaoSupport#getHibernateTemplate() without giving it a reference to a SessionFactory or a HibernateTemplate.
Note that HibernateDaoSupport will create its own HibernateTemplate as long as you give it a SessionFactory.
I suggest you make the following changes:
Remove AnnotationSessionFactoryBean sessionFactory from UserDaoImpl
Fix configuration of UserDaoImpl by leveraging its inherited setSessionFactory(SessionFactory) method
So you actually end up with this DAO code:
public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
#Override
public void addUser(UserMap userMap) {
getHibernateTemplate().save(userMap);
}
#Override
public List<User> findAllUser() {
return getHibernateTemplate().find("from User");
}
#Override
public void deleteUser(UserMap user) {
getHibernateTemplate().delete(user);
}
#Override
public void updateUser(UserMap user) {
getHibernateTemplate().update(user);
}
}
And this configuration code:
#Configuration
#ComponentScan(basePackages = {"com.argus.intenew"})
public class Webconfig {
//snip...
#Bean
public UserDaoImpl userDao() {
UserDaoImpl userDao=new UserDaoImpl();
userDao.setSessionFactory(sessionFactory().getObject());
return userDao;
}
}
Note that it's ok to return the FactoryBean from the sessionFactory() configuration method since Spring will detect and utilize its lifecycle methods (via InitializingBean and DisposableBean), but you need to accommodate by calling the FactoryBean method getObject() yourself.
Don't user HibernateDaoSupport and/or HibernateTemplate. With the release of Hibernate 3.0.1 that support should be regarded deprecated. As mentioned in the reference guide implement the dao/repository based on plain hibernate.
Your dao will look like
#Repository
public class UserDaoImpl implements UserDao {
#Autowired
private SessionFactory sessionFactory;
#Override
public void addUser(UserMap userMap) {
System.out.println("33333333333333333333");
sessionFactory.getCurrentSession().save(userMap);
}
#Override
public List<User> findAllUser() {
return sessionFactory.getCurrentSession().createQuery("from User").list();
}
#Override
public void deleteUser(UserMap user) {
sessionFactory.getCurrentSession().delete(user);
}
#Override
public void updateUser(UserMap user) {
sessionFactory.getCurrentSession().update(user);
}
}
As you are already using the #ComponentScan annotation (and I assume yo have your BO annotated with #Service and properly annotated with #Autowired there is no need to explictly configure you dao and service in the configuration.
#Configuration
#ComponentScan(basePackages = {"com.argus.intenew"})
public class Webconfig {
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "org.hibernate.dialect.MySQLDialect ";
private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "true";
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/MyUser");
dataSource.setUsername("root");
dataSource.setPassword("XXX");
return dataSource;
}
#Bean
public AnnotationSessionFactoryBean sessionFactory() {
AnnotationSessionFactoryBean sessionFactory = new AnnotationSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
String[] pckage={"com.argus.intenew"};
sessionFactory.setPackagesToScan(pckage);
sessionFactory.setHibernateProperties(hibProperties());
return sessionFactory;
}
private Properties hibProperties() {
Properties properties = new Properties();
properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, "org.hibernate.dialect.MySQLDialect ");
properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, "true");
return properties;
}
#Bean
public HibernateTransactionManager transactionManager() {
return new HibernateTransactionManager(sessionFactory().getObject());
}
}
A note regarding DriverManagerDataSource this is nice for testing but please don't use this in production (unless you want an application that doesn't perform). Use a proper JDBC Connection Pool instead.
A final note, if you really want productivity drop hibernate, switch to JPA and use Spring Data JPA for your repositories. Saves you writing a lot of implementation code. (And the best maintainable and testable code is code not written :) ).