You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ibatis.apache.org by cb...@apache.org on 2007/02/11 05:33:00 UTC

svn commit: r505832 - in /ibatis/trunk/java/mapper/mapper2: build/ src/com/ibatis/common/beans/ src/com/ibatis/common/jdbc/ src/com/ibatis/common/resources/ src/com/ibatis/sqlmap/engine/builder/xml/ src/com/ibatis/sqlmap/engine/mapping/parameter/ test/...

Author: cbegin
Date: Sat Feb 10 20:32:59 2007
New Revision: 505832

URL: http://svn.apache.org/viewvc?view=rev&rev=505832
Log:
1) Implemented private constructor access.
2) Centralized all calls to Class.newInstance() within ClassInfo 

Added:
    ibatis/trunk/java/mapper/mapper2/test/testdomain/PrivateAccount.java
Modified:
    ibatis/trunk/java/mapper/mapper2/build/version.properties
    ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/ClassInfo.java
    ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/jdbc/ScriptRunner.java
    ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/resources/Resources.java
    ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/SqlMapConfigParser.java
    ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/SqlMapParser.java
    ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapping/parameter/InlineParameterMapParser.java
    ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/BaseSqlMapTest.java
    ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/DirectFieldMappingTest.java
    ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/maps/Account.xml

Modified: ibatis/trunk/java/mapper/mapper2/build/version.properties
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/build/version.properties?view=diff&rev=505832&r1=505831&r2=505832
==============================================================================
--- ibatis/trunk/java/mapper/mapper2/build/version.properties (original)
+++ ibatis/trunk/java/mapper/mapper2/build/version.properties Sat Feb 10 20:32:59 2007
@@ -1,5 +1,5 @@
 #Build version info
-#Fri Feb 09 00:34:05 MST 2007
+#Sat Feb 10 18:39:04 MST 2007
 version=2.3.1
-buildDate=2007/02/09 00\:34
-buildNum=680
+buildDate=2007/02/10 18\:39
+buildNum=681

Modified: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/ClassInfo.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/ClassInfo.java?view=diff&rev=505832&r1=505831&r2=505832
==============================================================================
--- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/ClassInfo.java (original)
+++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/beans/ClassInfo.java Sat Feb 10 20:32:59 2007
@@ -43,6 +43,7 @@
   private HashMap getMethods = new HashMap();
   private HashMap setTypes = new HashMap();
   private HashMap getTypes = new HashMap();
+  private Constructor defaultConstructor;
 
   static {
     SIMPLE_TYPE_SET.add(String.class);
@@ -76,20 +77,49 @@
 
   private ClassInfo(Class clazz) {
     className = clazz.getName();
+    addDefaultConstructor(clazz);
     addMethods(clazz);
     addFields (clazz);
     readablePropertyNames = (String[]) getMethods.keySet().toArray(new String[getMethods.keySet().size()]);
     writeablePropertyNames = (String[]) setMethods.keySet().toArray(new String[setMethods.keySet().size()]);
   }
 
+  private void addDefaultConstructor(Class clazz) {
+    Constructor[] consts = clazz.getDeclaredConstructors();
+    for (int i = 0; i < consts.length; i++) {
+      Constructor constructor = consts[i];
+      if (constructor.getParameterTypes().length == 0) {
+        if (canAccessPrivateMethods()) {
+          try {
+            constructor.setAccessible(true);
+          } catch (Exception e) {
+            // Ignored. This is only a final precaution, nothing we can do.
+          }
+        }
+        if (constructor.isAccessible()) {
+          this.defaultConstructor = constructor;
+        }
+      }
+    }
+  }
+
   private void addFields(Class clazz) {
     Field[] fields = clazz.getDeclaredFields();
     for (int i=0; i < fields.length; i++) {
-      fields[i].setAccessible(true);
-      setMethods.put("(" + fields[i].getName() + ")", new SetFieldInvoker(fields[i]));
-      setTypes.put("(" + fields[i].getName() + ")", fields[i].getType());
-      getMethods.put("(" + fields[i].getName() + ")", new GetFieldInvoker(fields[i]));
-      getTypes.put("(" + fields[i].getName() + ")", fields[i].getType());
+      Field field = fields[i];
+      if (canAccessPrivateMethods()) {
+        try {
+          field.setAccessible(true);
+        } catch (Exception e) {
+          // Ignored. This is only a final precaution, nothing we can do.
+        }
+      }
+      if (field.isAccessible()) {
+        setMethods.put("(" + field.getName() + ")", new SetFieldInvoker(field));
+        setTypes.put("(" + field.getName() + ")", field.getType());
+        getMethods.put("(" + field.getName() + ")", new GetFieldInvoker(field));
+        getTypes.put("(" + field.getName() + ")", field.getType());
+      }
     }
     if (clazz.getSuperclass() != null) {
       addFields(clazz.getSuperclass());
@@ -99,29 +129,30 @@
   private void addMethods(Class cls) {
     Method[] methods = getAllMethodsForClass(cls);
     for (int i = 0; i < methods.length; i++) {
-      String name = methods[i].getName();
+      Method method = methods[i];
+      String name = method.getName();
       if (name.startsWith("set") && name.length() > 3) {
-        if (methods[i].getParameterTypes().length == 1) {
+        if (method.getParameterTypes().length == 1) {
           name = dropCase(name);
           if (setMethods.containsKey(name)) {
             // TODO(JGB) - this should probably be a RuntimeException at some point???
             log.error("Illegal overloaded setter method for property " + name + " in class " + cls.getName() +
                 ".  This breaks the JavaBeans specification and can cause unpredicatble results.");
           }
-          setMethods.put(name, new MethodInvoker(methods[i]));
-          setTypes.put(name, methods[i].getParameterTypes()[0]);
+          setMethods.put(name, new MethodInvoker(method));
+          setTypes.put(name, method.getParameterTypes()[0]);
         }
       } else if (name.startsWith("get") && name.length() > 3) {
-        if (methods[i].getParameterTypes().length == 0) {
+        if (method.getParameterTypes().length == 0) {
           name = dropCase(name);
-          getMethods.put(name, new MethodInvoker(methods[i]));
-          getTypes.put(name, methods[i].getReturnType());
+          getMethods.put(name, new MethodInvoker(method));
+          getTypes.put(name, method.getReturnType());
         }
       } else if (name.startsWith("is") && name.length() > 2) {
-        if (methods[i].getParameterTypes().length == 0) {
+        if (method.getParameterTypes().length == 0) {
           name = dropCase(name);
-          getMethods.put(name, new MethodInvoker(methods[i]));
-          getTypes.put(name, methods[i].getReturnType());
+          getMethods.put(name, new MethodInvoker(method));
+          getTypes.put(name, method.getReturnType());
         }
       }
       name = null;
@@ -147,8 +178,8 @@
    * We use this method, instead of the simpler Class.getMethods(),
    * because we want to look for private methods as well. 
    * 
-   * @param cls
-   * @return
+   * @param cls The class
+   * @return An array containing all methods in this class
    */
   private Method[] getClassMethods(Class cls) {
     HashMap uniqueMethods = new HashMap();
@@ -209,17 +240,6 @@
     return sb.toString();
   }
 
-  private boolean canAccessPrivateMethods() {
-    try {
-      System.getSecurityManager().checkPermission(new ReflectPermission("suppressAccessChecks"));
-      return true;
-    } catch (SecurityException e) {
-      return false;
-    } catch (NullPointerException e) {
-      return true;
-    }
-  }
-
   private static String dropCase(String name) {
     if (name.startsWith("is")) {
       name = name.substring(2);
@@ -236,6 +256,19 @@
     return name;
   }
 
+  private static boolean canAccessPrivateMethods() {
+    try {
+      System.getSecurityManager().checkPermission(new ReflectPermission("suppressAccessChecks"));
+      return true;
+    } catch (SecurityException e) {
+      return false;
+    } catch (NullPointerException e) {
+      return true;
+    } catch (Exception e) {
+      return false;
+    }
+  }
+
   /**
    * Gets the name of the class the instance provides information for
    *
@@ -245,6 +278,18 @@
     return className;
   }
 
+  public Object instantiateClass() {
+    if (defaultConstructor != null) {
+      try {
+        return defaultConstructor.newInstance(null);
+      } catch (Exception e) {
+        throw new RuntimeException("Error instantiating class. Cause: " + e, e);
+      }
+    } else {
+      throw new RuntimeException ("Error instantiating class.  There is no default constructor for class " + className);
+    }
+  }
+
   /**
    * Gets the setter for a property as a Method object
    *
@@ -394,12 +439,12 @@
   public static ClassInfo getInstance(Class clazz) {
     if (cacheEnabled) {
       synchronized (clazz) {
-        ClassInfo cache = (ClassInfo) CLASS_INFO_MAP.get(clazz);
-        if (cache == null) {
-          cache = new ClassInfo(clazz);
-          CLASS_INFO_MAP.put(clazz, cache);
+        ClassInfo cached = (ClassInfo) CLASS_INFO_MAP.get(clazz);
+        if (cached == null) {
+          cached = new ClassInfo(clazz);
+          CLASS_INFO_MAP.put(clazz, cached);
         }
-        return cache;
+        return cached;
       }
     } else {
       return new ClassInfo(clazz);

Modified: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/jdbc/ScriptRunner.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/jdbc/ScriptRunner.java?view=diff&rev=505832&r1=505831&r2=505832
==============================================================================
--- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/jdbc/ScriptRunner.java (original)
+++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/jdbc/ScriptRunner.java Sat Feb 10 20:32:59 2007
@@ -88,7 +88,7 @@
   public void runScript(Reader reader) throws IOException, SQLException{
     try {
       if (connection == null) {
-        DriverManager.registerDriver((Driver) Resources.classForName(driver).newInstance());
+        DriverManager.registerDriver((Driver) Resources.instantiate(driver));
         Connection conn = DriverManager.getConnection(url, username, password);
         try {
           if (conn.getAutoCommit() != autoCommit) {

Modified: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/resources/Resources.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/resources/Resources.java?view=diff&rev=505832&r1=505831&r2=505832
==============================================================================
--- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/resources/Resources.java (original)
+++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/common/resources/Resources.java Sat Feb 10 20:32:59 2007
@@ -15,6 +15,8 @@
  */
 package com.ibatis.common.resources;
 
+import com.ibatis.common.beans.ClassInfo;
+
 import java.io.*;
 import java.net.URL;
 import java.net.URLConnection;
@@ -289,9 +291,16 @@
    * @throws InstantiationException If the class cannot be instantiaed
    * @throws IllegalAccessException If the class is not public, or other access problems arise
    */
-  public static Object instantiate(Class clazz)
-      throws InstantiationException, IllegalAccessException {
-    return clazz.newInstance();
+  public static Object instantiate(Class clazz) throws InstantiationException, IllegalAccessException {
+    try {
+      return ClassInfo.getInstance(clazz).instantiateClass();
+    } catch (Exception e) {
+      // Try alternative...theoretically should fail for the exact same
+      // reason, but in case of a weird security manager, this will help
+      // some cases.
+      //return clazz.newInstance();
+      return clazz.newInstance();
+    }
   }
 
   private static ClassLoader getClassLoader() {

Modified: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/SqlMapConfigParser.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/SqlMapConfigParser.java?view=diff&rev=505832&r1=505831&r2=505832
==============================================================================
--- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/SqlMapConfigParser.java (original)
+++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/SqlMapConfigParser.java Sat Feb 10 20:32:59 2007
@@ -261,7 +261,7 @@
           vars.errorCtx.setMoreInfo("Check the callback attribute '" + callback + "' (must be a classname).");
 
           TypeHandler typeHandler;
-          Object impl = Resources.classForName(callback).newInstance();
+          Object impl = Resources.instantiate(callback);
           if (impl instanceof TypeHandlerCallback) {
             typeHandler = new CustomTypeHandler((TypeHandlerCallback) impl);
           } else if (impl instanceof TypeHandler) {

Modified: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/SqlMapParser.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/SqlMapParser.java?view=diff&rev=505832&r1=505831&r2=505832
==============================================================================
--- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/SqlMapParser.java (original)
+++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/SqlMapParser.java Sat Feb 10 20:32:59 2007
@@ -268,7 +268,7 @@
         if (callback != null) {
           vars.errorCtx.setMoreInfo("Check the parameter mapping typeHandler attribute '" + callback + "' (must be a TypeHandler or TypeHandlerCallback implementation).");
           try {
-            Object impl = Resources.classForName(callback).newInstance();
+            Object impl = Resources.instantiate(callback);
             if (impl instanceof TypeHandlerCallback) {
               handler = new CustomTypeHandler((TypeHandlerCallback) impl);
             } else if (impl instanceof TypeHandler) {
@@ -434,7 +434,7 @@
         if (callback != null) {
           vars.errorCtx.setMoreInfo("Check the result mapping typeHandler attribute '" + callback + "' (must be a TypeHandler or TypeHandlerCallback implementation).");
           try {
-            Object impl = Resources.classForName(callback).newInstance();
+            Object impl = Resources.instantiate(callback);
             if (impl instanceof TypeHandlerCallback) {
               handler = new CustomTypeHandler((TypeHandlerCallback) impl);
             } else if (impl instanceof TypeHandler) {
@@ -512,7 +512,7 @@
         if (callback != null) {
           vars.errorCtx.setMoreInfo("Check the result mapping typeHandler attribute '" + callback + "' (must be a TypeHandlerCallback implementation).");
           try {
-            Object impl = Resources.classForName(callback).newInstance();
+            Object impl = Resources.instantiate(callback);
             if (impl instanceof TypeHandlerCallback) {
               handler = new CustomTypeHandler((TypeHandlerCallback) impl);
             } else if (impl instanceof TypeHandler) {

Modified: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapping/parameter/InlineParameterMapParser.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapping/parameter/InlineParameterMapParser.java?view=diff&rev=505832&r1=505831&r2=505832
==============================================================================
--- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapping/parameter/InlineParameterMapParser.java (original)
+++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapping/parameter/InlineParameterMapParser.java Sat Feb 10 20:32:59 2007
@@ -101,7 +101,7 @@
         } else if ("handler".equals(field)) {
           try {
             value = typeHandlerFactory.resolveAlias(value);
-            Object impl = Resources.classForName(value).newInstance();
+            Object impl = Resources.instantiate(value);
             if (impl instanceof TypeHandlerCallback) {
               mapping.setTypeHandler(new CustomTypeHandler((TypeHandlerCallback) impl));
             } else if (impl instanceof TypeHandler) {

Modified: ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/BaseSqlMapTest.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/BaseSqlMapTest.java?view=diff&rev=505832&r1=505831&r2=505832
==============================================================================
--- ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/BaseSqlMapTest.java (original)
+++ ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/BaseSqlMapTest.java Sat Feb 10 20:32:59 2007
@@ -7,6 +7,7 @@
 import junit.framework.TestCase;
 import testdomain.Account;
 import testdomain.Order;
+import testdomain.PrivateAccount;
 
 import javax.sql.DataSource;
 import java.io.Reader;
@@ -75,7 +76,14 @@
     assertEquals("Begin", account.getLastName());
     assertNull(account.getEmailAddress());
   }
-  
+
+  protected void assertPrivateAccount6(PrivateAccount account) {
+    assertEquals(6, account.getId());
+    assertEquals("Jennifer", account.getFirstName());
+    assertEquals("Begin", account.getLastName());
+    assertNull(account.getEmailAddress());
+  }
+
   protected void assertAccount1(Map account) {
     Integer id = (Integer) account.get("id");
     String firstName = (String) account.get("firstName");

Modified: ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/DirectFieldMappingTest.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/DirectFieldMappingTest.java?view=diff&rev=505832&r1=505831&r2=505832
==============================================================================
--- ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/DirectFieldMappingTest.java (original)
+++ ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/DirectFieldMappingTest.java Sat Feb 10 20:32:59 2007
@@ -1,6 +1,7 @@
 package com.ibatis.sqlmap;
 
 import testdomain.Account;
+import testdomain.PrivateAccount;
 
 import java.sql.SQLException;
 
@@ -14,7 +15,7 @@
   public void testInsertAndSelectDirectToFields() throws SQLException {
     Account account = newAccount6();
 
-    sqlMap.update("insertAccountFromFields", account);
+    sqlMap.insert("insertAccountFromFields", account);
 
     account = (Account) sqlMap.queryForObject("getAccountToFields", new Integer(6));
 
@@ -22,5 +23,15 @@
     assertAccount6(account.getAccount());
   }
   
+  public void testGetAccountWithPrivateConstructor() throws SQLException {
+    Account account = newAccount6();
+
+    sqlMap.insert("insertAccountFromFields", account);
+
+    PrivateAccount pvt = (PrivateAccount) sqlMap.queryForObject("getAccountWithPrivateConstructor", new Integer(6));
+
+    assertPrivateAccount6(pvt);
+  }
+
 
 }

Modified: ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/maps/Account.xml
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/maps/Account.xml?view=diff&rev=505832&r1=505831&r2=505832
==============================================================================
--- ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/maps/Account.xml (original)
+++ ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/maps/Account.xml Sat Feb 10 20:32:59 2007
@@ -493,4 +493,20 @@
     where ACC_ID = #value#
   </select>
 
+  <select id="getAccountWithPrivateConstructor"
+    parameterClass="int"
+    resultClass="testdomain.PrivateAccount">
+    select
+      ACC_ID as "(id)",
+      ACC_FIRST_NAME as "(firstName)",
+      ACC_LAST_NAME as "(lastName)",
+      ACC_EMAIL as "(emailAddress)",
+      ACC_ID as "(account).(id)",
+      ACC_FIRST_NAME as "(account).(firstName)",
+      ACC_LAST_NAME as "(account).(lastName)",
+      ACC_EMAIL as "(account).(emailAddress)"
+    from ACCOUNT
+    where ACC_ID = #value#
+  </select>
+
 </sqlMap>

Added: ibatis/trunk/java/mapper/mapper2/test/testdomain/PrivateAccount.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/test/testdomain/PrivateAccount.java?view=auto&rev=505832
==============================================================================
--- ibatis/trunk/java/mapper/mapper2/test/testdomain/PrivateAccount.java (added)
+++ ibatis/trunk/java/mapper/mapper2/test/testdomain/PrivateAccount.java Sat Feb 10 20:32:59 2007
@@ -0,0 +1,124 @@
+package testdomain;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+public class PrivateAccount implements Serializable {
+
+  private int id;
+  private String firstName;
+  private String lastName;
+  private String emailAddress;
+  private int[] ids;
+  private int age;
+  private Date dateAdded;
+  private PrivateAccount account;
+  private List accountList;
+  private boolean bannerOption;
+  private boolean cartOption;
+
+  private PrivateAccount() {
+  }
+
+  public int getId() {
+    return id;
+  }
+
+  public void setId(int id) {
+    this.id = id;
+  }
+
+  public int[] getIds() {
+    return ids;
+  }
+
+  public void setIds(int[] ids) {
+    this.ids = ids;
+  }
+
+  /**
+   * @return Returns the age.
+   */
+  public int getAge() {
+    return age;
+  }
+
+  /**
+   * @param age The age to set.
+   */
+  public void setAge(int age) {
+    this.age = age;
+  }
+
+  /**
+   * @return Returns the dateAdded.
+   */
+  public Date getDateAdded() {
+    return dateAdded;
+  }
+
+  /**
+   * @param dateAdded The dateAdded to set.
+   */
+  public void setDateAdded(Date dateAdded) {
+    this.dateAdded = dateAdded;
+  }
+
+  public String getFirstName() {
+    return firstName;
+  }
+
+  public void setFirstName(String firstName) {
+    this.firstName = firstName;
+  }
+
+  public String getLastName() {
+    return lastName;
+  }
+
+  public void setLastName(String lastName) {
+    this.lastName = lastName;
+  }
+
+  public String getEmailAddress() {
+    return emailAddress;
+  }
+
+  public void setEmailAddress(String emailAddress) {
+    this.emailAddress = emailAddress;
+  }
+
+  public PrivateAccount getAccount() {
+    return account;
+  }
+
+  public void setAccount(PrivateAccount account) {
+    this.account = account;
+  }
+
+  public List getAccountList() {
+    return accountList;
+  }
+
+  public void setAccountList(List accountList) {
+    this.accountList = accountList;
+  }
+
+  public boolean isBannerOption() {
+    return bannerOption;
+  }
+
+  public void setBannerOption(boolean bannerOption) {
+    this.bannerOption = bannerOption;
+  }
+
+
+  public boolean isCartOption() {
+    return cartOption;
+  }
+
+  public void setCartOption(boolean cartOption) {
+    this.cartOption = cartOption;
+  }
+}