NullPointerException is thrown when trying to call JDBC from a servlet - java

I'm running my servlet RegistrationServlet , and I try to create a Database object
Here is the servlet :
#WebServlet("/register")
public class RegistrationServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
#Override
public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException
{
// create a new connection to mysql database , with this we put the new client in the database
Database myDabatase = null;
try {
myDabatase = new Database();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} // create a new database
myDabatase.createDatabaseAndTables(); // create the tables of the database
HttpSession session = request.getSession();
synchronized(session)
{
boolean returnValue = myDabatase.addNewClient("david", "cole", "jamie", "123456789", "johnny", "blabla");
if (returnValue == true) // client was added
{
String addressPath = "/WEB-INF/results/show-name.jsp";
RequestDispatcher dispatcher = request.getRequestDispatcher(addressPath);
dispatcher.forward(request, response);
}
else if (returnValue == false) // client was not added becuase he's already registered
{
}
}
}
}
Here is the complete class :
But when I execute that line in my servlet :
boolean returnValue = myDabatase.addNewClient("david", "cole", "jamie", "123456789", "johnny", "blabla");
I get a NullPointerException that says :
java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1711)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1556)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
at db.Database.<init>(Database.java:18)
at servlets.RegistrationServlet.doGet(RegistrationServlet.java:28)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
Which led me to the line :
Class.forName("com.mysql.jdbc.Driver");
in the constructor of the Database class , and as you can see in the track trace :
java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
But , when I execute the same program as a Main program :
public class Main {
public static void main(String [ ] args) throws Exception
{
Database myConnection = new Database();
myConnection.createDatabaseAndTables();
boolean returnValue = myConnection.addNewClient("david", "cole", "jamie", "123456789", "johnny", "blabla");
}
}
Everything is okay , and I get no NullPointerException .
Then what's wrong if I do that same thing from a servelt ? why the NullPointerException ?
Regards

The MySQL driver is missing from the classpath when you run the servlet. The JAR file with the driver probably needs to be added to the WEB-INF/lib directory of your webapp.

Make sure mysql driver jar is in your lib folder (or classpath if its console app). Try to specify port to mysql (3306 if you didn't change it).

The MySQL jar is missing from the classpath of your server's container whereas it is present when you run the standalone main application.

I had the same problem, in the same line, but I solved it by adding to the project the JAR for the MySQL connection.
Before, it was not included in the project because all the data for the connection had been added within the server configuration (Payara Server 5), just for this reason the error does not occur when displaying the project on the server. However, when running it in JUnit this is not taken into account, so it is necessary to add the JAR to make the connection directly from the project and not from the server.
I hope this is useful, for those who have the same problem.

Related

How can I rerun an Apache Flink Postgres JDBC job without getting "No suitable driver found" exception

I have a Flink job derived from the starter Maven project. That job has a source that opens a Postgres JDBC connection. I am executing the job on my own Flink session cluster using the example docker-compose.yml.
When I submit the job for the first time it executes successfully. When I try to submit it again I get the following error:
Caused by: java.sql.SQLException: No suitable driver found for jdbc:postgresql://host.docker.internal:5432/postgres?user=postgres&password=mypassword
at java.sql.DriverManager.getConnection(DriverManager.java:689)
at java.sql.DriverManager.getConnection(DriverManager.java:270)
at com.myorg.project.JdbcPollingSource.run(JdbcPollingSource.java:25)
at org.apache.flink.streaming.api.operators.StreamSource.run(StreamSource.java:110)
at org.apache.flink.streaming.api.operators.StreamSource.run(StreamSource.java:66)
at org.apache.flink.streaming.runtime.tasks.SourceStreamTask$LegacySourceFunctionThread.run(SourceStreamTask.java:269)
I have to restart my cluster in order to rerun my job. Why is this happening? How can I submit my job again without having to restart the cluster?
The only addition to the Maven starter project is:
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.24</version>
</dependency>
The Flink source does nothing but open a JDBC connection and is as follows:
package com.mycompany;
import org.apache.flink.streaming.api.functions.source.RichSourceFunction;
import java.sql.Connection;
import java.sql.DriverManager;
public class JdbcSource extends RichSourceFunction<Integer> {
private final String connString;
public JdbcSource(String connString) {
this.connString = connString;
}
#Override
public void run(SourceContext<Integer> ctx) throws Exception {
try (Connection conn = DriverManager.getConnection(this.connString)) {
}
}
#Override
public void cancel() {
}
}
I have tested this on Flink version 1.14.0 and 1.13.2 with the same results.
Note that this question provides a solution of using Class.forName("org.postgresql.Driver"); within my RichSourceFunction. However I would like to know what is going on.
The first question you can refer JDBC driver cannot be found when reading a DataSet from an SQL database in Apache Flink.
Second, if you use session mode. It can be easy to rerun the Flink job without restart the cluster. you can log in job manager shell then use the command rerun job.
Class.forName("org.postgresql.Driver"); will trigger static method block, so you DriverManager can get driver class. see:
// from org.postgresql.Driver
static {
try {
register();
} catch (SQLException var1) {
throw new ExceptionInInitializerError(var1);
}
}
I have this pom.xml dependency for Postgres for Apache Flink 1.13:
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4-1201-jdbc41</version>
</dependency>
you can have a Postgres connector class for example:
public class PostgreSQLConnector {
private static volatile PostgreSQLConnector instance;
private Connection connectionDB = null;
public PostgreSQLConnector(your params) {
...
}
public static PostgreSQLConnector getInstance() {
PostgreSQLConnector postgreSQLConnector = instance;
if (postgreSQLConnector != null)
return postgreSQLConnector;
synchronized (PostgreSQLConnector.class) {
if (instance == null) {
instance = new PostgreSQLConnector(your params);
}
return instance;
}
}
public Connection getConnectionDB() throws SQLException {
if (checkNullConnection()) CreateConnection();
return connectionDB;
}
public void CheckConnection() throws SQLException {
if (checkNullConnection()) CreateConnection();
}
public void CreateConnection() throws SQLException {
try {
Class.forName(sink.driverName);
connectionDB = DriverManager.getConnection(fullUrl, username, password);
} catch (Exception e) {
...
}
}
public boolean checkNullConnection() throws SQLException {
return (connectionDB == null || connectionDB.isClosed());
}
}
then you can create a RichSourceFunction and create the connection in the overrides open method, not in the run
public class JdbcSource extends RichSourceFunction<Integer> {
private final String connString;
private static Connection dbConnection;
private static final PostgreSQLConnector postgreSQLConnector = PostgreSQLConnector.getInstance();
public JdbcSource(String connString) {
this.connString = connString;
}
#Override
public void open(Configuration parameters) throws SQLException {
dbConnection = postgreSQLConnector.getConnectionDB();
}
#Override
public void close() throws Exception {
if (dbConnection != null) dbConnection.close();
}
#Override
public void run(SourceContext<Integer> ctx) throws Exception {
do something here with the connection
}
#Override
public void cancel() {
}
}
Something like that you could maybe try and it should work
According to the official documentation of PostgreSQL JDBC driver, if you are using Java 1.6+, you can just put the driver's jar file into the classpath. The driver will be loaded by the JVM automatically. So the question is how to place the driver's jar file into the classpath.
Since you are using docker to deploy a session cluster, there's two way that may works:
Put the driver's jar file into docker image
Run and access the image with the command:
docker docker run -it -v $PWD:/tmp/flink <address to image> -- bash
Copy the driver's jar file into the folder /opt/flink/lib.
Create a new image from the container. Since /opt/flink/lib is loaded as classpath by default, now the driver's jar file is located at the classpath.
Package the driver's jar into your user jar
Add maven-assembly-plugin to the pom.xml of your maven project. Recompile your project and get a jar file with dependencies. In this jar, the PostgreSQL JDBC driver is packaged together.

Java8-Maven No suitable jdbc driver found

I need help with my project when I try to run the project using myBatis, SQL Connector and Maven and I just get that error:
"no suitable jdbc driver found"
I have no clue how to fix this from now on.
public void openConnection() throws IOException, SQLException {
///database/src/main/java/Mappers/
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(inputStream);
session = sqlSessionFactory.openSession();
updateData();
}
private void updateData() {
int createTable = session.update("database.resources.createTableToTest");
int addTable = session.update("database.resources.addToTest");
test();
}
You have to set classpath for your connector.jar in eclipse using build path and
You also have to put connector.jar to the lib folder of WEB-INF Directory.

Class.forName("com.mysql.jdbc.Driver").newInstance()

I am having this error on Netbeans 7.2, it says that ClassNotFoundexception and InstantationException. I am really stuck on this matter. Kindly help me.
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
String driver = "com.mysql.jdbc.Driver";
con = null;
String username = "";
String password = "";
Class.forName("com.mysql.jdbc.Driver").newInstance();
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/dbName", "root", "password");
Statement st = con.createStatement();
ResultSet mar = st.executeQuery("SELECT * FROM table");
Gson gson = new GsonBuilder().create();
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
} catch (SQLException e) {
String message = e.getMessage();
}
What about this simple way?!
java.sql.Driver d=new com.mysql.jdbc.Driver();
I also wondered why do you connect to database with such this way?! It's better let server manage it.
First config the context.xml (if you are using tomcat) like this:
<context>
<Resource name="_ds" auth="Container" type="javax.sql.DataSource"
maxActive="128" maxIdle="32" username="_admin" password="qwerty" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://127.0.0.1:3306/dbname"/>
</context>
Then, simple get a connection from this resource in servlet/etc, like this:
public void init() {
try {
_ds = (DataSource) InitialContext.lookup("java:/comp/env/_ds");
} catch (Exception ex) {
}
}
private javax.sql.DataSource _ds;
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
try {
/*String driver = "com.mysql.jdbc.Driver";
con = null;
String username = "";
String password = "";
Class.forName("com.mysql.jdbc.Driver").newInstance();
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/dbName", "root", "password");*/
Connection con=_ds.getConnection();
Statement st = con.createStatement();
ResultSet mar = st.executeQuery("SELECT * FROM table");
Gson gson = new GsonBuilder().create();
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
con.close();
} catch (SQLException e) {
String message = e.getMessage();
}
By the way, don't forget to compy the MySQL JDBC driver jar-file in <CATALINA_BASE>/lib folder.
All you need is Class.forName("com.mysql.jdbc.Driver")
This acts like class loader and load your driver class for you. For that you need to add the corresponding jar file(which has the driver implementation). So download and add mysql-connector.jar in your class path.
Note : If you are using Java 7 then there is no need to even add the Class.forName("com.mysql.jdbc.Driver") statement.Automatic Resource Management (ARM) is added in JDBC 4.1 which comes by default in Java 7.
You might want to solve a bigger problem. You ought not enter configuration data such as database connection information directly in your servlet.
Are you using Tomcat? You can simply use JNDI. You will be able to change database details and drivers without having to recompile your servlet.
Here is the Tomcat 7.0 JNDI Datasource HOW-TO shows various ways in which you can get a Connection to your database.
On that page, you have a code example of how to get a Connection (Oracle 8i, 9i & 10g -> Part 3), and how to write a MySQL specific configuration.
Make sure to download a correct MySQL jar and place it in your Tomcat's lib/ directory (or alternatively your WAR's WEB-INF/lib).
You need to add mysqlconnector.jar file found here: ( http://dev.mysql.com/downloads/connector/j/ ) into your lib folder of your project. Include it with your project and then you can access your connection with database.
Add that jar into the buildpath.

How to run the servlet test by using HttpUnit servlet runner? Problems in Starting up with ServletUnit?

I was planning to unit test my Servlet through ServletUnit and ran across some problems :
- As a starting point, we are supposed to create a ServletRunner object. One of the constructors expects File object with web.xml file. I provide the full path of my web.xml file but somehow it ignores the path provided and searches at the top level folder. The code-snippet and error message is below:
Code Snippet
ServletRunner sr = new ServletRunner(new File("* C:/eclipse-workspaces/pocs/lms-csd/src/main/webapp/WEB-INF/web.xml*"));
ServletUnitClient sc = sr.newClient();
WebRequest request = new PostMethodWebRequest("path to be specified" ); request.setParameter( "userId", "test" );
request.setParameter( "password", "csd" );
WebResponse response = sc.getResponse(request);
String text = response.getText();
Assert.assertTrue(text.contains("Welcome to Leave Management System"));
stack trace
com.meterware.httpunit.HttpInternalErrorException:
Error on HTTP request: 500 org.apache.jasper.JasperException: java.io.FileNotFoundException: * C:\eclipse-workspaces\pocs\lms-csd\WEB-INF\web.xml*
(The system cannot find the path specified)
[http://localhost/login] - Why does the system keep on looking at the folder structure to be .../WEB-INF/web.xml.
Mine is a maven project and I would not like to change the structure of the project to adapt this way. How can I make ServletRunner class to read from a specified folder ? - In the Servlet code,
I use the following code :
String result = null if (someCondition) result = "/welcome.jsp"; } else { logger.warn("Password Validation failed"); request.setAttribute("failedlogin", new Boolean(true)); result = "/index.jsp"; } } RequestDispatcher requestDispatcher = getServletContext().getRequestDispatcher(result); requestDispatcher.forward(request, response);
Again ServletUnit expects welcome.jsp to be at root foler, though jsp files are present at .../src/main/webapp/ folder. Again how can ServletUnit be told about the target folder location ?
Many thanks in advance.
Best Regards
M.SuriNaidu
This is the sort of thing I do. This is a facsimile of the base class of my servlet tests. In this case I pass the relative path of the web.xml file as it exists in my source tree. I run these tests from ant and eclipse.
abstract public class ServletTestCase {
protected ServletRunner m_runner;
protected ServletUnitClient m_client;
protected String m_userAgent = "something/1.0";
#Override
protected void setUp() throws Exception {
super.setUp();
initHttpUnit();
}
#Override
protected void tearDown() throws Exception {
shutdownHttpUnit();
super.tearDown();
}
protected void initHttpUnit() throws IOException, SAXException {
shutdownHttpUnit();
// We are expecting UTF-8 character handling in URLs, make it the default
HttpUnitOptions.setDefaultCharacterSet("UTF-8");
// Find the servlet's web.xml file and use it to init servletunit
File file = new File("tests/web.xml"));
m_runner = new ServletRunner(file);
m_client = m_runner.newClient();
m_client.getClientProperties().setUserAgent(m_userAgent);
}
protected void shutdownHttpUnit() {
if (m_runner != null) {
m_runner.shutDown();
}
m_client = null;
m_runner = null;
}
}

Java class not found errors while running

I have a class that is having some dependency problems referencing external library files. Every time I try to run this on the server I get errors saying class not found, such as this:
SEVERE: Class [ org/json/JSONException ] not found. Error while loading [ class com.myproj.logic.Driver ]
this is preventing the class from executing. I tried taking out the specific throws execption by just saying "throws exception" and got the following error:
WARNING: A system exception occurred during an invocation on EJB Driver method public void com..logic.Driver.initURL() throws java.lang.Exception
javax.ejb.EJBException: javax.ejb.CreateException: Initialization failed for Singleton Driver
Caused by: java.lang.ClassNotFoundException: org.apache.commons.io.IOUtils
#Singleton
public class Driver {
#EJB RSSbean rssbean;
#PostConstruct
#Schedule(hour ="*/1", minute ="*/1", second ="*/1", persistent = false)
public void initURL() throws IOException, JSONException{
URL twitterSource = new URL("http://search.twitter.com/search.json?q=news");
ByteArrayOutputStream urlOutputStream = new ByteArrayOutputStream();
IOUtils.copy(twitterSource.openStream(), urlOutputStream);
String urlContents = urlOutputStream.toString();
JSONObject thisobject = new JSONObject(urlContents);
JSONArray names = thisobject.names();
JSONArray asArray = thisobject.toJSONArray(names);
JSONArray resultsArray = thisobject.getJSONArray("results");
JSONObject jsonObject = resultsArray.getJSONObject(0);
String twitterText = jsonObject.getString("text");
//System.out.println(twitterText);
System.out.println("Calling rssbean from Driver");
rssbean.updateDatabase("twitterText");
}
}
I have edited the Java classpath and added a user library for each of these as well as editing the Build Path of the project. The libraries are displayed in the list and I don't get compiler errors so at least Eclipse has recognized them. The problem comes during execution so I think something is wrong there.
Should I edit the classpath in Windows>Preferences>Java>Classpath> and add the Jars there? I have not had to do this for any other libraries before.
I found out you have to add any library files in the Glassfish/domain/lib directory before they're recognized by glassfish on the server.

Categories

Resources