You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user-java@ibatis.apache.org by jaybytez <ja...@gmail.com> on 2006/08/19 02:44:42 UTC

jdbcType/javaType accessibility in TypeHandler

I created this JIRA issue based on the TypeHandler and wanted to know if
anyone is having this issue.  It started out as an ehancement request but is
turning into a larger issue.

https://issues.apache.org/jira/browse/IBATIS-332

The setParameter method in TypeHandler makes jdbcType available...I like
it...but am not totally sure why its available..because it is not available
in any of the getResult methods.  So, if I create a TypeHandler for my
DateTime object (that deals with java.sql.Date and java.sql.Timestamp), I
can run a PreparedStatement setDate or setTimestamp based on the jdbcType
passed into the setParameter method.  But the jdbcType is not passed into
the getResult, so I will not be able to know which get method to call
(getDate or getTimestamp).  If I call getTimestamp on a DATE type, I get an
Oracle error.  So now instead of defining a global handler for my DateTime
object, I have to create two handlers....one for java.sql.Date to my
DateTime and one for java.sql.Timestamp to my DateTime)  and I cannot
register them as global since you register them by the javaType (not
jdbcType as I have assumed).  So I have to set the typeHandler in each of my
sqlMaps in every instance I use Date or Timestamp.

It would be a significant increase of functionality and limit the amount of
TypeHandlers needed if each setParameter and getResults had access to the
javaType/jdbcType (and I don't know in the iBatis API if it does).  

Also, as my entry in JIRA explains, I could create a TypeHandler for a
superclass and use the iBatis configuration (sqlMap jdbcType) to help me
instantiate the correct version of the class in the TypeHandler.  Instead, I
have to create a multitude of TypeHandlers for my TypeSafeEnumeration
objects (one for each type because the superclass does not know which
instance to Cast the class to, but it would know this through the javaType).

I am trying to find out the best solutions and so far the only viable one is
to move away from global handlers and always make specific ones that deal
with one specialized Java Type and only one specialized Jdbc Type.

But for instance in a BooleanTypeHandler (where char 'T' is true, where
String "true" is true, and where int 1 is true), this may store a char as a
VARCHAR and a String as a VARCHAR and an int as a INTEGER.  This works fine
in the setParameter.  But you are in trouble in the getResults because you
don't have access to the jdbcType defined in the sqlMap to know which
ResultSet .getXXX method you should call.  There is a little more
flexibility when dealing with other SQL Types (outside of Date/Timestamp)
since you can call (in getResult) ResultSet's getString and return most
datatypes as a String.  


Any thoughts on this?  Is this available?

I am finally integrating iBatis into the framework and I just don't want
this to be one of the concerns or questionable parts of the architecture
that some developers think is too confusing or combersome...creating
multiple TypeHandlers.

Thanks so much for all your development!

jay
-- 
View this message in context: http://www.nabble.com/jdbcType-javaType-accessibility-in-TypeHandler-tf2130612.html#a5880443
Sent from the iBATIS - User - Java forum at Nabble.com.


Creating superclass TypeHandlers (jdbcType/javaType)

Posted by jaybytez <ja...@gmail.com>.
I wanted to see still if anyone had thoughts of the possibility for creating
typehandlers for a superclass and utilizing that typehandler for all
implementations of that superclass.

Anyone have examples of how they do that?  What I am trying to find out is
how that can be done without (jdbcType/javaType) to help instantiate the
specific instance?

You can read my Jira suggestion for more details.

Thanks,

jay
-- 
View this message in context: http://www.nabble.com/jdbcType-javaType-accessibility-in-TypeHandler-tf2130612.html#a5977367
Sent from the iBATIS - User - Java forum at Nabble.com.


Re: jdbcType/javaType accessibility in TypeHandler

Posted by jaybytez <ja...@gmail.com>.
Clintion,

Thanks for your response.  I have resolved the issue by just changing my
ResultSet getTimestamp/getDate to getObject since I can get the date string
just by calling toString on the getObject response.  The problem I was
having was not knowing whether I could call getTimestamp or getDate because
I did not have any information in the getResult methods (of TypeHandler). 
So I was making an assumption that getTimestamp would work for both sql
types Date/Timestamp.  But my code was erroring out.  So changing the
getDate/getTimestamp to getObject...I am able to extract the String from
getObject and parse it (using a format) into a DateTime object.  This
problem is resolved.

But I still cannot create TypeHandlers for (interfaces/abstract classes)
that can apply to the implementations of those classes.  So...like my Jira
entry...we have our own pre-JDK1.5 class called TypeSafeEnumeration to
represent our Enums.  We have to create an instance of this for each Enum we
use and therefore we have to create a handler for each instance.  If the
TypeHandler getResult method passed in the additional iBatis configuration
information like javaType, I could create one TypeHandler for the superclass
TypeSafeEnumeration and use the javaType parameter to cast returned Object
to the correct type.  

For example, this is what it could look like:

public class AbstractTypeSafeEnumerationTypeHandler implements
NewTypeHandler {

    /**
     * This method overrides the default setParameter method in TypeHandler.
     *
     * @param ps param
     * @param i param
     * @param parameter param
     * @param jdbcType param
     *
     * @throws SQLException can be thrown
     */
    public void setParameter(PreparedStatement ps, int i, Object parameter,
String jdbcType)
      throws SQLException {
        if(parameter == null) {
            JdbcType type =
(JdbcType)JdbcType.getTypeByDisplayValue(jdbcType, JdbcType.class);
            int sqlType = Integer.parseInt(type.getValue());
            ps.setNull(i, sqlType);
        }
        else {
            AbstractTypeSafeEnumeration enum =
(AbstractTypeSafeEnumeration)parameter;
            ps.setString(i, enum.getValue());
        }
    }

    private AbstractTypeSafeEnumeration getEnum(String value, String
javaType) {
        Class clazz = null;
        try {
            clazz = Class.forName(javaType);
        }
        catch (ClassNotFoundException e) {
            throw new RuntimeException("Invalid javaType - This class does
not exist: -> " + javaType, e);
        }
        return AbstractTypeSafeEnumeration.getTypeByValue(value, clazz);
    }
    
    /**
     * This method overrides the default getResult method in TypeHandler.
     *
     * @param rs param
     * @param columnName param
     *
     * @return returned
     *
     * @throws SQLException can be thrown
     */
    public Object getResult(ResultSet rs, String columnName, String
javaType)
      throws SQLException {
        String result = rs.getString(columnName);
        return this.getEnum(result, javaType);
    }

    /**
     * This method overrides the default getResult method in TypeHandler.
     *
     * @param rs param
     * @param columnIndex param
     *
     * @return returned
     *
     * @throws SQLException can be thrown
     */
    public Object getResult(ResultSet rs, int columnIndex, String javaType)
      throws SQLException {
        String result = rs.getString(columnIndex);
        return this.getEnum(result, javaType);
    }


    /**
     * This method overrides the default getResult method in TypeHandler.
     *
     * @param cs param
     * @param columnIndex param
     *
     * @return returned
     *
     * @throws SQLException can be thrown
     */
    public Object getResult(CallableStatement cs, int columnIndex, String
javaType)
      throws SQLException {
            String result = cs.getString(columnIndex);
            return this.getEnum(result, javaType);
    }


    /**
     * This method overrides the default equals method in TypeHandler.
     *
     * @param object param
     * @param dbVal param
     *
     * @return returned
     */
    public boolean equals(Object object, String dbVal) {
        return
StringHelper.equals(((AbstractTypeSafeEnumeration)object).getValue(),
dbVal);
    }


    /**
     * This method overrides the default valueOf method in TypeHandler.
     *
     * @param dbVal param
     *
     * @return returned
     */
    public Object valueOf(String dbVal) {
        return dbVal;
    }
} 


-- 
View this message in context: http://www.nabble.com/jdbcType-javaType-accessibility-in-TypeHandler-tf2130612.html#a5928370
Sent from the iBATIS - User - Java forum at Nabble.com.


Re: jdbcType/javaType accessibility in TypeHandler

Posted by Clinton Begin <cl...@gmail.com>.
Unfortunately this is largely by design.

I chose to anchor the TypeHandler first to the Java type, because that's
what the JDBC API relies on.  It's the required type.  The JDBC type is not
required by the JDBC API to retrieve data from a ResultSet, so I did not
build a dependency on it.

Now for the good news...hopefully:  You can implement actual TypeHandler
classes, not just TypeHandlerCallback classes, and register them the same
way.

org.apache.ibatis.type.TypeHandler.java

(That said, I'm not sure why you can't register them globally in
SqlMapConfig.xml....it should work the same way...)

Cheers,
Clinton

On 8/18/06, jaybytez <ja...@gmail.com> wrote:
>
>
> I created this JIRA issue based on the TypeHandler and wanted to know if
> anyone is having this issue.  It started out as an ehancement request but
> is
> turning into a larger issue.
>
> https://issues.apache.org/jira/browse/IBATIS-332
>
> The setParameter method in TypeHandler makes jdbcType available...I like
> it...but am not totally sure why its available..because it is not
> available
> in any of the getResult methods.  So, if I create a TypeHandler for my
> DateTime object (that deals with java.sql.Date and java.sql.Timestamp), I
> can run a PreparedStatement setDate or setTimestamp based on the jdbcType
> passed into the setParameter method.  But the jdbcType is not passed into
> the getResult, so I will not be able to know which get method to call
> (getDate or getTimestamp).  If I call getTimestamp on a DATE type, I get
> an
> Oracle error.  So now instead of defining a global handler for my DateTime
> object, I have to create two handlers....one for java.sql.Date to my
> DateTime and one for java.sql.Timestamp to my DateTime)  and I cannot
> register them as global since you register them by the javaType (not
> jdbcType as I have assumed).  So I have to set the typeHandler in each of
> my
> sqlMaps in every instance I use Date or Timestamp.
>
> It would be a significant increase of functionality and limit the amount
> of
> TypeHandlers needed if each setParameter and getResults had access to the
> javaType/jdbcType (and I don't know in the iBatis API if it does).
>
> Also, as my entry in JIRA explains, I could create a TypeHandler for a
> superclass and use the iBatis configuration (sqlMap jdbcType) to help me
> instantiate the correct version of the class in the TypeHandler.  Instead,
> I
> have to create a multitude of TypeHandlers for my TypeSafeEnumeration
> objects (one for each type because the superclass does not know which
> instance to Cast the class to, but it would know this through the
> javaType).
>
> I am trying to find out the best solutions and so far the only viable one
> is
> to move away from global handlers and always make specific ones that deal
> with one specialized Java Type and only one specialized Jdbc Type.
>
> But for instance in a BooleanTypeHandler (where char 'T' is true, where
> String "true" is true, and where int 1 is true), this may store a char as
> a
> VARCHAR and a String as a VARCHAR and an int as a INTEGER.  This works
> fine
> in the setParameter.  But you are in trouble in the getResults because you
> don't have access to the jdbcType defined in the sqlMap to know which
> ResultSet .getXXX method you should call.  There is a little more
> flexibility when dealing with other SQL Types (outside of Date/Timestamp)
> since you can call (in getResult) ResultSet's getString and return most
> datatypes as a String.
>
>
> Any thoughts on this?  Is this available?
>
> I am finally integrating iBatis into the framework and I just don't want
> this to be one of the concerns or questionable parts of the architecture
> that some developers think is too confusing or combersome...creating
> multiple TypeHandlers.
>
> Thanks so much for all your development!
>
> jay
> --
> View this message in context:
> http://www.nabble.com/jdbcType-javaType-accessibility-in-TypeHandler-tf2130612.html#a5880443
> Sent from the iBATIS - User - Java forum at Nabble.com.
>
>