2

I am working on spring boot application and I trying to connect datasource using JNDI but it is not working and giving me below error please help if any one knows the reason:

This is the error it is showing:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'i': Invocation of init method failed; nested exception is org.springframework.jndi.JndiLookupFailureException: JndiObjectTargetSource failed to obtain new target object; nested exception is javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial 

For the pom.xml dependency file I have included following dependencies:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <!-- Added from here --> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>42.2.25</version> </dependency> 

As I am using postgresql database I have used it's dependencies and in application.properties file I have mentioned as below:

## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties) # Datasource settings spring.datasource.initialize=true spring.datasource.jndi-name=jdbc/IDB spring.jmx.enabled: false spring.datasource.driver-class-name=org.postgresql.Driver spring.datasource.url=jdbc:postgresql://localhost:5432/postgres spring.datasource.username=postgres spring.datasource.password=ROOT spring.datasource.type=javax.sql.DataSource spring.datasource.separator=; 

And for tomcat context naming initialization I have defined bean as below:

@Bean public TomcatServletWebServerFactory tomcatFactory() { return new TomcatServletWebServerFactory() { @Override protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) { tomcat.enableNaming(); try { tomcat.addContext("/aiv/appimages", imgLoc); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return super.getTomcatWebServer(tomcat); } @Override protected void postProcessContext(org.apache.catalina.Context context) { ContextResource resource = new ContextResource(); resource.setName("jdbc/ActiveIDB"); resource.setType(DataSource.class.getName()); resource.setProperty("driverClassName", "org.postgresql.Driver"); resource.setProperty("url", "jdbc:postgresql://localhost:5432/postgres"); resource.setProperty("username", "postgres"); resource.setProperty("password", "ROOT"); context.getNamingResources().addResource(resource); } }; } @Bean(destroyMethod="") public DataSource dataSource() throws IllegalArgumentException, NamingException { JndiObjectFactoryBean bean = new JndiObjectFactoryBean(); bean.setJndiName("java:comp/env/jdbc/IDB"); bean.setProxyInterface(DataSource.class); bean.setLookupOnStartup(false); bean.afterPropertiesSet(); return (DataSource)bean.getObject(); } 

Please any one can let me know what is wrong am I doing why it is giving me that error. Help appriteated.

1 Answer 1

2

You have to do 5 things:

  1. tomcat.enableNaming();
  2. add ContextResource to NamingResources (use same names: jdbc/IDB and jdbc/ActiveIDB have different hash codes :) )
  3. spring.datasource.jndi-name: jdbc/DS_NAME
  4. add org.springframework:spring-jdbc (class EmbeddedDatabaseType) to classpath (it will activate JndiDataSourceAutoConfiguration)

at this moment, spring will try to create datasource but fails, because of org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory class is not in classpath (it's default factory for javax.sql.DataSource resource)

  1. add dependency org.apache.tomcat:tomcat-dbcp:8.5.4 [or hier version] (it contains org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory)

 package com.example; import org.apache.catalina.Context; import org.apache.catalina.startup.Tomcat; import org.apache.tomcat.util.descriptor.web.ContextResource; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.embedded.tomcat.TomcatWebServer; import org.springframework.context.annotation.Bean; import javax.servlet.ServletException; import javax.sql.DataSource; import java.io.IOException; import java.sql.SQLException; @SpringBootApplication public class Application { /** * Or you can copy full implementation from * org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration.EmbeddedTomcat * override only getTomcatWebServer(Tomcat) * and provide TomcatContextCustomizer instead of overriding 'postProcessContext(Context)' */ @Bean public TomcatServletWebServerFactory tomcatServletWebServerFactory() { return new TomcatServletWebServerFactory() { @Override protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) { //1 enable naming tomcat.enableNaming(); return super.getTomcatWebServer(tomcat); } @Override protected void postProcessContext(Context context) { //2 create resource ContextResource resource = new ContextResource(); resource.setName("jdbc/h2DS"); resource.setType(DataSource.class.getName()); resource.setProperty("driverClassName", "org.h2.Driver"); resource.setProperty("url", "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"); resource.setProperty("username", "sa"); resource.setProperty("password",""); context.getNamingResources().addResource(resource); } }; } public static void main(String[] args) throws ServletException, IOException, SQLException { //3 JndiDataSourceAutoConfiguration will provide that bean if // a) spring.datasource.jndi-name: jdbc/h2DS // b) org.springframework:spring-jdbc (class EmbeddedDatabaseType) is in classpath SpringApplication.run(Application.class, args) .getBean(DataSource.class) .getConnection(); } } 

dependencies

  1. org.springframework.boot:spring-boot-starter-web
  2. org.springframework:spring-jdbc
  3. com.h2database:h2:2.1.214 (runtime)
  4. org.apache.tomcat:tomcat-dbcp:8.5.4 [or hier] (runtime)

application.properties

spring.datasource.jndi-name=jdbc/h2DS 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.