Tutorial :A very very strange error ClassCastException. PreparedStatement's setInt method



Question:

Can anybody tell me why is this method not working?

String strQuery = "Insert Into cust_subs (CustomerId,SubscriptionId) Values (?,?)";  PreparedStatement objPreparedStatement = Utils.getPreparedStatement(objConnection, strQuery);  objPreparedStatement.setInt(2, currentSubscriptions.get(0) );  

where currentSubscriptions is:

List<Integer> currentSubscriptions;  

I get this error even though it is Integer list:-

SEVERE: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer

Assume that connection object already exists. And i am very sure that currentSubscriptions is not null else i wouldn't have got this error. If instead of using List i hardcode like this:

objPreparedStatement.setInt(2,1);  

It works. I have even printed the values of List using System.out.println and it's perfectly fine. They are integers only. Don't know why is it treating them as Strings. I have even tried Integer.parseInt on list's item. Still it gives me the same error. This is one of the funniest errors I have ever faced.

Thanks in advance :)

EDIT :-

Atleast this should work. But even this is not working :-

  int intSubscriptionId = Integer.parseInt( currentSubscriptions.get(0).toString());                objPreparedStatement.setInt(2, intSubscriptionId );  

EDIT 2:

Posting whole code :-

package beans;    import entities.Customer;  import entities.Subscription;  import java.io.IOException;  import java.io.Serializable;  import java.sql.Connection;  import java.sql.PreparedStatement;  import java.sql.ResultSet;  import java.sql.SQLException;  import java.sql.Savepoint;  import java.util.ArrayList;  import java.util.List;  import javax.faces.bean.ManagedBean;  import javax.faces.bean.ViewScoped;  import javax.faces.context.FacesContext;  import javax.servlet.http.HttpServletRequest;  import misc.Utils;    @ManagedBean  @ViewScoped  public class AddSubscriptionBean implements Serializable {        private Customer customer;      private List<Integer> currentSubscriptions;      private List<Subscription> subscriptionList;        public List<Subscription> getSubscriptionList() {          return subscriptionList;      }        public void setSubscriptionList(List<Subscription> subscriptionList) {          this.subscriptionList = subscriptionList;      }        public List<Integer> getCurrentSubscriptions() {          return currentSubscriptions;      }        public void setCurrentSubscriptions(List<Integer> currentSubscriptions) {          this.currentSubscriptions = currentSubscriptions;      }        public Customer getCustomer() {          return customer;      }        public void setCustomer(Customer customer) {          this.customer = customer;      }        /** Creates a new instance of AddSubscriptionBean */      public AddSubscriptionBean() throws IOException, SQLException {            Connection objConnection = null;          try {              HttpServletRequest objHttpServletRequest = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();              int intCustomerId = Integer.parseInt(objHttpServletRequest.getParameter("cid"));              String strQuery = "Select * from customer Where CustomerID = " + intCustomerId;                ResultSet objResultSet = Utils.executeResultSet(objConnection, strQuery);              if (objResultSet.next()) {                  String strFirstName = objResultSet.getString("FirstName");                  String strLastName = objResultSet.getString("LastName");                  customer = new Customer(intCustomerId, strFirstName, strLastName);              }                currentSubscriptions = new ArrayList<Integer>();                for (Subscription objSubscription : customer.getSubscriptionList()) {                  currentSubscriptions.add(objSubscription.getSubscriptionId());              }                  subscriptionList = new ArrayList<Subscription>();              strQuery = "Select * from subscription";              objResultSet = Utils.executeResultSet(objConnection, strQuery);              while (objResultSet.next()) {                  int intSubscriptionId = objResultSet.getInt("SubscriptionId");                  String strSubsriptionTitle = objResultSet.getString("Title");                  String strSubsriptionType = objResultSet.getString("Type");                  Subscription objSubscription = new Subscription(intSubscriptionId, strSubsriptionTitle, strSubsriptionType);                  subscriptionList.add(objSubscription);              }              } catch (Exception ex) {              ex.printStackTrace();              FacesContext.getCurrentInstance().getExternalContext().redirect("index.jsf");          } finally {              if (objConnection != null) {                  objConnection.close();              }          }      }        public void save() throws SQLException {            Connection objConnection = null;          Savepoint objSavepoint = null;          try {              objConnection = Utils.getConnection();              objConnection.setAutoCommit(false);              objSavepoint = objConnection.setSavepoint();              String strQuery = "Delete From cust_subs Where CustomerId = " + customer.getCustomerId();                if (!Utils.executeQuery(objConnection, strQuery)) {                  throw new Exception();              }                strQuery = "Insert Into cust_subs (CustomerId,SubscriptionId) Values (?,?)";                  int intCustomerId = customer.getCustomerId();              PreparedStatement objPreparedStatement = Utils.getPreparedStatement(objConnection, strQuery);              for (int intIndex = 0; intIndex < currentSubscriptions.size(); intIndex++) {                  objPreparedStatement.setInt(1, intCustomerId);                  int intSubscriptionId = Integer.parseInt( currentSubscriptions.get(0).toString());                    objPreparedStatement.setInt(2, intSubscriptionId );                  objPreparedStatement.addBatch();              }                objPreparedStatement.executeBatch();                objConnection.commit();          } catch (Exception ex) {              ex.printStackTrace();              if (objConnection != null) {                  objConnection.rollback(objSavepoint);              }          } finally {              if (objConnection != null) {                  objConnection.close();              }          }      }  }  

This is my JSF page :-

<?xml version='1.0' encoding='UTF-8' ?>  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  <html xmlns="http://www.w3.org/1999/xhtml"        xmlns:h="http://java.sun.com/jsf/html"        xmlns:f="http://java.sun.com/jsf/core"        xmlns:msc="http://mscit/jsf">      <h:head>          <title>Facelet Title</title>      </h:head>      <h:body>          <center>              <h:form>              <h1>Add Subscription</h1>                <b> Customer Name :</b> <h:outputText value="#{addSubscriptionBean.customer.firstName} #{addSubscriptionBean.customer.lastName}"/>                <h:selectManyCheckbox value="#{addSubscriptionBean.currentSubscriptions}">                    <f:selectItems value="#{addSubscriptionBean.subscriptionList}" var="row" itemLabel="#{row.title}" itemValue="#{row.subscriptionId}" />                </h:selectManyCheckbox>                <h:commandButton value="Save" actionListener="#{addSubscriptionBean.save}"/>              </h:form>          </center>      </h:body>  </html>  

Please look at the h:selectManyCheckbox of JSF. JSF internally passes all the checkboxes that i have checked to my List. I think JSF is converting my integer list to string.


Solution:1

You need to instruct h:selectManyCheckbox to convert the values to Integer by specifying javax.faces.Integer as converter. Generic types are namely unknown in EL and it treats the parameters by default as String.

<h:selectManyCheckbox converter="javax.faces.Integer">  

No need to use List<String> instead which would only lead to more weaktype clutter in the bean.


Solution:2

It's possible to put Strings into a List<Integer> if you use unsafe operations:

List<Integer> intList = new ArrayList<Integer>();  List list = intList;  list.add("1");  

intList and list hold references to the same list, which now contains a string. As you've seen, you get a ClassCastException upon trying to extract the element from intList.

Java generics work using hidden casting, and you can defeat the type-checking. To test this, assign to a List, then print the class of every element:

List currentSubscriptionsUnsafe = currentSubscriptions;  for(Object o : currentSubscriptionsUnsafe)  {    System.out.println(o.getClass());  }  

EDIT: I'm not familiar with JSF, but I think your guess is correct. One solution is to make currentSubscriptions a List<String> everywhere (which JSF seems to expect). Then, get(0) will return a String, which you can parse into an Integer. There may be a cleaner method, but this should work.


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »