Commons DbUtils
  1. Commons DbUtils
  2. DBUTILS-3

[dbutils] Setting bean properties fails silently

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: 1.1
    • Labels:
      None
    • Environment:

      Operating System: other
      Platform: Other

      Description

      I had a property in my bean that wasn't being set by BeanHandler. No matter
      the value of the matching field name in the database, the value in the bean
      would always come back as 0.

      I traced the culprit to BasicRowProcessor.callSetter(), which calls the
      setter method on the bean corresponding to the same field name in the
      database. Before it attempts to call the setter, it checks to make sure that
      the type of the value retrieved from the database is compatible with the type
      of the bean. This behavior is fair enough, but if the types are determined to
      be incompatible, DBUtils essentially fails silently. That is, it does not call
      the setter and it does nothing to inform the developer that this is what
      happened.

      This was frustrating for me because I had a field that was type int in my bean
      and type long in the database, but I didn't realize why it wasn't being set
      until I stepped through the code.

      POSSIBLE RESOLUTIONS
      --------------------
      1. Start a FAQ for DBUtils and mention that a bean's property will not be
      initialized if its type is incompatible with the corresponding field in the
      database

      2. Log some message to this effect when it occurs (I don't believe DBUtils has
      any logging, so this probably isn't viable)

      3. Throw an exception when this case occurs. Better that the program fail
      obviously and with some information about what happened rather than return a
      bean in an invalid state.

      1. patch-DBUTILS-3.txt
        0.7 kB
        Alan B. Canon

        Activity

        Hide
        Henri Yandell added a comment -

        Oops, bad on my part. Your patch for DBUTILS-32 included this fix and I applied that part of it without noticing.

        So this is resolved as a part of r470003.

        Show
        Henri Yandell added a comment - Oops, bad on my part. Your patch for DBUTILS-32 included this fix and I applied that part of it without noticing. So this is resolved as a part of r470003.
        Hide
        Alan B. Canon added a comment -

        I supplied a patch for DBUTILS-1 which also fixes the present issue. It would be best to apply the patch for DBUTILS-1, and not the patch submitted above.

        Show
        Alan B. Canon added a comment - I supplied a patch for DBUTILS-1 which also fixes the present issue. It would be best to apply the patch for DBUTILS-1 , and not the patch submitted above.
        Hide
        Alan B. Canon added a comment -

        Patch to resolve issue as described in previous comments.

        Show
        Alan B. Canon added a comment - Patch to resolve issue as described in previous comments.
        Hide
        Henri Yandell added a comment -

        Any chance of a patch file? Will make it easier if you're in the habit of supplying those sooner rather than later.

        'svn diff' can create them, as can the GUI svn tools (I presume).

        Show
        Henri Yandell added a comment - Any chance of a patch file? Will make it easier if you're in the habit of supplying those sooner rather than later. 'svn diff' can create them, as can the GUI svn tools (I presume).
        Hide
        Alan B. Canon added a comment -

        The above described behaviour of BeanProcessor.toBean() can be fixed by changing the implementation to the following:

        private void callSetter(Object target, PropertyDescriptor prop, Object value)
        throws SQLException {

        Method setter = prop.getWriteMethod();

        if (setter == null)

        { return; }

        Class[] params = setter.getParameterTypes();
        try {
        // Don't call setter if the value object isn't the right type
        if (this.isCompatibleType(value, params[0])) {
        setter.invoke(target, new Object[]

        { value }

        );
        } else

        { throw new SQLException( "Cannot set " + prop.getName() + ": incompatible types."); }

        } catch (IllegalArgumentException e)

        { throw new SQLException( "Cannot set " + prop.getName() + ": " + e.getMessage()); }

        catch (IllegalAccessException e)

        { throw new SQLException( "Cannot set " + prop.getName() + ": " + e.getMessage()); }

        catch (InvocationTargetException e)

        { throw new SQLException( "Cannot set " + prop.getName() + ": " + e.getMessage()); }

        }

        Show
        Alan B. Canon added a comment - The above described behaviour of BeanProcessor.toBean() can be fixed by changing the implementation to the following: private void callSetter(Object target, PropertyDescriptor prop, Object value) throws SQLException { Method setter = prop.getWriteMethod(); if (setter == null) { return; } Class[] params = setter.getParameterTypes(); try { // Don't call setter if the value object isn't the right type if (this.isCompatibleType(value, params [0] )) { setter.invoke(target, new Object[] { value } ); } else { throw new SQLException( "Cannot set " + prop.getName() + ": incompatible types."); } } catch (IllegalArgumentException e) { throw new SQLException( "Cannot set " + prop.getName() + ": " + e.getMessage()); } catch (IllegalAccessException e) { throw new SQLException( "Cannot set " + prop.getName() + ": " + e.getMessage()); } catch (InvocationTargetException e) { throw new SQLException( "Cannot set " + prop.getName() + ": " + e.getMessage()); } }
        Hide
        Emmanuel Bourg added a comment -

        The javadoc for the method BeanProcessor.toBean() states:

        "The column type can be converted to the property's set method parameter type
        with a ResultSet.get* method. If the conversion fails (ie. the property was an
        int and the column was a Timestamp) an SQLException is thrown."

        So I guess the right behavior in the case you mention would be to throw an
        exception.

        An alternative would be to try a conversion (long->int) and cast an exception
        only if it's not possible (because the value overflows).

        Show
        Emmanuel Bourg added a comment - The javadoc for the method BeanProcessor.toBean() states: "The column type can be converted to the property's set method parameter type with a ResultSet.get* method. If the conversion fails (ie. the property was an int and the column was a Timestamp) an SQLException is thrown." So I guess the right behavior in the case you mention would be to throw an exception. An alternative would be to try a conversion (long->int) and cast an exception only if it's not possible (because the value overflows).

          People

          • Assignee:
            Unassigned
            Reporter:
            Tim Bailen
          • Votes:
            1 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development