TLDR;
The JDBI @BindBean
annotation generates an IllegalAccessException
with AutoValue generated types because the generated types are package private and by default can't be accessed by default using reflection.
Is JDBI inflexible or is there a workaround via AutoValue? (Full questions below)
Quick Background
I'm attempting to use the JDBI @BindBean
annotation with a type whose source is generated using AutoValue.
package com.example;
@AutoValue
public abstract class Foo {
public String getBar();
}
The issue is that the generated code looks like:
package com.example;
@AutoValue
class AutoValue_Foo extends Foo {
private final String bar;
@Override
public String getBar() {
return this.bar;
}
// toString, equals, hashCode
}
Notice the class is package private!
Now if I attempt to use @BindBean
, for example:
@SqlQuery("select * from baz where bar = :foo.bar")
Condition find(@BindBean("foo") Foo foo);
Because AutoValue_Foo
is package private, and BindBeanFactory
uses reflection, if an attempt is made to call find
with an AutoValue_Foo
type, the result is:
java.lang.IllegalAccessException: ... can not access a member of class com.example.Foo with modifiers "public"
The relevant JDBI code is here. I understand from a Java reflection perspective, this could be resolved using setAccessible(true)
but that would require a PR to JDBI.
So the questions are as follow:
Is there a way to restructure my code where I can bind a Foo
of
type AutoValue_Foo
using @BindBean
without creating a new JDBI
mapper?
Is there a way to have @AutoValue
generate classes that are
public
. I understand why this would generally not be desirable
(push people to use the interface and not the implementation).
Is the BindBeanFactory
too inflexible? Should it utilize
setAccessible(true)
on methods that are otherwise available
outside of their originating package?
Version 2.71 of JDBI will include the ability to specify a type token to @BindBean
using the type
field. This type token will allow for specifying the type used to make the reflective call against the provided argument.
@SqlQuery("select * from baz where bar = :foo.bar")
Condition find(@BindBean(value="foo", type=Foo.class) Foo foo);
Using this technique you can eliminate the IllegalAccessException
described above.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With