2

I've got a WebApp with Tomcat 10, Java11 using Jersey3. I defined a ConnectionPool in my context.xml for handling the connection to my OracleDB and now I'm trying to access the DataSource within my controller through a @Resource annotation. This should invoke a JNDI-lookup. Unfortunately, I always get a NPE as it seems not to find the resource while running... What am I doing wrong? Or what would the correct mappedName / lookup be?

  @Path("/data")
public class DataController  {

    @Context
    ServletContext context;

    @Resource(lookup = "java:/jdbc/myDB") //also tried java:/comp/env/jdbc/myDB and mappedName="jdbc/myDB"
    protected DataSource ds; //always null
<Context name="myapp">
<Resource type="javax.sql.DataSource"
          name="jdbc/myDB"
          factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
          driverClassName="oracle.jdbc.OracleDriver"
          url="jdbc:oracle:thin:@//localhost:1521/orcl"
          username="xy"
          password="xy"/>

According to the tutorials, a ref-link is optional when I define the resource directly in the context.xml.

Thanks for any input!

Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
Remo
  • 1,112
  • 2
  • 12
  • 25

1 Answers1

3

This link is about jboss, but would seem relevant to you too. It says that according to the specification, Resource annotation to do JNDI lookups would only work with EJBs, so it wouldn't work for your case.

A workaround is to do the programmatic way to see if your datasource is working:

Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
DataSource bean = (DataSource ) envCtx.lookup("jdbc/myDB");

If you can find your datasource you can then try to optimize to avoid "manual" lookup above.

eis
  • 51,991
  • 13
  • 150
  • 199
  • alright, that seems to work. But calling this everytime I need to get a connection to the DB seems not correct - is there no other way? – Remo Feb 16 '21 at 15:59
  • @Remo sure there is, plenty of ways. Like I wrote, the code I wrote was a workaround which you can then try to optimize once you got that going. If you want to use Resource annotation, you'd have to use it in a way specified by the specification - namely using EJBs. – eis Feb 16 '21 at 16:03
  • Hm would there be another way using something like the Resource annotations? I shall not use EJBs though... – Remo Feb 16 '21 at 16:05
  • @Remo btw I think Resource annotation should require a bean but possibly not an EJB, so I'm starting to think it should work for your case too, since your jax-rs is regarded as a bean. did you try `@Resource(name = "jdbc/myDB")` and `@Resource(name = "java:comp/env/jdbc/myDB")`? – eis Feb 16 '21 at 16:21
  • 2
    @Remo You need not write the code seen in this Answer every time you need a connection. I suggest you **write this code once, then cache** the resulting `DataSource` object. Every time you need a connection, you retrieve the cached `DataSource` object and call `getConnection`. – Basil Bourque Feb 16 '21 at 17:15
  • @eis tried both variant of the annotation, did not work. I'll try to fetch it in the ContextListener and cache it from there. The context is one thing, I can get from everywhere. – Remo Feb 17 '21 at 07:55
  • @Remo for `@Resource` to work you probably need `jersey-cdi2-se`. – Piotr P. Karwasz Feb 17 '21 at 09:39
  • @eis jersey-cdi2-se requires a bean.xml, altough I have no EJBs etc. – Remo Feb 19 '21 at 15:18
  • @Remo I don't think you meant to comment that to me. But it requires beans.xml, not bean.xml, and that is a requirement of the CDI specification. beans.xml actually is often just empty marker file to enable CDI. – eis Feb 19 '21 at 16:08