how to config mybatis in springboot - spring-boot

I have two config here:
#Configuration
public class DataConfig {
#Value("${datasource.jdbcUrl}")
private String jdbcUrl;
#Value("${datasource.username}")
private String username;
#Value("${datasource.password}")
private String password;
#Value("${datasource.driverClassName:com.mysql.jdbc.Driver}")
private String driverClassName;
#Value("${datasource.initialSize:20}")
private int initialSize;
#Value("${datasource.maxActive:30}")
private int maxActive;
#Value("${datasource.minIdle:20}")
private int minIdle;
#Value("${datasource.transactionTimeoutS:30}")
private int transactionTimeoutS;
#Value("${datasource.basePackage:com.tg.ms.mapper}")
private String basePackage;
#Value("${datasource.mapperLocations}")
private String mapperLocations;
#Bean
public DataSource dataSource() {
DruidDataSource ds = new DruidDataSource();
ds.setMaxWait(maxWait);
ds.setValidationQuery(validationQuery);
ds.setRemoveAbandoned(removeAbandoned);
ds.setRemoveAbandonedTimeout(removeAbandonedTimeout);
ds.setTestWhileIdle(testWhileIdle);
ds.setTestOnReturn(testOnReturn);
ds.setTestOnBorrow(testOnBorrow);
ds.setMinIdle(minIdle);
return ds;
}
#Bean
public SqlSessionFactory sqlSessionFactoryBean() throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource());
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath:/mybatis/*.xml"));
return sqlSessionFactoryBean.getObject();
}
---------- Another Config -------------
#Configuration
#AutoConfigureAfter(DataBaseConfig.class)
public class MapperScannerConfig {
#Value("${datasource.basePackage:com.tg.ms.mapper}")
private String basePackage;
#Bean
public MapperScannerConfigurer BPMapperScannerConfigurer() {
System.out.println("mapper--1.----******----"+basePackage+"----*******");
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setBasePackage("com.tg.mapper");
mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactoryBean");
return mapperScannerConfigurer;
}
}
Can I put#Bean public MapperScannerConfigurer BPMapperScannerConfigurer() into DataConfig? I try but print:
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'testController': Unsatisfied dependency expressed through field 'testMapper'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testMapper' defined in file [/Users/twogoods/codesource/mainetset/target/classes/com/tg/mapper/TestMapper.class]: Cannot resolve reference to bean 'sqlSessionFactoryBean' while setting bean property 'sqlSessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactoryBean' defined in class path resource [com/tg/config/DataConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.ibatis.session.SqlSessionFactory]: Factory method 'sqlSessionFactoryBean' threw exception; nested exception is java.lang.NullPointerException
MapperScannerConfig init earlier than DataConfig, I get it from print log,#Value("${datasource.basePackage:com.tg.ms.mapper}") private String basePackage;can not get value(in DataConfig can get),I use #AutoConfigureAfter is useless,MapperScannerConfig is also eariler, I can not config mapper basePackage
log:Cannot enhance #Configuration bean definition 'BPMapperScannerConfigurer' since its singleton instance has been created too early. The typical cause is a non-static #Bean method with a BeanDefinitionRegistryPostProcessor return type: Consider declaring such methods as 'static'.

I got the same problem. MapperScannerConfigurer is initialized too early in spring framework and ,i think it causes the annotation #AutoConfigureAfter become useless.
So i solve it like : avoid the use of MapperScannerConfigurer:
two ways:
just use #MapperScan("com.a.b.package")
use annotation #org.apache.ibatis.annotations.Mapper in your mybatis mapper interface.

Related

Java AWS SDK v2 S3Client creation fail

I'm try to use S3Client from AWS Java SDK v2, on my JHipster Spring boot project.
In addition to S3CLient i'm using S3Presigner for pre-signed url generation.
This is the configuration class, that i'm using to create beans:
#Configuration
public class AWSConfiguration {
private final Logger log = LoggerFactory.getLogger(AWSConfiguration.class);
#Bean(name = "credentialsProvider")
public AwsCredentialsProvider getCredentialsProvider(#Value("${aws.accessKey}") String accessKey, #Value("${aws.secretKey}") String secretKey) {
return StaticCredentialsProvider.create(AwsBasicCredentials.create(accessKey, secretKey));
}
#Bean(name = "presigner")
#Primary
public S3Presigner getPresigner(#Value("${aws.region}") String awsRegion, #Qualifier("credentialsProvider") final AwsCredentialsProvider credentialsProvider) {
return S3Presigner.builder().credentialsProvider(credentialsProvider).region(Region.of(awsRegion)).build();
}
#Bean(name = "s3Client")
#Primary
public S3Client getS3Client(#Value("${aws.region}") String awsRegion, #Qualifier("credentialsProvider") final AwsCredentialsProvider credentialsProvider) {
return S3Client.builder().credentialsProvider(credentialsProvider).region(Region.of(awsRegion)).build();
}
}
At the boot, i've this error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 's3Client' defined in class path resource [com/cyd/bb/config/AWSConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [software.amazon.awssdk.services.s3.S3Client]: Factory method 'getS3Client' threw exception; nested exception is java.lang.IllegalArgumentException: Expected a profile or property definition on line 1
If i remove "s3Client" bean the project start correctly and i can use presigner without problems.
So s3Client produce the error, someone can help me for this issue?
Thanks in advance.

Using Prototype scope to create DataSource

I'm trying to create a Prototyped Scoped Spring bean using the given configuration. The details for url, username, password, driver will be determined at runtime. Here's my configuration:
#Configuration
class Cfg {
#Bean
public Function<DataSourcePropertiesMap, DriverManagerDataSource> functionOfDriverMgrDS() {
return this::driverManagerDataSource;
}
#Lazy
#Bean
#Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public DriverManagerDataSource driverManagerDataSource(DataSourcePropertiesMap dbPropsMap) {
var ds = new DriverManagerDataSource(dbPropsMap.getDbURL(), dbPropsMap.getDbUsername(), dbPropsMap.getDbPassword());
ds.setDriverClassName(dbPropsMap.getDbDriver());
return ds;
}
}
And the DataSourcePropertiesMap is simply a container for the four arguments as below:
#Getter
#AllArgsConstructor
public class DataSourcePropertiesMap {
#NonNull private final String dbURL;
#NonNull private final String dbUsername;
#NonNull private final String dbPassword;
#NonNull private final String dbDriver;
}
Whenever, I boot the application it throws the following exception:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'healthContributorRegistry' defined in class path resource [org/springframework/boot/actuate/autoconfigure/health/HealthEndpointConfiguration.class]: Unsatisfied dependency expressed through method 'healthContributorRegistry' parameter 2; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'dbHealthContributor' defined in class path resource [org/springframework/boot/actuate/autoconfigure/jdbc/DataSourceHealthContributorAutoConfiguration.class]: Unsatisfied dependency expressed through method 'dbHealthContributor' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'driverManagerDataSource' defined in class path resource [Cfg.class]: Unsatisfied dependency expressed through method 'driverManagerDataSource' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'DataSourcePropertiesMap' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Why Spring still requires arguments for DriverManagerDataSource with valid driver class for Prototyped Scoped beans. My assumption is it will register a bean someway and create a new instance whenever a call is made with the arguments. If I create a default bean of type DataSourcePropertiesMap with dummy values it requires a valid driverclass.
Editing my original answer since I have not seen this part of the question
The details for url, username, password, driver will be determined at
runtime.
As of spring boot 2.x there is still no automatic way of loading properties on runntime. You would have to manually parse the file and read those properties inside this prototype bean method.

Cucumber Spring and class configuration

I'm struggling with Cucumber and Spring configuration.
I'm writing selenium framework using Page Object Pattern, with BrowserFactory.
When I use #ComponentScan, #Component and #Autowire annotations everything works fine, but when I want to create a bit more complicated bean with #Bean annotation (BrowserFactory which registers few browser drivers) in #Configuration class it does not work, during debug I'm getting nulls on every single variable I'm trying to Autowire.
I'm using Spring 4.2.4, all cucumber dependencies in version 1.2.4.
Config:
#Configuration
public class AppConfig {
#Bean
#Scope("cucumber-glue")
public BrowserFactory browserFactory() {
BrowserFactory browserFactory = new BrowserFactory();
browserFactory.registerBrowser(new ChromeBrowser());
browserFactory.registerBrowser(new FirefoxBrowser());
return browserFactory;
}
#Bean(name = "loginPage")
#Scope("cucumber-glue")
public LoginPage loginPage() throws Exception {
return new LoginPage();
}
#Bean(name = "login")
#Scope("cucumber-glue")
public Login login() {
return new Login();
}
}
POP:
public class LoginPage extends Page {
public LoginPage() throws Exception {
super();
}
...
}
Page:
public class Page {
#Autowired
private BrowserFactory browserFactory;
public Page() throws Exception{
...
}
}
Login:
public class Login {
#Autowired
private LoginPage loginPage;
public Login(){}
...
}
Steps:
#ContextConfiguration(classes = {AppConfig.class})
public class LoginSteps {
#Autowired
Login login;
public LoginSteps(){
}
#Given("^an? (admin|user) logs in$")
public void adminLogsIn(Login.User user) throws Exception {
World.currentScenario().write("Logging in as " + user + "\n");
login.as(user);
}
}
Error:
cucumber.runtime.CucumberException: Error creating bean with name 'LoginSteps': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: Login LoginSteps.login; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'login': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private LoginPage Login.loginPage; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'loginPage' defined in AppConfig: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [LoginPage]: Factory method 'loginPage' threw exception; nested exception is java.lang.NullPointerException
And now for the fun part...
BrowserFactory in World class is properly Autowired!!
World:
public class World {
#Autowired
private BrowserFactory browserFactory;
...
}
So I'll answer my own question:)
Issue was that I was calling BrowserFactory inside of Page constructor.
Looks like this bean was not yet created and was causing NPEs.
In order to fix that I:
Added #Lazy annotation to configuration (all elements that use this configuration, both defined in that class and those which will be found by Scan will be created as Lazy)
Moved call to Browser Factory to #PostConstruct method
Two more things to increase readability of Spring config:
Added #ComponentScan to configuration
Classes with no constructor parameters are annotated with #Component and #Scope("cucumber-glue") annotation so bean creation can be removed from AppConfig.class

Spring integration, auto wiring failed (null)

I am using spring integration to listen to emails.
I have a Spring component named mailService that is instantiated and the method handledMail is called each time a new email arrives.
I wanted to add some more code into EmailService like this:
#Component(value="mailService")
public class EmailService {
#Autowired
private ApplicationContext applicationContext;
My issue is that I have a null pointer exception when accessing applicationContext
Do you have any idea where does this can come from? My applicationContext.xml file was read. All the channels have started and the emailService component has been instantiated by Spring. Should I add something specific in the configuration?
Some more code:
#Component(value="mailService")
public class EmailService {
private final static Logger logger = Logger.getLogger(EmailService.class);
#Autowired
#Qualifier(value="mailSender")
private JavaMailSenderImpl mailSender;
public EmailService() {
initContext();
}
private void initContext() {
RuleManager ruleManager = (RuleManager) applicationContext.getBean("localRuleManager");
ContextEvidence evidence = new ContextEvidenceEntry(EvidenceType.ROLE, new String("Front Office"));
ruleManager.addMultipleEvidence(evidence);
}
I have a null pointer exception in the first line of initContext, applicationContext being null
The listening channel is started as below;
final ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
DirectChannel inputChannel = ac.getBean("receiveChannel", DirectChannel.class);
It was working fine before I added the applicationContext and the initContext() lines.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mailService' defined in file [XXXX/EmailService.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [XXXXEmailService]: Constructor threw exception; nested exception is java.lang.NullPointerException
Thanks
Gilles

How to create a Spring bean for apache logging Log class?

I'd like to create an autowired bean in a Dao class in order to do logging opperations. My way was hitherto static final statement like this:
private static final Log log = LogFactory.getLog(LoggedClass.class);
But now I'm trying to use IoC to turn classes decoupled.
If just add configuration in pom.xml and try to do sth like
#Autowired
Log log;
I receive an error message:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'funciDaoImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.apache.commons.logging.Log br.com.bb.dirco.dao.impl.FunciDaoImpl.log; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'log' defined in class path resource [com/company/project/util/PersistenceConfig.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [java.lang.Class]: : No qualifying bean of type [java.lang.Class] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [java.lang.Class] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
In order to get a logger, I had to provide a class to getLog method on LogFactory class and attribute it to Log instance. There's a way to do it using #Autowired Spring IoC? Thanks!
You can inject only those objects which are managed/created by Spring container. You have to register your bean (or factory method creating the bean) with container (with annotations like #Component/#Singleton/... or directly in xml)
In your case it's not very applicable since you have to have many different types (for every class) of logger objects provided by Spring and then when you inject they would have to be identified by different name/type for every class.
P.S. I don't see any problem using it the way you use it now
Where I work we have implemented support for #Autowired SLF4J Loggers using Springs BeanPostProcessor.
First you need to define an Logger placeholder bean in your application context. This bean is going to be injected by Spring into all bean with a #Autowired Logger field.
#Configuration
public class LoggerConfig {
#Bean
public Logger placeHolderLogger() {
return PlaceHolder.LOGGER;
}
#Bean
public AutowiredLoggerBeanPostProcessor loggerPostProcessor() {
return new AutowiredLoggerBeanPostProcessor();
}
}
Then you an AutowiredLoggerBeanPostProcessor which inspects all beans, indetify bean that contain Logger fields annotated with #Autowired (at this point should contain a reference to the Logger placeholder bean), create a new Logger for the partilcar bean an assigned it to the fields.
#Component
public class AutowiredLoggerBeanPostProcessor implements BeanPostProcessor, PriorityOrdered {
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
attachLogger(bean);
return bean;
}
#Override
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
attachLogger(bean);
return bean;
}
private void attachLogger(final Object bean) {
ReflectionUtils.doWithFields(bean.getClass(), new FieldCallback() {
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
if (Logger.class.isAssignableFrom(field.getType()) &&
(field.isAnnotationPresent(Autowired.class) ||
field.isAnnotationPresent(Inject.class))) {
ReflectionUtils.makeAccessible(field);
if (field.get(bean) == PlaceHolder.LOGGER) {
field.set(bean, LoggerFactory.getLogger(bean.getClass()));
}
}
}
});
}
#Override
public int getOrder() {
return HIGHEST_PRECEDENCE;
}
}

Resources