Categories
discuss

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 …

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?

Answer

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.

Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..