JDBI has issue binding complex Enum type argument

464 views
Skip to first unread message

Jia Zhou

unread,
Mar 26, 2019, 5:00:55 PM3/26/19
to jDBI
Hello, 

I encountered an issue when trying to use @Bind to bind an enum type argument in JDBI 2.78. Not sure if this is addressed in the newer version or not. 

In my DAO interface, I have a query method that binds to a enum Type.

    @SqlQuery("SELECT A FROM TABLE_A WHERE  ID = :id AND TYPE = :type")
    List<TableA> findTableA(@Bind("id") long id, @Bind("type") Type type);

Type is declared as a complex Enum (when I say complex, I mean the enum values are including their own methods)

public enum Type 
{    
    Bad
    {
        @Override
        public int getCode()
        {            
             return 0;
        }
    },
    Good
    {
        @Override
        public int getCode()
        {            
             return 1;
        }
    };

    public abstract int getCode();
}

This enum Type is also used in a java Bean class. We also have insert/update methods in the DAO that are using @BindBean annotation to persist to database. They work fine. But when we are trying to use @Bind to bind this Type as a single value the method fails. 

I debugged JDBI code and find out why this is not working. Basically, when using @Bind with an enum type, jdbi uses the actual argument object's class type to resolve to an ArgumentFactory. In this case, type.getClass(). JDBI do a test to see if it is enum type by calling Class.isEnum() method. For a complex enum type (which declare methods in enum value), the actual class type is an inner anonymous class (something like Typ$1) which is not an enum type. Thus isEnum call return false. (See https://bugs.java.com/bugdatabase/view_bug.do?bug_id=5020490https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6709903). Since the test returns false, JDBI doesn't recognize we are trying to bind an enum type, so it resolves to ObjectArgument to bind it which fails when try to set value to sql statement because it cannot resolve to the correct column type.
But when using @BindBean, jdbi uses reflection and use property getter method's return type as the type to resolve. This time the class is Type.class, and its call to isEnum return true. So this resolves to EnumArgument correctly.

It looks like to better test enum type, we will need to use reflection to find the declared type of a bind argument with @Bind annotation. Otherwise, we have to limit the use of @Bind for simple enum type only. 

Should I open a bug/feature request ticket?

Thanks.

Matthew Hall

unread,
Mar 26, 2019, 6:35:19 PM3/26/19
to jd...@googlegroups.com
A bug ticket or PR would be great.

This should not be difficult to resolve--we just have to check `Enum.class.isAssignableFrom(expectedType)` instead of calling `expectedType.isEnum()` directly.

-Matt

--
You received this message because you are subscribed to the Google Groups "jDBI" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jdbi+uns...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Matthew Hall

unread,
Mar 26, 2019, 6:39:58 PM3/26/19
to jd...@googlegroups.com
In the meantime, you could work around this issue by registering an ArgumentFactory with the improved enum check.

Or you could upgrade the Jdbi 3.x (currently 3.6.0) which does not have this problem (that I am aware of).

-Matt

Jia Zhou

unread,
Mar 26, 2019, 11:37:17 PM3/26/19
to jDBI
Thanks Matt. 

Enum.class.isAssignableFrom(expectedType) should resolve the issue. I'll add my own ArgumentFactory class and use this check to workaround this issue for now. We are using jdbi in Dropwizard. We are waiting Dropwizard to release the next version that supports Java 11. Dropwizard latest version already uses jdbi 3.x. So once we upgrade Dropwizard, we should be able to pick up the jdbi 3.x. I will report back if it works fine.

I also submitted a bug here.

Thanks,
Jia
Reply all
Reply to author
Forward
0 new messages