Using JDBI #BindBean with AutoValue - java

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.

Related

ByteBuddy: newly defined fields not visible through reflection

I use ByteBuddy in an Agent to add a tracking variable to each Runnable in a test program:
new AgentBuilder.Default()
.with(AgentBuilder.LambdaInstrumentationStrategy.ENABLED)
.type(ElementMatchers.isSubTypeOf(Runnable.class)
.and(ElementMatchers.not(ElementMatchers.isInterface())))
.and(ElementMatchers.not(ElementMatchers.isAbstract()))
.transform((builder, typeDescription, classLoader, module) -> builder
.defineField("foo", String.class)
.constructor(ElementMatchers.any())
.intercept(Advice.to(TestRunnableConstructorInterceptor.class))
.method(ElementMatchers.named("run"))
.intercept(Advice.to(TestRunnableRunInterceptor.class))
)
With my Interceptor classes looking like this:
public static class TestRunnableConstructorInterceptor {
#Advice.OnMethodExit
public static void intercept(#Advice.This Object thiz, #Advice.FieldValue(value="foo",readOnly=false) String foo) throws Exception {
foo = "baz"; // this sets the value successfully
}
}
public static class TestRunnableRunInterceptor {
#Advice.OnMethodEnter
public static void intercept(#Advice.This Object thiz, #Advice.FieldValue("foo") String foo) throws Exception {
System.out.println(foo); //prints "baz"
thiz.getClass().getField("foo"); // java.lang.NoSuchFieldException
}
}
I can see that ByteBuddy is passing through the newly defined field via the FieldValue annotation, but reflectively the variable is not visible - perhaps because the reflection is being applied to the original class, and not the 'rebased' class?
Is this the expected behavior? Is there a way to access this new field via reflection?
Could this be something to do with the Runnables being lambdas? I'm using Advice rather than MethodDelegation because if I try to use MethodDelegation on Runnable#run I get errors like this (from my interception Listener)
Failed to transform java.util.concurrent.ThreadPoolExecutor$Worker$auxiliary$8cXEOSRS$auxiliary$7BgjnLbO (before loading) + Exception: java.lang.IllegalStateException: Cannot resolve type description for java.util.concurrent.ThreadPoolExecutor$Worker$auxiliary$8cXEOSRS Cannot resolve type description for java.util.concurrent.ThreadPoolExecutor$Worker$auxiliary$8cXEOSRSnet.bytebuddy.pool.TypePool$Resolution$Illegal.resolve(TypePool.java:134)
As mentioned in the comments, you need to use the getDeclaredField method instead of getField when you want to locate non-public fields.
I assume that your MethodDelegation renders errors as you instrument any Runnable. Do you request #SuperMethodCall proxies in your delegation method? In this case, you are instructing Byte Buddy to also instrument these classes what is impossible as their byte code is not persisted.
Normally, Byte Buddy excludes synthetic classes from instrumentation. As you instrument the java.* namespace, I assume that you are not using the default exclusion matcher? You should ideally restrain your space of instrumented types, for example by name where you could also exclude classes containing $auxiliary$. Otherwise, you can still exclude synthetic classes as it is by default.

Programmatically assess relationship between type variables in class hierarchy

Suppose I have a Java class hierarchy defined as follow:
interface Bar<T> {}
class Foo<A,B> implements Bar<B> {}
How can I programmatically assess (using reflection) that the type parameter of Bar in Foo is the second of foo's parameters and not the first (B instead of A)?
I've tried using TypeVariable#getName() in order to compare the names, but when I apply getGenericInterfaces() to Foo<A,B> I get Bar<T> and not Bar<B>
Solution (thanks to #LouisWasserman): use Foo.class.getGeenricInterfaces()[0].getActualTypeParameters() returns the correct TypeVariable (B instead of T, in the previous example)
well using TypeVariable#getName() return the type as it appears in the source code in your case it's normal to get Bar<T>. TypeVariable Doc
Using reflection in generic Classes can't help, because of Type Erasure. Erasure of Generic Types
I've the same issue in some personal projects, I tried to change the design of my class, have a look at the example below:
Instead of this:
public class Mapper<T> {
public Mapper(){
}
}
I used this:
public class Mapper {
private Class<?> entityClazz;
public Mapper(Class<?> entity){
this.entityClazz = entity
//Here I've donne all reflection issues i want !
}
}
You can use Class#isAssignableFrom() Doc to test assignability between Class Objects.
I hope this helps, good luck !

How to specify static method as annotation value in Java

I want to provide an annotation as the following:
public #interface CloneField
{
String sourceField();
Class<?> customCloner();
}
Where people can annotation fields on their classes and some framework will automatically copy fields to their classes instances by running a method from the customCloner on an external data source object.
For example:
class Test {
#CloneField(sourceField = "demoTest", customCloner = StringToIntCloner.class)
private int testField;
This will copy a string value from a field named demoTest on the external data source object into an int field on the user's object.
Since the customCloner doesn't hold any data I would want to define the cloning method as static without the need to instantiate it just for calling a method.
Usually I would define the custom cloner class as:
Class <? extends FieldCloner> customCloner;
where FieldCloner has a method for cloning.
But since static methods are not supported on interfaces there isn't a clean way to do so.
Is there an elegant way to do so in Java 7?
Beside the problem of running the method which can be solved by reflection I want to verify at compile time that the customCloner class has the appropriate method for cloning.

Java type level annotation and private member visibility

I'm trying to externalize the baseurl of a spring #Controller into a static String member of the controller class. If i do so i have to declare the member public - otherwise it will not be visible to the #RequestMapping annotation. I can't understand why - isn't the annotation part of the class?
Can someone explain why i am forced not to use private here?
Invalid:
#Controller
#RequestMapping(PendingApprovalsController.CONTROLLER_URL)
public class PendingApprovalsController {
private static final String CONTROLLER_URL = "/some/url";
...
}
Valid:
#Controller
#RequestMapping(PendingApprovalsController.CONTROLLER_URL)
public class PendingApprovalsController {
public static final String CONTROLLER_URL = "/some/url";
...
}
An annotation is an ordinary Java class itself. It can't see the members of an annotated class unless they are visible to it, using normal Java rules. Furthermore the existence of annotations may be used by other code at runtime to operate on the members of the annotated class; if those members are not visible, those operations can't be performed.
This page from the JDK documentation package talks about how to define custom annotations, and how to consume annotations applied in code, and it's enlightening in this regard. To define an annotation type, you do something like
public #interface Copyright {
String value();
}
Your custom annotation is defined as a special kind of Java interface; in user, the JVM supplies a runtime implementation as needed. But the key thing to note is how you use your custom annotation, for example:
Method m = ... // Get a java.lang.reflect.Method object from somewhere
if (m.hasAnnotation(Copyright.class)) ...
Note that here we refer to the class object of the annotation type, demonstrating that an annotation is compiled to a normal Java type.

Prototyping in Java instead of extending

Is Javascript-like prototyping anyhow achievable, even using Reflection? Can I wrap my object inside another one, just to extend its functionality with one or two more methods, without wiring all its original nonprivate methods to the wrapper class, or extends is all I get?
If you are looking for extension methods, you could try Xtend. Xtend is language that compiles to java code and eliminates boilerplate code.
The following text is stolen from the Xtend Docs for extensions:
By adding the extension keyword to a field, a local variable or a parameter declaration, its instance methods become extension methods.
Imagine you want to have some layer specific functionality on a class Person. Let us say you are in a servlet-like class and want to persist a Person using some persistence mechanism. Let us assume Person implements a common interface Entity. You could have the following interface
interface EntityPersistence {
public save(Entity e);
public update(Entity e);
public delete(Entity e);
}
And if you have obtained an instance of that type (through a factory or dependency injection or what ever) like this:
class MyServlet {
extension EntityPersistence ep = Factory.get(typeof(EntityPersistence))
...
}
You are able to save, update and delete any entity like this:
val Person person = ...
person.save // calls ep.save(person)
person.name = 'Horst'
person.update // calls ep.update(person)
person.delete // calls ep.delete(person)
I don't think you can do this in Java. You can though in Groovy, using metaclasses
String.metaClass.world = {
return delegate + " world!"
}
println "Hello".world()

Categories