0

I am trying to connect to a postgres db using a spring jdbc connection. However it cannot seem to find the postgres drivers when the app is deployed to tomcat. I can view the class in intellij, and it is listed in my external dependencies folder, but alas a ClassNotFoundException is thrown.

<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:context="http://www.springframework.org/schema/context"
   xmlns:mvc="http://www.springframework.org/schema/mvc"
   xmlns:util="http://www.springframework.org/schema/util" xmlns:aop="http://www.springframework.org/schema/aop"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
   http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

<context:component-scan base-package="com.planit.mvc.*"/>

<mvc:resources mapping="/resources/**" location="/resources/"/>
<!--https://github.com/priyatam/springmvc-bootstrap-showcase/tree/master/src/main/webapp  base resources off this.-->
<mvc:annotation-driven/>

<mvc:view-controller path="/" view-name="hello"/>


<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/pages/"/>
    <property name="suffix" value=".jsp"/>
</bean>

<!-- DB CONNECTION -->
<bean class="java.net.URI" id="dbUrl">
    <constructor-arg value="#{T(com.ProjectUtils).getDBUrl()}"/>
</bean>

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="org.postgresql.Driver" />
    <property name="url" value="#{ 'jdbc:postgresql://' + @dbUrl.getHost() + ':' + @dbUrl.getPort() + @dbUrl.getPath() }"/>
    <property name="username" value="#{ @dbUrl.getUserInfo().split(':')[0] }"/>
    <property name="password" value="#{ @dbUrl.getUserInfo().split(':')[1] }"/>
</bean>




<util:properties id="socialAuthProperties" location="/WEB-INF/oauth_consumer.properties"></util:properties>

<bean id="socialAuthConfig" class="org.brickred.socialauth.SocialAuthConfig">
    <property name="applicationProperties">
        <ref bean="socialAuthProperties"/>
    </property>
</bean>

<bean id="socialAuthManager" class="org.brickred.socialauth.SocialAuthManager" scope="session">
    <property name="socialAuthConfig">
        <ref bean="socialAuthConfig"/>
    </property>
    <aop:scoped-proxy/>
</bean>

<bean id="socialAuthTemplate" class="org.brickred.socialauth.spring.bean.SocialAuthTemplate" scope="session">
    <aop:scoped-proxy/>
</bean>


<bean id="socialAuthWebController" class="org.brickred.socialauth.spring.controller.SocialAuthWebController">
    <constructor-arg value="#{T(com.ProjectUtils).getBaseUrl()}"/>
    <constructor-arg value="authSuccess"/>
    <constructor-arg value="jsp/accessDenied.jsp"/>
</bean>


<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    <property name="corePoolSize" value="5"/>
    <property name="maxPoolSize" value="10"/>
    <property name="WaitForTasksToCompleteOnShutdown" value="true"/>
</bean>

And my POM is as follows.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.springapp</groupId>
<artifactId>planit-dev</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<name>planit-dev</name>

<properties>
    <spring.version>4.0.0.RELEASE</spring.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>4.0.0.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
    </dependency>

    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.1</version>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>${spring.version}</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.8.2</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-mapper-asl</artifactId>
        <version>1.9.13</version>
    </dependency>

    <dependency>
        <groupId>org.brickred</groupId>
        <artifactId>socialauth</artifactId>
        <version>4.3</version>
    </dependency>

    <dependency>
        <groupId>org.brickred</groupId>
        <artifactId>socialauth-spring</artifactId>
        <version>2.4</version>
    </dependency>

    <dependency>
        <groupId>com.restfb</groupId>
        <artifactId>restfb</artifactId>
        <version>1.6.12</version>
    </dependency>

    <dependency>
        <groupId>com.google.apis</groupId>
        <artifactId>google-api-services-calendar</artifactId>
        <version>v3-rev73-1.17.0-rc</version>
    </dependency>

    <dependency>
        <groupId>com.google.oauth-client</groupId>
        <artifactId>google-oauth-client</artifactId>
        <version>1.17.0-rc</version>
    </dependency>

    <dependency>
        <groupId>com.google.oauth-client</groupId>
        <artifactId>google-oauth-client-servlet</artifactId>
        <version>1.17.0-rc</version>
    </dependency>

    <dependency>
        <groupId>com.google.http-client</groupId>
        <artifactId>google-http-client-jackson2</artifactId>
        <version>1.15.0-rc</version>
    </dependency>

    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.3.1</version>
    </dependency>

    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>r09</version>
    </dependency>

    <dependency>
        <groupId>org.optaplanner</groupId>
        <artifactId>optaplanner-core</artifactId>
        <version>6.0.1.Final</version>
    </dependency>

     <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>9.3-1100-jdbc41</version>
    </dependency>




</dependencies>

<build>

    <finalName>planit-dev</finalName>
    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.7</source>
                <target>1.7</target>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-surefire-plugin</artifactId>
            <configuration>
                <includes>
                    <include>**/*Tests.java</include>
                </includes>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <version>2.3</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals><goal>copy</goal></goals>
                    <configuration>
                        <artifactItems>
                            <artifactItem>
                                <groupId>com.github.jsimone</groupId>
                                <artifactId>webapp-runner</artifactId>
                                <version>7.0.40.0</version>
                                <destFileName>webapp-runner.jar</destFileName>
                            </artifactItem>
                        </artifactItems>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Upon a build in intellij it seems that the jar is not present in the libs folder under the web-inf directory, and when I call Class.forName("org.postgresql.Driver"); I get the class not found exception.

How can I have this added in correctly with maven?

Any help would be much appreciated.

EDIT:

It appears this is also happening with the Spring JDBC dependency that I have just added.

org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [org.springframework.jdbc.datasource.DriverManagerDataSource] for bean with name 'dataSource' defined in ServletContext resource [/WEB-INF/mvc-dispatcher-servlet.xml]; nested exception is java.lang.ClassNotFoundException: org.springframework.jdbc.datasource.DriverManagerDataSource
org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1327)

Also not in the maven output folder.

This is being deployed to heroku, so I cant just create a libs folder I dont think!

user1089599
  • 303
  • 6
  • 20

3 Answers3

1

The driver needs to be placed in $TOMCAT_HOME/lib instead of inside the WAR in WEB-INF/lib, and in the pom the driver dependency should be set to provided:

 <dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>9.3-1100-jdbc41</version>
    <scope>provided</scope>
</dependency>

In general the JDBC drivers should always be installed at the level of the server and not of the application. The reason is that the driver registers itself the first time that its initialized in a singleton at the level of a JVM class, and deploying it to multiple WARs will give rise to memory leaks.

Its possible that your Tomcat detects this situation and is unregistering the driver, preventing the memory leak but also from being initialized correctly - have a look at this answer for more details as well.

Community
  • 1
  • 1
Angular University
  • 42,341
  • 15
  • 74
  • 81
  • This is actually being deployed on heroku, so how can I compensate for that? – user1089599 Feb 17 '14 at 19:32
  • then heroku should make the driver available at the server you either by default as you chose Postgresql or via some configuration in the online console, check https://devcenter.heroku.com/articles/heroku-postgresql – Angular University Feb 17 '14 at 19:47
  • Its by following this guide that I actually get the issue, as my pom seems to import it the same way as the guide. – user1089599 Feb 17 '14 at 19:59
  • try putting it in scope provided in the pom, this means it will not go in the WAR but it should be provided by the server – Angular University Feb 17 '14 at 20:01
  • I am unfamiliar with Maven for this, however I see it is using a plugin called jimone.How can I ask for jars to be added into this destination file? – user1089599 Feb 17 '14 at 20:10
  • i have added the way to declare the driver dependency with scope provided. – Angular University Feb 17 '14 at 20:12
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/47694/discussion-between-user1089599-and-jhadesdev) – user1089599 Feb 17 '14 at 20:15
1

Turns out in my POM that I had somehow managed to change the packaging type from war to pom. Changing this back has added the libraries successfully into the war file!

<packaging>war</packaging>
user1089599
  • 303
  • 6
  • 20
0

I am using spring and postgresql in my project. Here some snippets: (ps: cannot remember if I put the postgresql drivers manually somewhere) (maven packages as war)

MAVEN

...
<properties>
    <postgresql.version>9.2-1003-jdbc4</postgresql.version>
</properties>
...

<dependencies>
    <!--PostgreSQL driver-->
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>${postgresql.version}</version>
    </dependency>
...

SPRING CONFIG CONTEXT

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="packagesToScan" value="au.com.xxx.core.modules.*.persistence"/>
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="showSql" value="false"/>
            <property name="generateDdl" value="false"/>
            <property name="database" value="POSTGRESQL"/>
        </bean>
    </property>
</bean>

    <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName" value="java:comp/env/jdbc/DatabaseName"/>
    </bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

TOMCAT CONTEXT

<Resource name="jdbc/DatabaseName" auth="Container" type="javax.sql.DataSource"
          username="myuser" password="secret"
          url="jdbc:postgresql://172.16.1.2:5432/db_name"
          driverClassName="org.postgresql.Driver"
          initialSize="5" maxWait="5000"
          maxActive="120" maxIdle="5"
          validationQuery="select 1"
          poolPreparedStatements="true"/>

<ResourceLink name="jdbc/DatabaseName"
              global="jdbc/DatabaseName"
              type="javax.sql.DataSource"/>

Mircea Stanciu
  • 3,675
  • 3
  • 34
  • 37