Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring boot JNDI datasource lookup failure - Name comp/env/jdbc not found in context "java:"

I have setup a spring boot (v 1.1.9) application to deploy as a WAR file. And I'm trying to integrate this web application with an existing data service module (added as a maven dependency).

Environment trying to deploy: WebSphere Application Server 8.5.5.4

The issue I'm facing is an application start-up failure when try to look-up a JNDI dataSource (jdbc/fileUploadDS) as below within the dependent data service module.

@Configuration
@Profile("prod")
public class JndiDataConfig implements DataConfig {

    @Bean
    public DataSource dataSource() throws NamingException {
          Context ctx = new InitialContext();
          return (DataSource) ctx.lookup("java:comp/env/jdbc/fileUploadDS");
    }

}

My Spring Boot configuration:

@Configuration
@ComponentScan(basePackages = { "au.com.aiaa.fileupload.data.*", "demo" })
@EnableAutoConfiguration(exclude = { HibernateJpaAutoConfiguration.class, DataSourceAutoConfiguration.class })
public class SampleApplication extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(applicationClass, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(applicationClass);
    }

    private static Class<SampleApplication> applicationClass = SampleApplication.class;

    @Bean
    public static Properties fileUploadJndiProperties() throws NamingException {
        JndiObjectFactoryBean jndiFactoryBean = new JndiObjectFactoryBean();
        jndiFactoryBean.setJndiName("props/FileUploadProperties");
        jndiFactoryBean.setExpectedType(Properties.class);
        jndiFactoryBean.setLookupOnStartup(true);
        jndiFactoryBean.afterPropertiesSet();
        return (Properties) jndiFactoryBean.getObject();
    }

}

Note that I'm able to lookup props/FileUploadProperties successfully. But failing to do the same for a datasource.

My doubt is it is trying to load a EmbeddedWebApplicationContext which is not what I want.

The stack trace is:

Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public javax.sql.DataSource au.com.aiaa.fileupload.data.dao.configuration.JndiDataConfig.dataSource() throws javax.naming.NamingException] threw exception; nested exception is **javax.naming.NameNotFoundException: Name comp/env/jdbc not found in context "java:".**
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:301)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1186)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:706)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:762)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
        at **org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:109)**
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
        at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:142)
        at org.springframework.boot.context.web.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:89)
        at org.springframework.boot.context.web.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:51)
        at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:175)


..................

Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public javax.sql.DataSource au.com.aiaa.fileupload.data.dao.configuration.JndiDataConfig.dataSource() throws javax.naming.NamingException] threw exception; nested exception is **javax.naming.NameNotFoundException: Name comp/env/jdbc not found in context "java:".**
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:188)
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:586)
        ... 132 common frames omitted
Caused by: javax.naming.NameNotFoundException: Name comp/env/jdbc not found in context "java:".
        at com.ibm.ws.naming.ipbase.NameSpace.getParentCtxInternal(NameSpace.java:1970)
        at com.ibm.ws.naming.ipbase.NameSpace.retrieveBinding(NameSpace.java:1377)
        at com.ibm.ws.naming.ipbase.NameSpace.lookupInternal(NameSpace.java:1220)
        at com.ibm.ws.naming.ipbase.NameSpace.lookup(NameSpace.java:1142)
        at com.ibm.ws.naming.urlbase.UrlContextImpl.lookupExt(UrlContextImpl.java:1436)
        at com.ibm.ws.naming.java.javaURLContextImpl.lookupExt(javaURLContextImpl.java:477)
        at com.ibm.ws.naming.java.javaURLContextRoot.lookupExt(javaURLContextRoot.java:485)
        at com.ibm.ws.naming.java.javaURLContextRoot.lookup(javaURLContextRoot.java:370)
        at org.apache.aries.jndi.DelegateContext.lookup(DelegateContext.java:161)
        at javax.naming.InitialContext.lookup(InitialContext.java:436)
        at au.com.aiaa.fileupload.data.dao.configuration.JndiDataConfig.dataSource(JndiDataConfig.java:41)
        at au.com.aiaa.fileupload.data.dao.configuration.JndiDataConfig$$EnhancerBySpringCGLIB$$8001dbbe.CGLIB$dataSource$0(<generated>)
        at au.com.aiaa.fileupload.data.dao.configuration.JndiDataConfig$$EnhancerBySpringCGLIB$$8001dbbe$$FastClassBySpringCGLIB$$3c9e0518.invoke(<generated>)
        at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
        at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:312)
        at au.com.aiaa.fileupload.data.dao.configuration.JndiDataConfig$$EnhancerBySpringCGLIB$$8001dbbe.dataSource(<generated>)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
        at java.lang.reflect.Method.invoke(Method.java:611)
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:166)

What am I missing here? Even when I try to explicitly define the dataSource bean method in SampleApplication.java like below it fails with the same error.

@Bean
    public static DataSource dataSource() throws NamingException {
        JndiObjectFactoryBean jndiFactoryBean = new JndiObjectFactoryBean();
        jndiFactoryBean.setJndiName("java:comp/env/jdbc/fileUploadDS");
        jndiFactoryBean.setExpectedType(DataSource.class);
        jndiFactoryBean.setLookupOnStartup(true);
        jndiFactoryBean.setResourceRef(true);
        jndiFactoryBean.afterPropertiesSet();
        return (DataSource) jndiFactoryBean.getObject();
    }

I referred this and it says we need to set enableNaming() on servlet container? Can I do something similar for non-embedded web application context? Or is it purely a WAS 8.5 issue??

like image 757
Dinusha Kariyawasam Avatar asked Dec 15 '14 07:12

Dinusha Kariyawasam


People also ask

Which exception do you use to detect if a lookup on a JNDI resources has failed?

If a resource reference does not exist in the application module, the JNDI lookup will fail with the javax. naming. NamingException mentioned above.

What is JNDI lookup in Java?

The Java Naming and Directory Interface (JNDI) is a Java API for a directory service that allows Java software clients to discover and look up data and resources (in the form of Java objects) via a name.

Why JNDI is used in Java?

The Java Naming and Directory Interface (JNDI) provides consistent use of naming and/or directory services as a Java API. This interface can be used for binding objects, looking up or querying objects, as well as detecting changes on the same objects.

What is Java comp ENV?

java:comp/env is the node in the JNDI tree where you can find properties for the current Java EE component (a webapp, or an EJB). Context envContext = (Context)initContext.lookup("java:comp/env");


4 Answers

You need to have resource reference with jdbc/fileUploadDS name in your web.xml. And make sure it is bound to actual datasource name during installation or via ibm-web-bnd.xml file.

Definition in web.xml:

<resource-ref>
    <description />
    <res-ref-name>jdbc/fileUploadDS</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>

If you dont want to use web.xml, then in normal Java EE app you could just add in web component (servlet, filter) the following class annotation:

@Resource(name="jdbc/fileUploadDS", type=javax.sql.DataSource.class, lookup="jdbc/fileUploadDS")

but I'm not Spring-boot expert, so don't know, if it will work or is possible there.

like image 151
Gas Avatar answered Nov 09 '22 17:11

Gas


I am able to connect my Spring-Boot application (deployed in Websphere Application Server 9) to WAS datasource. The following code worked for me, for connecting to DataSource:

@Bean(name = "WASDataSource")
public DataSource WASDataSource() throws Exception {        
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
return dataSourceLookup.getDataSource("DSNAME");
}   

@Bean(name = "WASDataSourceJdbcTemplate")
public JdbcTemplate jdbcTemplate_WASDS(@Qualifier("WASDataSource")
DataSource dsDB2) {
return new JdbcTemplate(dsDB2);
}

Note: The name of Datasource "DSNAME" is the name which appears on the UI of Websphere console. You can see that via -> Select Resources > JDBC > Data Sources.

Then I created jdbc template:

@Autowired
@Qualifier("WASDataSourceJdbcTemplate")
private JdbcTemplate db2WASTemplate;`

And running query using the query method works fine :
db2WASTemplate.query()

I did not create any Web.xml or ibm-web-bnd.xml files

like image 42
yash nigam Avatar answered Nov 09 '22 18:11

yash nigam


I just configured spring boot with my custom datasource as follows:

@Bean
@ConfigurationProperties("spring.datasource")
public DataSource dataSource() {
    return DataSourceBuilder.create().build();
}

and inside the application.properties file I defined all datasource settings as usual

spring.datasource.driver-class-name= ***
spring.datasource.url= ***
spring.datasource.username= ***
spring.datasource.password= ***
spring.datasource.jndi-name=jdbc/myDB

It works nicely with @SpringBootApplication with all other default settings

like image 23
Hany Sakr Avatar answered Nov 09 '22 17:11

Hany Sakr


I am facing the same problem. I don't know how to define tag in spring boot since there is no web.xml file in the spring boot.

So far what I came to know that we have to define it in the application file from where we start our spring application. I think we need to use this method to set the Datasource:

  @Bean(destroyMethod="")
  @ConfigurationProperties(prefix="datasource.mine")
  public DataSource dataSource() throws Exception {
      JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
      return dataSourceLookup.getDataSource("java:jdbc/configurationFile");
  }
like image 34
mohitkira Avatar answered Nov 09 '22 17:11

mohitkira