Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using JDBI @BindBean with AutoValue

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:

  1. 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?

  2. 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).

  3. Is the BindBeanFactory too inflexible? Should it utilize setAccessible(true) on methods that are otherwise available outside of their originating package?

like image 930
vpiTriumph Avatar asked Nov 30 '15 22:11

vpiTriumph


1 Answers

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.

like image 96
vpiTriumph Avatar answered Oct 21 '22 03:10

vpiTriumph