Sunday 6 April 2014

Exception in thread "main" java.lang.UnsupportedOperationException: The user must supply a JDBC connection

I got this error when I tried to persist  a row in the student table. I was using SQL Server 2008 R2 and Hibernate.
Exception in thread "main" java.lang.UnsupportedOperationException: The user must supply a JDBC connection
My hibernate.cfg.xml file is as follows:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
 
   <property name="url">jdbc:sqlserver://MYSERVER:1433;databaseName=MYDB</property>
<property name="username">sa</property>
<property name="password">MYPASSWORD</property>
<property name="driverClassName">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>

<property name="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<property name="hibernate.generate_statictics">true</property>
<property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property>
<property name="hibernate.current_session_context_class">thread</property>
<property name="hibernate.hbm2ddl.auto">create</property>


<mapping class="Student" />
</session-factory>
</hibernate-configuration>

The root cause of this error is  the incorrectly specified property names. Actually I copied the property names from the bean which was used to initialize the data source in spring from some other project. And out of my negligence forgot to check the property names.

Finally I landed with the correct configuration:
 <property name="hibernate.connection.url">jdbc:sqlserver://AXIOM:1433;databaseName=S3H4</property>
<property name="hibernate.connection.username">sa</property>
<property name="hibernate.connection.password">123</property>
<property name="hibernate.connection.driverClassName">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>


Note that its also OK if you give just connection.url and so on instead of hibernate.connection.url

Saturday 5 April 2014

Cannot insert the value NULL into column 'stateNo', table 'S3H4.dbo.State'; column does not allow nulls. INSERT fails.

I got the following error when trying to persist the State entity using the code - session.persist(state);

Apr 05, 2014 2:25:50 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: Cannot insert the value NULL into column 'stateNo', table 'S3H4.dbo.State'; column does not allow nulls. INSERT fails.

I was auto-generating the primary key using the GeneratedValue annotations given below.
@Entity
@Table(name="STATE")
public class State {

@Id
@GeneratedValue
private int stateNo;
 //other properties and their getters and setters.
}

This strategy of auto-generating primary keys worked fine as long as I was using Oracle 11g. As soon as I moved to SQL Server 2008 R2. I got the error message mentioned in red above.

Solution
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
@Entity
@Table(name="STATE")
public class State {

@Id
@GeneratedValue(generator="stateNoGenerator")
@GenericGenerator(strategy="increment",name="stateNoGenerator")
@Column(name="STATENO",length=10)
private int stateNo;
//other properties and their getters and setters.
}

Adding the GenericGenerator annotation did the trick. Do  note that GenericGenerator is present within org.hibernate.annotations package and not within  javax.persistence package as one would normally expect.
Add the generator attribute in the GeneratedValue annotation specifying the name of the GenericGenerator.

The content of element type "session-factory" must match "(property*,mapping*,(class-cache|collection-cache)*,event*,listener*)".

I got this exception
The content of element type "session-factory" must match "(property*,mapping*,(class-cache|collection-cache)*,event*,listener*)".

This is my hibernate.cfg.xml file
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
<session-factory>
 
   <mapping class="Student" />
<property name="url">jdbc:sqlserver://MYSERVER:1433;databaseName=MYDB</property>
<property name="username">sa</property>
<property name="password">PASSWORD</property>
<property name="driverClassName">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>

<property name="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<property name="hibernate.generate_statictics">true</property>
<property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property>
<property name="hibernate.current_session_context_class">thread</property>
<property name="hibernate.hbm2ddl.auto">none</property>

</session-factory>
</hibernate-configuration>

This is the stack trace:
log4j:WARN No appenders could be found for logger (org.hibernate.cfg.annotations.Version).
log4j:WARN Please initialize the log4j system properly.
Exception in thread "main" org.hibernate.MappingException: invalid configuration
at org.hibernate.cfg.Configuration.doConfigure(Configuration.java:1484)
at org.hibernate.cfg.Configuration.configure(Configuration.java:1425)
at org.hibernate.cfg.Configuration.configure(Configuration.java:1411)
at SQLSERVERTEST.main(SQLSERVERTEST.java:23)
Caused by: org.xml.sax.SAXParseException; lineNumber: 32; columnNumber: 20; The content of element type "session-factory" must match "(property*,mapping*,(class-cache|collection-cache)*,event*,listener*)".
at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
at org.apache.xerces.util.ErrorHandlerWrapper.error(Unknown Source)
at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
at org.apache.xerces.impl.dtd.XMLDTDValidator.handleEndElement(Unknown Source)
at org.apache.xerces.impl.dtd.XMLDTDValidator.endElement(Unknown Source)
at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanEndElement(Unknown Source)
at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
at org.dom4j.io.SAXReader.read(SAXReader.java:465)
at org.hibernate.cfg.Configuration.doConfigure(Configuration.java:1481)
... 3 more

Solution
Rearrange the contents of the hibernate configuration file and place the mapping element after all the property elements.
Examination of the error message suggests that within session-factory element first only the property element can appear followed by mapping, class-cache or collection-cache, even and finally listeners. If this ordering is not maintained the above exception is thrown.
The correct hibernate.cfg.xml:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
   
        <property name="url">jdbc:sqlserver://MYSERVER:1433;databaseName=MYDB</property>
<property name="username">sa</property>
<property name="password">PASSWORD</property>
<property name="driverClassName">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
<property name="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<property name="hibernate.generate_statictics">true</property>
<property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property>
<property name="hibernate.current_session_context_class">thread</property>
<property name="hibernate.hbm2ddl.auto">none</property>

<mapping class="Student" />
</session-factory>
</hibernate-configuration>

Saturday 8 February 2014

Program to read code from a file and print it to the console ignoring the comments in it.

This question was asked to me in Java Interview in Rolta India Pvt. Ltd. I  want to share the logic and code with you.

The solution is simple.

  • Create a Java Application (say IO)
  • Create a file with name code.java in your application folder. Place it in the root folder of your application. Your folder structure will look like this. To find the location of root folder of your application right click your project in Eclipse, Select Properties,  Select Resources from the left pane of the windows that opens. Check the value of Location property that is where your application root is.











  • Create a class (say Main)
  • Copy paste the following code in it.

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class Main {

 public static void main(String[] args) {
  try {
   File file = new File("code.java");
   FileReader fileReader = new FileReader(file);

   // Print the file or count the number of characters
   int data = fileReader.read();
   int count = 0;
   while (data != -1) {
    count++;
    // System.out.print((char)data);
    data = fileReader.read();
   }
  
   char[] cbuf = new char[count];
   fileReader.close();
   // initialize fileReader to start of file
   fileReader = new FileReader(file);
   fileReader.read(cbuf);

   for (int i = 0; i < count; i++) {
    if (cbuf[i] == '/') {
     if (cbuf[i + 1] == '*') {// check for multiline comments
      i += 2;
      while (!(cbuf[i] == '*' && cbuf[i + 1] == '/')) {
       i++; // ignore
      }
      i += 2;// ignore */
     }

     if (cbuf[i + 1] == '/') {// check for single line comments
      i += 2;
      while (cbuf[i] != '\n') {
       i++;
      }// while
     }
    }// check for multiline comments

    // print
    System.out.print(cbuf[i]);
   }// for
   fileReader.close();
  } catch (FileNotFoundException e) {
   System.out.println(e.getMessage());
  } catch (IOException e) {
   System.out.println(e.getMessage());
  }
  /*
   * some 
   * multiline comments
   */
 }
}

  • Copy the same code in code.java file in root folder of your application. Save it.
  • This program will print the code in code.java while ignoring the comments.
  • Run the program. 
  • In our class we created a file object. Then wrapped a FileReader around it. Note that as we are working with characters we have used FileReader.
  • We need to create a char array into which we can read the contents of the file. But in java to initialize an array you need to know the size.
  • So we have used a while loop to count the number of characters in the file. Then we can use that info to initialize our char array.
  • The public int read() method of FileReader class returns -1 if end of file is reached else returns the data at current pointer position and advances the data to next character. After executing the below loop our pointer will be at the end of file. 

                        int count = 0;
   while (data != -1) {
    count++;
    // System.out.print((char)data);
    data = fileReader.read();
   }

  • To make things simple we can also use the public int length() method of the File class to give us the number of characters in it.
                          int count = file.length();
  • We used the public int read(char[] cbuf)  method to read the contents of the file into that char array cbuf. In the while loop above we traversed the entire file from start to end to count the number of characters. So we have re-initialized it to start of the file.
  • The for loop contains the logic to skip multiline and single line comments.
  • If encounter '/' we check if the next character is '*' ,if it is then we go on ignoring the file until we find '*' immediately followed by '/'.
  • If we encounter '/' we check if the next character is '/', if it is then we go in ignoring the entire line.
  • If find neither a single line nor a multiline comment we print the chaaracters of the array 1 by 1.
Thats it. Hope this helps. 
Signing off!!!!
Happy Learning :)

Sunday 12 January 2014


Using Annotations in Hibernate.

In order to be able to use the code provided in the tutorial you must have Oracle 11g installed on your local machine or at least have access to it somehow J. You must modify the properties
connection.url, connection.username, connection.password shown in step 3 to suit your database settings.

This will be the final folder structure for your application.


Step 1: Create a Java Application using eclipse. 
Click New, Java Project.



Give it a suitable name say “HibernateAnnotationPractise”. Click finish.


Step 2: Configure the build path.

You can download the jars from this link


Add the following jars to your build path.

To do that, right click you project, click Build Path, Configure Build Path.
Click on Libraries tab, Add External Jars and browse to the folder having all the jars


Step 3: Create the hibernate configuration xml file.
Right click on src folder, new, file. Give it the name hibernate.cfg.xml. click Finish


Add the following code to the xml.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
       <session-factory>
              <!-- Setup the database connection -->
              <property name="connection.url">jdbc:oracle:thin:@localhost:1521:oracle</property>
              <property name="connection.username">SYSTEM</property>
              <property name="connection.password">Oracle123</property>
              <property name="connection.driver">oracle.jdbc.OracleDriver</property>
              <property name="connection.pool_size">1</property>
             
              <!-- SQL dialect -->
              <property name="dialect">org.hibernate.dialect.OracleDialect</property>
             
              <!-- Show sql statements to the  stdout -->
              <property name="show_sql">true</property>
             
              <!-- Configure the cache provider -->
              <property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
             
              <!-- Generate the database DDL from hibernate configuration file -->
              <property name="hbm2ddl.auto">update</property>
              <!-- create = create the database and remove the existing schema if any -->
              <!-- update = update the database if the schema already exists. Throws exception if matching schema not found.  -->
              <!-- create-delete = create the database and drop the schema after the sessionFactory is closed. -->
              <!-- validate = validate the existing schema and no changes will be made to the database. -->
             
              <property name="hibernate.allow_sql_comments">true</property>
              <property name="hibernate.format_sql">false</property>
              <property name="hibernate.generate_statistics">true</property>
             
              <!-- Hibernate's automatic session context management -->
              <property name="current__session_context_class">thread</property>
             
              <!-- Classes to be mapped -->
              <mapping class="Employee"/>
       </session-factory>
</hibernate-configuration>

Note : I am using Oracle 11g. You will have to modify the connection.url, connection.username, connection.password properties as per your database configurations. You can use the code provided as a format for those properties.

Step 4: Add the file Employee.java, HibernateUtility.java and Client.java in your source package.

Employee.java

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedNativeQueries;
import javax.persistence.NamedNativeQuery;

@Entity
/*table will be created with name Employee. If you want to give some other name use the table annotation - @Table(name=”EMP1”)*/
public class Employee {

       @Id
       private int id;
       private String name;

       public int getId() {
              return id;
       }

       public void setId(int id) {
              this.id = id;
       }

       public String getName() {
              return name;
       }

       public void setName(String name) {
              this.name = name;
       }

}

HibernateUtility.java

import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;

public class HibernateUtility{
       private static final SessionFactory SESSION_FACTORY;
       static{
              SESSION_FACTORY = new AnnotationConfiguration().configure().buildSessionFactory();
       }
      
       public static SessionFactory getSessionFactory(){
              return SESSION_FACTORY;
       }
}

Client.Java

import java.util.Iterator;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

public class Client {
       public static void main(String[] args) {
              Employee e1 = new Employee();
              e1.setId(125);
              e1.setName("Satish");
               try {
                     Class.forName ("oracle.jdbc.OracleDriver");
              } catch (ClassNotFoundException e) {
                     // TODO Auto-generated catch block
                     e.printStackTrace();
              }
               
              SessionFactory sessionFactory = HibernateUtility.getSessionFactory();
              Session session = sessionFactory.openSession();
              Transaction transaction = session.beginTransaction();
             
             
session.persist(e1);
             
             
              transaction.commit();
              session.close();
       }
}

Run Client.java. Enjoy, your employee has been persisted to the database :)
In my next update I will post how to use NamedQuery and NamedNativeQuery annotations with hibernate.
All the best!!!