I have started working on Spring Boot for a while. For a project, I am trying to use factory bean for datasource creation. Ultimately, i need to create datasources dynamically from another db table. I have a prototype bean that creates a new datasource each time i call context.getBean("getDbEndpointDatasource", args....)
#Bean
#Scope("prototype")
#Qualifier("getDbEndpointDatasource")
public DataSource getDbEndpointDatasource(String url, String className, String userName, String password) {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(url);
dataSource.setDriverClassName(className);
dataSource.setUsername(userName);
dataSource.setPassword(password);
return dataSource;
}
I am getting datasource by using below.
DataSource getDbEndpointDatasource = (DataSource) context.getBean("getDbEndpointDatasource",
"jdbc:postgresql://127.0.0.1/spring-test?user=spring-test&password=spring",
"org.postgresql.Driver", "spring", "spring");
So, with the configuration above, i get the below exception when i start spring boot.
Caused by: java.lang.IllegalArgumentException: wrong number of arguments
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
... 103 more
I have been searching for a while why spring gives this exception. I also have another factory bean that is prototype scoped as well and it gives me a new object each time it is calld as expected. But here, i don't understand why i get this error. The number of arguments i passed to context.getBean method seems correct. Also, if i remove Scope annotation, i get no exception but it gives me the same datasource each time i call. I am not sure if i miss anything. It seems strange to me.
I appreciate if someone can give a clue or guide.
Thanks
Can you try like below.
DataSource endpointDatasource = (DataSource) context.getBean("getDbEndpointDatasource");
endpointDatasource.getDbEndpointDatasource("jdbc:postgresql://127.0.0.1/spring-test?user=spring-test&password=spring","org.postgresql.Driver", "spring", "spring");
Related
I need to set SimpleDriverDataSource object in order to create datasource with MongoDB, however I am not able to figure out what I should pass as "Driver".
I searched and found out that this is the JDBC driver for MongoDB "mongodb.jdbc.MongoDriver", but how do I set it up while initializing SimpleDriverDataSource object?
I have tried doing the below, but it shows error mentioned below
#Bean
protected DataSource dataSource() {
SimpleDriverDataSource ds = new SimpleDriverDataSource();
Driver driver = new Driver("mongodb.jdbc.MongoDriver");
ds.setDriverClass(driver);
ds.setUrl("jdbc:mongodb://localhost:27017:spring-security-sampledb");
ds.setUsername("root");
ds.setPassword("secret");
return ds;
}
error
Cannot instantiate the type Driver
I am new to Spring Boot. Can you please help me in implementing this?
java.sql.Driver is an interface, which means you cannot instantiate it like that. You may want to review the basics of Java before starting with Spring Boot.
In any case, you need to use new mongodb.jdbc.MongoDriver() instead of new Driver(), or use setDriverClass and pass it the class reference (mongodb.jdbc.MongoDriver.class) instead of a Driver instance.
Also, please be aware that SimpleDriverDataSource is probably the wrong choice, as - for example - it doesn't provide connection pooling.
Using WildFly 13.
I'm trying to get a java.sql.Connection from the datasource that is being defined in stadalone.xml, as so:
ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("java:jboss/datasources/myDS");
connection = ds.getConnection(user, password);
The above always fails with Caused by: javax.resource.ResourceException: IJ031016: Wrong credentials passed to getConnection, while
ds.getConnection()
works just fine and can retrieve the connection.
Moreover, when getting and inspecting the metadata from the connection retrieved via the no args call, the user and password seem to be the same that I'm passing to the method with arguments but which fails.
The datasource's pool section must include the true attribute in order for this to work.
According to this documentation:
https://www.playframework.com/documentation/2.5.x/JavaDatabase#exposing-the-datasource-through-jndi
I simply need another entry in my application.conf to expose a DataSource in JNDI:
db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:play"
db.default.jndiName=DefaultDS
I've added "tyrex" % "tyrex" % "1.0.1" to my libraryDepenencies in build.sbt.
From reading several other posts on this, it sound like I should be able to simply use
DataSource ds = (DataSource) play.api.libs.JNDI.initialContext().lookup("DefaultDS");
To fetch the DataSource from JNDI. However, when I try this it throws the following Exception:
javax.naming.NameNotFoundException: DefaultDS not found
at tyrex.naming.MemoryContext.internalLookup(Unknown Source)
at tyrex.naming.MemoryContext.lookup(Unknown Source)
at javax.naming.InitialContext.lookup(InitialContext.java:417)
The main reason I'm trying to do this is so that Quartz can re-use the DataSource/ConnectionPool created by Play instead of defining another in quartz.properties. According to the docs:
http://www.quartz-scheduler.org/documentation/quartz-2.x/configuration/ConfigDataSources.html
I should need the following two lines in quartz.properties:
org.quartz.jobStore.dataSource = h2
org.quartz.dataSource.h2.jndiURL = DefaultDS
However, Quartz throws a bunch of exceptions:
java.sql.SQLException: Could not retrieve datasource via JNDI url 'DefaultDS' javax.naming.NameNotFoundException: DefaultDS not found [See nested exception: java.sql.SQLException: Could not retrieve datasource via JNDI url 'DefaultDS' javax.naming.NameNotFoundException: DefaultDS not found]
I'm not sure where to go next. Any help would be appreciated.
Thanks.
Found it.
I simply needed to add jdbc to my libraryDependencies in build.sbt. This created and exposed the DataSource in JNDI.
Caused by: java.lang.NullPointerException
at org.springframework.boot.actuate.endpoint.DataSourcePublicMetrics.initialize(DataSourcePublicMetrics.java:64) ~[spring-boot-actuator-1.3.2.RELEASE.jar:1.3.2.RELEASE]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.7.0_79]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[?:1.7.0_79]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.7.0_79]
at java.lang.reflect.Method.invoke(Method.java:606) ~[?:1.7.0_79]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:354) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
I disabled the metrics too but no luck
endpoints.enabled=false
endpoints.autoconfig.enabled=false
endpoints.metrics.enabled=false
The DataSourcePublicMetrics bean always gets created, even when the metrics are disabled. This causes a NullPointerException when the database connection is unavailable, causing spring boot not to start.
I am using Hikari datasource and it fails to construct data source object when database is unavailable. Hence NPE from DataSourcePublicMetrics bean. I am able to circumvent the issue creating a Hikari data source that is lazy initialized with database config even when database is unavailable for later use when database becomes available. Not sure why HikariDataSource does not have a constructor for lazy init. It does have a default constructor but database config can't be set using any setter method. This is useful for applications where database is not always necessary to start them up.
public class LazyConnectionDataSource extends HikariDataSource {
public LazyConnectionDataSource(HikariConfig config) {
config.validate();
config.copyState(this);
}
}
I am using db4free's mysql server for my spring-webmvc project.But the problem is , I can't get a connection to the server and the Exception is
org.springframework.web.util.NestedServletException: Request processing failed;
nested exception is org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException:
Must specify port after ':' in connection string
But I have specified port correctly just after ':' , Here is my configuration java class:
#Configuration
#ComponentScan(basePackages="org.ratajo.amaderbari")
#EnableWebMvc
public class MvcConfiguration extends WebMvcConfigurerAdapter{
#Bean
public DataSource getDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://http://www.db4free.net:3306/myDB");
dataSource.setUsername("user");
dataSource.setPassword("pass");
return dataSource;
}
Here is the sample program I am trying to execute
MvcConfiguration mv = new MvcConfiguration();
JdbcTemplate jdbcTemplate = new JdbcTemplate(mv.getDataSource());
String sql="CREATE TABLE 'contact' ('contact_id' int(11) NOT NULL AUTO_INCREMENT,) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8";
jdbcTemplate.execute(sql);
The url looks weird :
dataSource.setUrl("jdbc:mysql://http://www.db4free.net:3306/myDB");
should be something like
dataSource.setUrl("jdbc:mysql://www.db4free.net:3306/myDB");
otherwise it is trying to use http as hostname and //www.db4free.net as port. (which explains the error). But I would also double check the hostname as it looks weird to go to a host 'www.something'.
OTOH jdbc url's are weird.