Sun Codemodel generic method invocation - java

I'm using Codemodel library for java-class generation. Is there a way to generate a generic method invocation which looks like this:
clazz.<String>get(value)
There is certainly a way of just casting a return result to a correct type using the following expression:
JExpr.cast(stringType, clazz.invoke("get").arg(value))
which results in
(String) clazz.get(value)
but the preferred way of casting is the first one, as this code is generating templates for further manual editing by developers.

With the existing JCodeModel API, there is no pre-built way to handle this. You can, however, define your own JStatement type to generate the generic declaration like this:
JDefinedClass definedClass = codeModel._class(JMod.PUBLIC, "org.test.Tester", ClassType.CLASS);
JMethod method = definedClass.method(JMod.PUBLIC, codeModel.VOID, "test");
final JType targetType = codeModel.ref(String.class);
final JVar clazzVar = method.body().decl(codeModel.ref(Class.class), "clazz", JExpr.invoke("getClass"));
method.body().add(new JStatement(){
#Override
public void state(JFormatter f) {
f.g(clazzVar).p(".<").g(targetType).p(">").p("get").p("();").nl();
}
});
Which generates:
package org.test;
public class Tester {
public void test() {
Class clazz = getClass();
clazz.<String >get();
}
}
This is by no mean a complete solution (It's missing method call arguments for instance). Take a look at the implementation of the generate() method in JInvocation for the details that are required.

Related

Java 8 - Constructor Reference - The type Select does not define Select(DataObj) that is applicable here"

I defined one FunctionalInterface as below:
#FunctionalInterface
public interface BaseAction {
public void execute(final DataObj dataObj) throws Exception;
}
Then, a class implementing the same as follows:
public class Select implements BaseAction{
#Override
public void execute(final DataObj dataObj) {
//some operations on dataObj here..
}
}
And when I tried instantiating the class Select using syntax prior to Java 8, compiles for me, as follows:
public BaseAction getAction(final String action) {
switch (action) {
case "SELECT": return new Select(); //Works
}
return null;
}
But, when I tried instantiating it using Java 8 syntax, IDE starts complaining me "The type Select does not define Select(DataObj) that is applicable here",
public BaseAction getAction(final String action) {
switch (action) {
case "SELECT": return Select::new; //Compile error here..
}
return null;
}
Any idea how can I fix it?
What you're using is not "the Java 8 syntax for creating an object". You're using a reference to the constructor, so in a way the difference between your two pieces of code is the same as between
someObject.toString()
and
someObject.toString
The first one instantiates a new object, the second one points to the thing used to instantiate the new object, but doesn't call it (the more precise analogy would be to someObject::toString, by the way).
If all you want to do is to instantiate a Select object, then just keep using the "old" code, it's exactly how you'll do it in Java 8.
The new syntax is useful if you want to pass the specific constructor to use to some piece of code that wants to be agnostic to which constructor/type is used.
You could do something like that:
public void executeBaseAction(DataObject data, Supplier<BaseAction> baseActionSupplier) {
BaseAction action = baseActionSupplier.get();
action.execute(data);
}
And call it like this:
executeBaseAction(data, Select::new);
The method reference Select::new is a reference to a constructor, and it doesn't match the required functional interface signature, taking a DataObj parameter and returning void.
You'll need a Select reference to create the method reference, but it must refer to the execute method. This should work:
case "SELECT": return new Select()::execute;
As you've noted, return new Select(); works, and it's less verbose. I would still use this, but the method reference above should work.

Instantiate generified class after loading from repository

When writing a type handler for a repository (such as a web service or a database), I need to instantiate the type after the value is loaded from the repository.
Let's say I get a String value from the repository and there is a constructor with one String argument that I can use. If the return type has a type parameter, what else can I do besides instantiating the raw type? It seems raw types exist only for compatibility with legacy code so I would prefer not to use them.
Normally ? can be used as type parameter (if you know the type will be correct at runtime), but not in this case because you can't instantiate classes with wildcards as type parameter.
EDIT: some example code:
Let's say I have a PrimaryKey class like this:
public class PrimaryKey<R extends RepositoryObject<R>> {
private String value;
public PrimaryKey(String value) {
this.value = value;
}
}
And a set of classes that extend RepositoryObject, which is defined like this:
public class RepositoryObject<R extends RepositoryObject<R>> {
private PrimaryKey<R> pk;
public RepositoryObject(PrimaryKey<R> pk) {
this.pk = pk;
}
PrimaryKey<R> getPrimaryKey() {
return pk;
}
}
Example of a subclass:
public class User extends RepositoryObject<User> {
public User(PrimaryKey<User> userId) {
super(userId);
}
}
Now the type handling method for class PrimaryKey will look something like this:
public PrimaryKey<?> getValue(String stringValue) {
return new PrimaryKey<>(stringValue);
}
But this results in a compiler error (in the Maven build, not in Eclipse IDE strangely enough) even though I'm using the diamond operator instead of when instantiating. Maybe for some reason type inference doesn't work well because of the recursion in the type parameters.
In Java 7 you can typically use the diamond operator to get around this limitation:
Container<?> c = new Container<>(arg);
Otherwise you can use a helper factory method:
<T> Container<T> makeContainer(String arg) {
return new Container<T>(arg);
}
...
Container<?> c = makeContainer(arg);
EDIT:
Following your update, I can see you're using a recursive type parameter <R extends RepositoryObject<R>>. This compile error is due to limitations of javac when it comes to wildcard capture and recursive type parameters. See this related post for example: Java CRTP and Wildcards: Code compiles in Eclipse but not `javac`
Unfortunately, using a raw type is necessary as a workaround, but it can be hidden as an implementation detail:
public PrimaryKey<?> getValue(String stringValue) {
#SuppressWarnings("rawtypes") //a raw type is necessary to placate javac
final PrimaryKey<?> pk = new PrimaryKey(stringValue);
return pk;
}
class SomeBogusClass extends RepositoryObject<SomeBogusClass> { }
return new PrimaryKey<SomeBogusClass>(stringValue);
seriously, you can put anything there that satisfies the bounds, even some bogus class that has nothing to do with your code.

How do I disambiguate in Scala between methods with vararg and without

I'm trying to use the java jcommander library from Scala. The java JCommander class has multiple constructors:
public JCommander(Object object)
public JCommander(Object object, ResourceBundle bundle, String... args)
public JCommander(Object object, String... args)
I want to to call the first constructor that takes no varargs. I tried:
jCommander = new JCommander(cmdLineArgs)
I get the error:
error: ambiguous reference to overloaded definition,
both constructor JCommander in class JCommander of type (x$1: Any,x$2: <repeated...>[java.lang.String])com.beust.jcommander.JCommander
and constructor JCommander in class JCommander of type (x$1: Any)com.beust.jcommander.JCommander
match argument types (com.lasic.CommandLineArgs) and expected result type com.beust.jcommander.JCommander
jCommander = new JCommander(cmdLineArgs)
I've also tried using a named parameter, but got the same result:
jCommander = new JCommander(`object` = cmdLineArgs)
How do I tell Scala I want to call the constructor that doesn't take varargs?
I'm using Scala 2.8.0.
Sorry, I now realize this is a known interoperability problem with Java. See this question and the ticket. The only work around I know of is to create a small Java class just to disambiguate these calls.
The only Scala solution to this problem that I know involves reflection.
Ambiguous Methods
Let's suppose we have a Java test class:
public class Ambig {
public Ambig() {}
public String say(Object o) { return o.toString(); }
public String say(Object o, String... ss) { return o.toString()+ss.length; }
}
We can get access to the method via reflection directly:
val ambig = new Ambig
val methods = ambig.getClass.getMethods.filter(_.getName == "say")
val wanted = methods.find(_.getParameterTypes.length == 1).get
wanted.invoke(ambig, Some(5)).asInstanceOf[String]
or we can use structural types (which use reflection under the hood) to achieve the same thing with less boilerplate:
def sayer(speaker: { def say(o: Object): String }, o: Object) = speaker.say(o)
sayer(new Ambig, Some(5))
Ambiguous Constructors
Our strategy has to differ because we don't actually have an object to begin with. Let's suppose we have the Java class
public class Ambig2 {
public final String say;
public Ambig2(Object o) { say = o.toString(); }
public Ambig2(Object o, String... ss) { say = o.toString()+ss.length; }
}
The structural types approach no longer works, but we can still use reflection:
val mkAmbig2 = classOf[Ambig2].getConstructors.filter(_.getParameterTypes.length==1)
val ambig = mkAmbig2.head.newInstance(Some(5)).asInstanceOf[Ambig2]
ambig.say // Some(5)
I think your easiest option is to have a Java class with a factory method to bridge the issue:
package com.beust.jcommander;
public class JCommanderFactory {
public static createWithArgs(Object cmdLineArgs) {
return new JCommander(cmdLineArgs);
}
}
Alternatively you could use http://jewelcli.sourceforge.net/usage.html instead. JewelCli has an unambiguous factory method for the same purpose and also uses PICA (Proxied Interfaces Configured with Annotations) technique http://www.devx.com/Java/Article/42492/1954.
In fact I have an example of using JewelCLI with Scala here on Stack Overflow.
The way to avoid this ambiguity is to force the compiler to pick the overload that takes more than one argument, using Scala's collection explosion syntax to pass in a singleton collection:
import java.util.stream.Stream
val stream = Stream.of(List(1):_*)
You can call the constructor with varags, but pass an empty list of varags.
(Of course, if you know that constructing JCommander with empty varags will produce the same result as calling the overloaded constructor (or method) without vargs)
jCommander = new JCommander(cmdLineArgs, Nil: _*)

How to get string name of a method in java?

How can I find out through reflection what is the string name of the method?
For example given:
class Car{
public void getFoo(){
}
}
I want to get the string "getFoo", something like the following:
Car.getFoo.toString() == "getFoo" // TRUE
You can get the String like this:
Car.class.getDeclaredMethods()[0].getName();
This is for the case of a single method in your class. If you want to iterate through all the declared methods, you'll have to iterate through the array returned by Car.class.getDeclaredMethods():
for (Method method : Car.class.getDeclaredMethods()) {
String name = method.getName();
}
You should use getDeclaredMethods() if you want to view all of them, getMethods() will return only public methods.
And finally, if you want to see the name of the method, which is executing at the moment, you should use this code:
Thread.currentThread().getStackTrace()[1].getMethodName();
This will get a stack trace for the current thread and return the name of the method on its top.
Since methods aren't objects themselves, they don't have direct properties (like you would expect with first-class functions in languages like JavaScript).
The closest you can do is call Car.class.getMethods()
Car.class is a Class object which you can use to invoke any of the reflection methods.
However, as far as I know, a method is not able to identify itself.
So, you want to get the name of the currently executing method? Here's a somewhat ugly way to do that:
Exception e = new Exception();
e.fillInStackTrace();
String methodName = e.getStackTrace()[0].getMethodName();
Look into this thread:
Getting the name of the currently executing method
It offers some more solutions - for example:
String name = new Object(){}.getClass().getEnclosingMethod().getName();
With Java 8, you can do this with a few lines of code (almost) without any additional libraries. The key is to convert your method into a serialisable lambda expression. Therefore, you can just define a simple interface like this:
#FunctionalInterface
public interface SerializableFunction<I, O> extends Function<I, O>, Serializable {
// Combined interface for Function and Serializable
}
Now, we need to convert our lambda expression into a SerializedLambda object. Apparently, Oracle does not really want us to do that, so take this with a grain of salt... As the required method is private, we need to invoke it using reflections:
private static final <T> String nameOf(SerializableFunction<T, ?> lambda) {
Method findMethod = ReflectionUtils.findMethod(lambda.getClass(), "writeReplace");
findMethod.setAccessible(true);
SerializedLambda invokeMethod = (SerializedLambda) ReflectionUtils.invokeMethod(findMethod, lambda);
return invokeMethod.getImplMethodName();
}
I'm using Springs ReflectionUtils class here for simplicity, but you can of course replace this by manually looping through all superclasses and use getDeclaredMethod to find the writeReplace method.
And this is it already, now you can use it like this:
#Test
public void testNameOf() throws Throwable {
assertEquals("getName", nameOf(MyClassTest::getName));
}
I haven't checked this with Java 9s module system, so as a little disclaimer it might be more tricky to do this with more recent Java versions...
try this,
import java.lang.reflect.*;
public class DumpMethods {
public static void main(String args[]) {
try {
Class c = Class.forName(args[0]);
Method m[] = c.getDeclaredMethods();
for (int i = 0; i < m.length; i++)
System.out.println(m[i].toString());
} catch (Throwable e) {
System.err.println(e);
}
}
}
Wait, since you already know the method name, can't you just type it as a string?
Instead of (pseudo) Class.methodName.toString(), just use "methodName".
Otherwise you can use Class#getDeclaredMethods() to get all the methods in a class

Type-safe method reflection in Java

Is any practical way to reference a method on a class in a type-safe manner? A basic example is if I wanted to create something like the following utility function:
public Result validateField(Object data, String fieldName,
ValidationOptions options) { ... }
In order to call it, I would have to do:
validateField(data, "phoneNumber", options);
Which forces me to either use a magic string, or declare a constant somewhere with that string.
I'm pretty sure there's no way to get around that with the stock Java language, but is there some kind of (production grade) pre-compiler or alternative compiler that may offer a work around? (similar to how AspectJ extends the Java language) It would be nice to do something like the following instead:
public Result validateField(Object data, Method method,
ValidationOptions options) { ... }
And call it with:
validateField(data, Person.phoneNumber.getter, options);
As others mention, there is no real way to do this... and I've not seen a precompiler that supports it. The syntax would be interesting, to say the least. Even in your example, it could only cover a small subset of the potential reflective possibilities that a user might want to do since it won't handle non-standard accessors or methods that take arguments, etc..
Even if it's impossible to check at compile time, if you want bad code to fail as soon as possible then one approach is to resolve referenced Method objects at class initialization time.
Imagine you have a utility method for looking up Method objects that maybe throws error or runtime exception:
public static Method lookupMethod( Class c, String name, Class... args ) {
// do the lookup or throw an unchecked exception of some kind with a really
// good error message
}
Then in your classes, have constants to preresolve the methods you will use:
public class MyClass {
private static final Method GET_PHONE_NUM = MyUtils.lookupMethod( PhoneNumber.class, "getPhoneNumber" );
....
public void someMethod() {
validateField(data, GET_PHONE_NUM, options);
}
}
At least then it will fail as soon as MyClass is loaded the first time.
I use reflection a lot, especially bean property reflection and I've just gotten used to late exceptions at runtime. But that style of bean code tends to error late for all kinds of other reasons, being very dynamic and all. For something in between, the above would help.
There isn't anything in the language yet - but part of the closures proposal for Java 7 includes method literals, I believe.
I don't have any suggestions beyond that, I'm afraid.
Check out https://proxetta.jodd.org/refs/methref. It uses the Jodd proxy library (Proxetta) to proxy your type. Not sure about its performance characteristics, but it does provide type safety.
An example: Suppose Str.class has method .boo(), and you want to get its name as the string "boo":
String methodName = Methref.of(Str.class).name(Str::boo);
There's more to the API than the example above: https://oblac.github.io/jodd-site/javadoc/jodd/methref/Methref.html
Is any practical way to reference a method on a class in a type-safe manner?
First of all, reflection is type-safe. It is just that it is dynamically typed, not statically typed.
So, assuming that you want a statically typed equivalent of reflection, the theoretical answer is that it is impossible. Consider this:
Method m;
if (arbitraryFunction(obj)) {
m = obj.getClass().getDeclaredMethod("foo", ...);
} else {
m = obj.getClass().getDeclaredMethod("bar", ...);
}
Can we do this so that that runtime type exceptions cannot happen? In general NO, since this would entail proving that arbitraryFunction(obj) terminates. (This is equivalent to the Halting Problem, which is proven to be unsolvable in general, and is intractable using state-of-the-art theorem proving technology ... AFAIK.)
And I think that this road-block would apply to any approach where you could inject arbitrary Java code into the logic that is used to reflectively select a method from an object's class.
To my mind, the only moderately practical approach at the moment would be to replace the reflective code with something that generates and compiles Java source code. If this process occurs before you "run" the application, you've satisfied the requirement for static type-safety.
I was more asking about reflection in which the result is always the same. I.E. Person.class.getMethod("getPhoneNumber", null) would always return the same method and it's entirely possible to resolve it at compile time.
What happens if after compiling the class containing this code, you change Person to remove the getPhoneNumber method?
The only way you can be sure that you can resolve getPhoneNumber reflectively is if you can somehow prevent Person from being changed. But you can't do that in Java. Runtime binding of classes is a fundamental part of the language.
(For record, if you did that for a method that you called non-reflectively, you would get an IncompatibleClassChangeError of some kind when the two classes were loaded ...)
It has been pointed out that in Java 8 and later you could declare your validator something like this:
public Result validateField(Object data,
SomeFunctionalInterface function,
ValidationOptions options) { ... }
where SomeFunctionalInterface corresponds to the (loosely speaking) common signature of the methods you are validating.
Then you can call it with a method reference; e.g.
validateField(data, SomeClass::someMethod, options)
This is approach is statically type-safe. You will get a compilation error if SomeClass doesn't have someMethod or if it doesn't conform to SomeFunctionalInterface.
But you can't use a string to denote the method name. Looking up a method by name would entail either reflection ... or something else that side-steps static (i.e. compile time / load time) type safety.
Java misses the syntax sugar to do something as nice as Person.phoneNumber.getter. But if Person is an interface, you could record the getter method using a dynamic proxy. You could record methods on non-final classes as well using CGLib, the same way Mockito does it.
MethodSelector<Person> selector = new MethodSelector<Person>(Person.class);
selector.select().getPhoneNumber();
validateField(data, selector.getMethod(), options);
Code for MethodSelector: https://gist.github.com/stijnvanbael/5965609
Inspired by mocking frameworks, we could dream up the following syntax:
validator.validateField(data, options).getPhoneNumber();
Result validationResult = validator.getResult();
The trick is the generic declaration:
class Validator {
public <T> T validateField(T data, options) {...}
}
Now the return type of the method is the same as your data object's type and you can use code completion (and static checking) to access all the methods, including the getter methods.
As a downside, the code isn't quite intuitive to read, since the call to the getter doesn't actually get anything, but instead instructs the validator to validate the field.
Another possible option would be to annotate the fields in your data class:
class FooData {
#Validate(new ValidationOptions(...))
private PhoneNumber phoneNumber;
}
And then just call:
FooData data;
validator.validate(data);
to validate all fields according to the annotated options.
The framework picklock lets you do the following:
class Data {
private PhoneNumber phoneNumber;
}
interface OpenData {
PhoneNumber getPhoneNumber(); //is mapped to the field phoneNumber
}
Object data = new Data();
PhoneNumber number = ObjectAccess
.unlock(data)
.features(OpenData.class)
.getPhoneNumber();
This works in a similar way setters and private methods. Of course, this is only a wrapper for reflection, but the exception does not occur at unlocking time not at call time. If you need it at build time, you could write a unit test with:
assertThat(Data.class, providesFeaturesOf(OpenData.class));
I found a way to get the Method instance using Lambdas. It works only on interface methods though currently.
It works using net.jodah:typetools which is a very lightweight library.
https://github.com/jhalterman/typetools
public final class MethodResolver {
private interface Invocable<I> {
void invokeWithParams(I instance, Class<?>[] parameterTypes) throws Throwable;
}
interface ZeroParameters<I, R> extends Invocable<I> {
R invoke(I instance) throws Throwable;
#Override
default void invokeWithParams(I instance, Class<?>[] parameterTypes) throws Throwable {
invoke(instance);
}
}
public static <I, R> Method toMethod0(ZeroParameters<I, R> call) {
return toMethod(ZeroParameters.class, call, 1);
}
interface OneParameters<I, P1, R> extends Invocable<I> {
R invoke(I instance, P1 p1) throws Throwable;
#Override
default void invokeWithParams(I instance, Class<?>[] parameterTypes) throws Throwable {
invoke(instance, param(parameterTypes[1]));
}
}
public static <I, P1, R> Method toMethod1(OneParameters<I, P1, R> call) {
return toMethod(OneParameters.class, call, 2);
}
interface TwoParameters<I, P1, P2, R> extends Invocable<I> {
R invoke(I instance, P1 p1, P2 p2) throws Throwable;
#Override
default void invokeWithParams(I instance, Class<?>[] parameterTypes) throws Throwable {
invoke(instance, param(parameterTypes[1]), param(parameterTypes[2]));
}
}
public static <I, P1, P2, R> Method toMethod2(TwoParameters<I, P1, P2, R> call) {
return toMethod(TwoParameters.class, call, 3);
}
private static final Map<Class<?>, Object> parameterMap = new HashMap<>();
static {
parameterMap.put(Boolean.class, false);
parameterMap.put(Byte.class, (byte) 0);
parameterMap.put(Short.class, (short) 0);
parameterMap.put(Integer.class, 0);
parameterMap.put(Long.class, (long) 0);
parameterMap.put(Float.class, (float) 0);
parameterMap.put(Double.class, (double) 0);
}
#SuppressWarnings("unchecked")
private static <T> T param(Class<?> type) {
return (T) parameterMap.get(type);
}
private static <I> Method toMethod(Class<?> callType, Invocable<I> call, int responseTypeIndex) {
Class<?>[] typeData = TypeResolver.resolveRawArguments(callType, call.getClass());
Class<?> instanceClass = typeData[0];
Class<?> responseType = responseTypeIndex != -1 ? typeData[responseTypeIndex] : Void.class;
AtomicReference<Method> ref = new AtomicReference<>();
I instance = createProxy(instanceClass, responseType, ref);
try {
call.invokeWithParams(instance, typeData);
} catch (final Throwable e) {
throw new IllegalStateException("Failed to call no-op proxy", e);
}
return ref.get();
}
#SuppressWarnings("unchecked")
private static <I> I createProxy(Class<?> instanceClass, Class<?> responseType,
AtomicReference<Method> ref) {
return (I) Proxy.newProxyInstance(MethodResolver.class.getClassLoader(),
new Class[] {instanceClass},
(proxy, method, args) -> {
ref.set(method);
return parameterMap.get(responseType);
});
}
}
Usage:
Method method = MethodResolver.toMethod2(SomeIFace::foobar);
System.out.println(method); // public abstract example.Result example.SomeIFace.foobar(java.lang.String,boolean)
Method get = MethodResolver.<Supplier, Object>toMethod0(Supplier::get);
System.out.println(get); // public abstract java.lang.Object java.util.function.Supplier.get()
Method accept = MethodResolver.<IntFunction, Integer, Object>toMethod1(IntFunction::apply);
System.out.println(accept); // public abstract java.lang.Object java.util.function.IntFunction.apply(int)
Method apply = MethodResolver.<BiFunction, Object, Object, Object>toMethod2(BiFunction::apply);
System.out.println(apply); // public abstract java.lang.Object java.util.function.BiFunction.apply(java.lang.Object,java.lang.Object)
Unfortunately you have to create a new interface and method based on the parameter count and whether the method returns void or not.
However, if you have a somewhat fixed/limited method signature/parameter types, then this becomes quite handy.

Categories