How can I create a Functional interface implementation for Fields? - java

Consider a field weight in class Animal. I want to be able to create a getter and setter functional interface objects for manipulating this field.
class Animal {
int weight;
}
My current approach is similar to one used for methods:
public static Supplier getter(Object obj, Class<?> cls, Field f) throws Exception {
boolean isstatic = Modifier.isStatic(f.getModifiers());
MethodType sSig = MethodType.methodType(f.getType());
Class<?> dCls = Supplier.class;
MethodType dSig = MethodType.methodType(Object.class);
String dMthd = "get";
MethodType dType = isstatic? MethodType.methodType(dCls) : MethodType.methodType(dCls, cls);
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle fctry = LambdaMetafactory.metafactory(lookup, dMthd, dType, dSig, lookup.unreflectGetter(f), sSig).getTarget();
fctry = !isstatic && obj!=null? fctry.bindTo(obj) : fctry;
return (Supplier)fctry.invoke();
}
But this gives the following error:
java.lang.invoke.LambdaConversionException: Unsupported MethodHandle kind: getField x.Animal.weight:()int
UPDATE
I am trying to create a class ObjectMap implementing interface Map, which basically tries to represent an object as a Map, where the object can be of any type. Was currently using Field.get() and Field.set() for manipulating fields in get() and put() methods, and using above mentioned approach to create Supplier and Consumer objects for invoking getter and setter methods. I was wondering if i could merge the two separate methods into one.
Example class which could be used as a Map through ObjectMap:
public class ThisCanBeAnything {
/* fields */
public String normalField;
private int hiddenFiled;
private String hiddenReadonlyField;
/* getters and setters */
public int hiddenField() {
return hiddenField;
}
public void hiddenField(int v) {
System.out.println("set: hiddenField="+v);
hiddenField = v;
}
public String hiddenReadonlyField() {
return hiddenReadonlyField;
}
}
And here is the expected usage:
Object o = new ThisCanBeAnything();
Map m = new ObjectMap(o);
m.put("normalField", "Normal");
System.out.println(m.get("normalField")); // Normal
m.put("hiddenField", 1); // set: hiddenField=1
System.out.println(m.get("hiddenField")); // 1
m.put("hiddenReadonlyField", 1); // does not do anything
System.out.println(m.get("hiddenReadonlyField")); // null

You are making it too difficult that it needs to be. When you have a Field, you can directly invoke unreflectGetter on the lookup factory to retrieve a MethodHandle:
Produces a method handle giving read access to a reflected field. The type of the method handle will have a return type of the field's value type. If the field is static, the method handle will take no arguments. Otherwise, its single argument will be the instance containing the field.
public static Supplier<Object> getter(Object obj, Class<?> cls, Field f) {
f.setAccessible(true);
MethodHandles.Lookup lookup = MethodHandles.lookup();
return () -> {
try {
MethodHandle handle = lookup.unreflectGetter(f);
return Modifier.isStatic(f.getModifiers()) ? handle.invoke() : handle.invoke(obj);
} catch (Throwable t) {
throw new IllegalArgumentException(t);
}
};
}
This returns a supplier of the value of the field. Depending on the accessibility of the field, you might need to invoke setAccessible(true).
Note that method handles and the reflection API also differs in terms of performance and might be faster.

Functional style lets you think about such things in new ways. Instead of a reflection-based approach like
Supplier getter(Object obj, Class<?> cls, Field f){...}
try something like
static <O,F> Supplier<F> getter(O obj, Function<O,F> extractor) {
return () -> extractor.apply(obj);
}
which you would invoke like
Supplier<Integer> getWeight = getter(animal, a -> a.weight);
Integer weight = getWeight.get();
Is a -> a.weight any harder than coming up with a Field via reflection?
One advantage is that you could use fields or methods as needed, e.g., if you added a getter for weight,
Supplier<Integer> getWeight = getter(animal, Animal::getWeight);
A similar setter factory might be
static <O,F> Consumer<F> setter(O obj, BiConsumer<O,F> modifier) {
return field -> modifier.accept(obj,field);
}
Invoked like this
Consumer<Integer> setWeight = setter(animal, (a, w) -> a.weight = w);
setWeight.accept(90);

You can directly write the lambda, you don't need the LambdaMetafactory at all:
public static Supplier getter(Object obj, Field f) {
return () -> {
try {
return f.get(obj);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
};
}
Or a runtime-typesafe version:
public static <T> Supplier<T> getter(Object obj, Class<T> fieldClass, Field f) {
if (!fieldClass.isAssignableFrom(f.getType()))
throw new RuntimeException("Field is not of expected type");
return () -> {
try {
return (T) f.get(obj);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
};
}
e.g.:
private class X {
public int a;
}
#Test
public void supplier_getter_test() throws NoSuchFieldException {
X a = new X();
a.a = 5;
Supplier<Integer> sup = getter(a, int.class, X.class.getField("a"));
assertEquals(5, sup.get().intValue());
}

You can’t bind a MethodHandle bearing a direct access to a field to a function interface instance, but you can bind the accessor method of the Field instance:
public static Supplier getter(Object obj, Class<?> cls, Field f) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle get=lookup.findVirtual(Field.class,"get",MethodType.genericMethodType(1));
MethodHandle fctry = LambdaMetafactory.metafactory(lookup, "get",
get.type().changeReturnType(Supplier.class), MethodType.genericMethodType(0),
get, MethodType.genericMethodType(0)).getTarget();
return (Supplier)fctry.invoke(f, Modifier.isStatic(f.getModifiers())? null: obj);
}
Though in this specific example you may consider generating an IntSupplier instead:
public static IntSupplier getter(Object obj, Class<?> cls, Field f) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle get=lookup.findVirtual(Field.class, "getInt",
MethodType.methodType(int.class, Object.class));
MethodHandle fctry = LambdaMetafactory.metafactory(lookup, "getAsInt",
get.type().changeReturnType(IntSupplier.class), MethodType.methodType(int.class),
get, MethodType.methodType(int.class)).getTarget();
return (IntSupplier)fctry.invoke(f, Modifier.isStatic(f.getModifiers())? null: obj);
}
…
final Animal animal = new Animal();
IntSupplier s=getter(animal, Animal.class, Animal.class.getDeclaredField("weight"));
animal.weight=42;
System.out.println(s.getAsInt());

I know it's a late answer, but I have developed a library that you can use to turn any MethodHandle into a lambda function. The performance is the same as if you would manually implement the function with direct access.
The impl is based around the fact that static final MethodHandles are being inlined to point of being as fast as direct access. More info on this can be found here:
How can I improve performance of Field.set (perhap using MethodHandles)?
The library can be found here: https://github.com/LanternPowered/Lmbda. For now you will have to use Jitpack to access it (small library so it won't take long to compile):
https://jitpack.io/#LanternPowered/Lmbda
An example for setting a field on a object:
import org.lanternpowered.lmbda.LmbdaFactory;
import org.lanternpowered.lmbda.LmbdaType;
import org.lanternpowered.lmbda.MethodHandlesX;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.function.ObjIntConsumer;
public class LambdaSetterTest {
public static void main(String... args) throws Exception {
final MethodHandles.Lookup lookup = MethodHandlesX.privateLookupIn(TestObject.class, MethodHandles.lookup());
final MethodHandle methodHandle = lookup.findSetter(TestObject.class, "data", int.class);
final ObjIntConsumer<TestObject> setter = LmbdaFactory.create(new LmbdaType<ObjIntConsumer<TestObject>>() {}, methodHandle);
final TestObject object = new TestObject();
System.out.println(100 == object.getData());
setter.accept(object, 10000);
System.out.println(10000 == object.getData());
}
public static class TestObject {
private int data = 100;
int getData() {
return this.data;
}
}
}
And getting a field from a object:
import org.lanternpowered.lmbda.LmbdaFactory;
import org.lanternpowered.lmbda.LmbdaType;
import org.lanternpowered.lmbda.MethodHandlesX;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.function.ToIntFunction;
public class LambdaSetterTest {
public static void main(String... args) throws Exception {
final MethodHandles.Lookup lookup = MethodHandlesX.privateLookupIn(TestObject.class, MethodHandles.lookup());
final MethodHandle methodHandle = lookup.findGetter(TestObject.class, "data", int.class);
final ToIntFunction<TestObject> getter = LmbdaFactory.create(new LmbdaType<ToIntFunction<TestObject>>() {}, methodHandle);
final TestObject object = new TestObject();
System.out.println(100 == getter.applyAsInt(object));
object.setData(10000);
System.out.println(10000 == getter.applyAsInt(object));
}
public static class TestObject {
private int data = 100;
void setData(int value) {
this.data = value;
}
}
}

Related

Creating a mock library

I want to create a Mock Library class that implements InvocationHandler interface from Java Reflection.
This is the template I have created:
import java.lang.reflect.*;
import java.util.*;
class MyMock implements InvocationHandler {
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// todo
}
public MyMock when(String method, Object[] args) {
// todo
}
public void thenReturn(Object val) {
// todo
}
}
The when and thenReturn methods are chained methods.
Then when method registers the given mock parameters.
thenReturn method registers the expected return values for the given mock parameters.
Also, I want to throw java.lang.IllegalArgumentException if the proxied interface calls methods or uses parameters that are not registered.
This is a sample interface:
interface CalcInterface {
int add(int a, int b);
String add(String a, String b);
String getValue();
}
Here we have two overloaded add methods.
This is a program to test the mock class I wanted to implement.
class TestApplication {
public static void main(String[] args) {
MyMock m = new MyMock();
CalcInterface ref = (CalcInterface) Proxy.newProxyInstance(MyMock.class.getClassLoader(), new Class[]{CalcInterface.class}, m);
m.when("add", new Object[]{1,2}).thenReturn(3);
m.when("add", new Object[]{"x","y"}).thenReturn("xy");
System.out.println(ref.add(1,2)); // prints 3
System.out.println(ref.add("x","y")); // prints "xy"
}
}
This is the code which I have implemented so far to check the methods in CalcInterface:
class MyMock implements InvocationHandler {
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
int n = args.length;
if(n == 2 && method.getName().equals("add")) {
Object o1 = args[0], o2 = args[1];
if((o1 instanceof String) && (o2 instanceof String)) {
String s1 = (String) o1, s2 = (String) o2;
return s1+ s2;
} else if((o1 instanceof Integer) && (o2 instanceof Integer)) {
int s1 = (Integer) o1, s2 = (Integer) o2;
return s1+ s2;
}
}
throw new IllegalArgumentException();
}
public MyMock when(String method, Object[] args) {
return this;
}
public void thenReturn(Object val) {
}
}
Here I am checking only for methods with the name add and having 2 arguments, with their type as String or Integer.
But I wanted to create this MyMock class in a general fashion, supporting different interfaces not just CalcInterface, and also supporting different methods not just the add method I implemented here.
You have to separate the builder logic from the object to build. The method when has to return something which remembers the arguments, so that the invocation of thenReturn still knows the context.
For example
public class MyMock implements InvocationHandler {
record Key(String name, List<?> arguments) {
Key { // stream().toList() creates an immutable list allowing null
arguments = arguments.stream().toList();
}
Key(String name, Object... arg) {
this(name, arg == null? List.of(): Arrays.stream(arg).toList());
}
}
final Map<Key, Function<Object[], Object>> rules = new HashMap<>();
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
var rule = rules.get(new Key(method.getName(), args));
if(rule == null) throw new IllegalStateException("No matching rule");
return rule.apply(args);
}
public record Rule(MyMock mock, Key key) {
public void thenReturn(Object val) {
var existing = mock.rules.putIfAbsent(key, arg -> val);
if(existing != null) throw new IllegalStateException("Rule already exist");
}
public void then(Function<Object[], Object> f) {
var existing = mock.rules.putIfAbsent(key, Objects.requireNonNull(f));
if(existing != null) throw new IllegalStateException("Rule already exist");
}
}
public Rule when(String method, Object... args) {
Key key = new Key(method, args);
if(rules.containsKey(key)) throw new IllegalStateException("Rule already exist");
return new Rule(this, key);
}
}
This is already capable of executing your example literally, but also supports something like
MyMock m = new MyMock();
CalcInterface ref = (CalcInterface) Proxy.newProxyInstance(
CalcInterface.class.getClassLoader(), new Class[]{CalcInterface.class}, m);
m.when("add", 1,2).thenReturn(3);
m.when("add", "x","y").thenReturn("xy");
AtomicInteger count = new AtomicInteger();
m.when("getValue").then(arg -> "getValue invoked " + count.incrementAndGet() + " times");
System.out.println(ref.add(1,2)); // prints 3
System.out.println(ref.add("x","y")); // prints "xy"
System.out.println(ref.getValue()); // prints getValue invoked 1 times
System.out.println(ref.getValue()); // prints getValue invoked 2 times
Note that when you want to add support for rules beyond simple value matching, a hash lookup will not work anymore. In that case you have to resort to a data structure you have to search linearly for a match.
The example above uses newer Java features like record classes but it shouldn’t be too hard to rewrite it for previous Java versions if required.
It’s also possible to redesign this code to use the real builder pattern, i.e. to use a builder to describe the configuration prior to creating the actual handler/mock instance. This allows the handler/mock to use an immutable state:
public class MyMock2 {
public static Builder builder() {
return new Builder();
}
public interface Rule {
Builder thenReturn(Object val);
Builder then(Function<Object[], Object> f);
}
public static class Builder {
final Map<Key, Function<Object[], Object>> rules = new HashMap<>();
public Rule when(String method, Object... args) {
Key key = new Key(method, args);
if(rules.containsKey(key))
throw new IllegalStateException("Rule already exist");
return new RuleImpl(this, key);
}
public <T> T build(Class<T> type) {
Map<Key, Function<Object[], Object>> rules = Map.copyOf(this.rules);
return type.cast(Proxy.newProxyInstance(type.getClassLoader(),
new Class[]{ type }, (proxy, method, args) -> {
var rule = rules.get(new Key(method.getName(), args));
if(rule == null) throw new IllegalStateException("No matching rule");
return rule.apply(args);
}));
}
}
record RuleImpl(MyMock2.Builder builder, Key key) implements Rule {
public Builder thenReturn(Object val) {
var existing = builder.rules.putIfAbsent(key, arg -> val);
if(existing != null) throw new IllegalStateException("Rule already exist");
return builder;
}
public Builder then(Function<Object[], Object> f) {
var existing = builder.rules.putIfAbsent(key, Objects.requireNonNull(f));
if(existing != null) throw new IllegalStateException("Rule already exist");
return builder;
}
}
record Key(String name, List<?> arguments) {
Key { // stream().toList() createns an immutable list allowing null
arguments = arguments.stream().toList();
}
Key(String name, Object... arg) {
this(name, arg == null? List.of(): Arrays.stream(arg).toList());
}
}
}
which can be used like
AtomicInteger count = new AtomicInteger();
CalcInterface ref = MyMock2.builder()
.when("add", 1,2).thenReturn(3)
.when("add", "x","y").thenReturn("xy")
.when("getValue")
.then(arg -> "getValue invoked " + count.incrementAndGet() + " times")
.build(CalcInterface.class);
System.out.println(ref.add(1,2)); // prints 3
System.out.println(ref.add("x","y")); // prints "xy"
System.out.println(ref.getValue()); // prints getValue invoked 1 times
System.out.println(ref.getValue()); // prints getValue invoked 2 times
InvocationHandler is used to invoke a method signature against an object instance (proxy) that's instantiated in memory (or a class, if you're tapping a static method), not to support methods that aren't in the supplied proxy's class at all, which is how you've implemented it here. That said, you can probably achieve what you're trying to do by holding the method signature you're trying to mock (as well as the value you want to return when the args match) in private variables.
This may work, with the proviso that I haven't done Java in a couple of years, so I may be a bit rusty:
class MyMock implements InvocationHandler {
private String methodName = null;
private Object[] supportedArgs = null;
private Object returnValue = null;
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// If we don't know when this mock is supposed to be used, it's useless
assert this.methodName != null: "when(method, args) hasn't been called against the mock yet!";
// Note that both args and supportedArgs will be null if the method signature has no params
if (method.getName().equals(this.methodName) && this.supportedArgs == args) {
return this.returnValue;
}
try {
return method.invoke(proxy, args);
}
catch (IllegalAccessException | InvocationTargetException innerException){
// The proxy didn't support the method either, so let's throw an IllegalArgumentException
throw new IllegalArgumentException("The supplied method signature isn't implemented in the proxy.");
}
}
public MyMock when(String method, Object[] args) {
this.methodName = method;
this.supportedArgs = args;
return this;
}
public void thenReturn(Object val) {
this.returnValue = val;
}
}

Enforce compile type safety with TypeSafeMap

Problem statement: We are building a library which has a TypeSafeMap as response. TypeSafeMap is a map which can hold any type of objects.
Now, the client is going to access the typesafemap. We are trying to enforce some level of compile type safety. Below is the code and more explanation.
Response structure:
public Class Response {
private TypeSafeMap t;
public TypeSafeMap getMap() { return t; }
}
//Type safety Map
public class TypeSafeMap
{
private final static Map<String, Object> map = new HashMap<>();
public static <T> T put(String key, T value) {
if (null != key) {
return (T) map.put(key, value);
}
return (T) map;
}
#SuppressWarnings("unchecked")
public static <T> T get(PartyEnums partyEnum)
{
return (T) map.get(partyEnum.PARTY.name());
}
}
//Enum that we expose to client to get the property and the corresponding field type
public enum PartyEnums
{
PARTY("party", new ArrayList<Party>().getClass());
private final String name;
private final Class<?> clzz; //this is the type client should access as field type
PartyEnums(String name,Class<?> clzz)
{
this.name = name;
this.clzz=clzz;
}
public Class<?> getClzz()
{
return clzz;
}
#SuppressWarnings("unchecked")
public <T> T getInstance()
{
T ins = null;
try {
ins = (T) getClzz().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
return ins;
}
}
//Client call
public class ClientCall {
Object obj = TypeSafeMap.get(PartyEnums.PARTY); //No error.
String str = TypeSafeMap.get(PartyEnums.PARTY); //No error.
But we want enforce some level of compile type safety as the field type "str" and TypeSafeMap.get() type do not match.
How can we enforce compile type safety?
List<Party> party = TypeSafeMap.get(PartyEnums.PARTY);// OK.
}
TL;DR
This cannot be done using an enum in its current form.
There was a JEP 301: Enhanced Enums that would address the very same problem, but it's been withdrawn.
Your only choice to enforce type-safety (currently) is to simulate an enum by using a final class with predefined typed constants.
I would imagine it to be something like this:
public final class Key<V> {
public static final Key<List<Party>> PARTY_LIST = new Key<>("party list");
public static final Key<Map<Integer, String>> PARTY_MAP = new Key<>("party map");
public static final Key<String> SOME_STRING = new Key<>("party string");
private final String name;
private Key(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
And now we are ready to make your TypeSafeMap really type-safe by modifying both <T> T put(String key, T value) (which would not obviously be safe even if the "enum approach" was theoretically possible) and <T> T get(PartyEnums partyEnum) this way:
public static class TypeSafeMap {
private final static Map<String, Object> MAP = new HashMap<>();
#SuppressWarnings("unchecked")
public static <T> T put(Key<T> key, T value) {
if (null != key) {
return (T) MAP.put(key.getName(), value);
}
return value;
}
#SuppressWarnings("unchecked")
public static <T> T get(Key<T> key) {
return (T) MAP.get(key.getName());
}
}
I still see at least 2 possible issues that:
Multiple constants may share the same name hence effectively overwriting each other once used (can be tackled for instance using an enum instead of String)
put(Key<T> key, T value) passes through the input value back even for the null keys which is (in my opinion) fail-safe but misleading for the caller (who might think the "store" operation was somehow succeeded.
However, given the weak points above this implementation still fits your original intention, so that:
These cases would pass:
map.put(Key.JUST_STRING, "just string");
map.put(Key.PARTY_LIST, Arrays.asList(new Party()));
...
Object resultAsObject = map.get(Key.PARTY_LIST);
List<Party> resultAsList = map.get(Key.PARTY_LIST);
String resultString = map.get(Key.JUST_STRING);
But these fail with compile-time error:
map.put(Key.PARTY_LIST, Arrays.asList(new String()));
...
String stringFromList = map.get(Key.PARTY_LIST);
Note that Object resultAsObject = map.get(<ANYTHING>) will always succeed as any returned value (including nulls) can we represented as an Object variable

Bean post processor for Retry annotation

I have a legacy project with Spring version 3.0 (I can't use Retriable annotation from spring package).
I want to implement Retryable annotation to annotate my methods which execution should be retry on fail.
This is my class:
#Component
public final class RetryBpp implements BeanPostProcessor {
private final ConcurrentMap<String, ClassDefinition> map = new ConcurrentHashMap<>();
#Override
public Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException {
final Class<?> asClass = bean.getClass();
final Method[] methods = asClass.getMethods();
final List<Method> collect = Stream.of(methods)
.filter(method -> method.isAnnotationPresent(Repitable.class))
.collect(Collectors.toList());
if(!collect.isEmpty()){
this.map.put(beanName,new ClassDefinition(collect,asClass));
}
return bean;
}
#Override
public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
final ClassDefinition definition = this.map.get(beanName);
if(definition != null){
final Class beanClass = definition.asClass;
return Proxy.newProxyInstance(beanClass.getClassLoader(), beanClass.getInterfaces(), (proxy, method, args) -> {
if(definition.isMethodPresent(method)){
System.out.println("Present");
return this.retry(definition.originalMethod(method),bean,args);
} else{
return method.invoke(bean,args);
}
});
} else{
return bean;
}
}
private Object retry(final Method method,final Object originalBean,Object[] argc){
final Repitable repitable = method.getAnnotation(Repitable.class);
int attempts = repitable.attempts();
Throwable exc = null;
while(attempts!=0){
try{
return method.invoke(originalBean,argc);
}catch (final Throwable throwable){
exc = throwable;
attempts--;
this.sleep(repitable.delay(),repitable.timeUnit());
}
}
throw new RuntimeException(exc);
}
#SneakyThrows(InterruptedException.class)
private void sleep(final int time, final TimeUnit timeUnit){
timeUnit.sleep(time);
}
#AllArgsConstructor
private static final class ClassDefinition{
private final List<Method> methods;
private final Class asClass;
boolean isMethodPresent(final Method method){
return this.methods.stream().anyMatch(mthd->mthd.getName().equals(method.getName()));
}
Method originalMethod(final Method method){
return this.methods.stream().filter(mthd->mthd.getName().equals(method.getName())).findFirst().orElseThrow(NullPointerException::new);
}
}
}
And it work but I want to change two things
1)In retry method I want to keep last exception and throw when repeateCount = 0 for this I need to declare null ptr to exc, but I want all my fields to be final. Is it any possible way to rewrite my code?
2) In ClassDefinition I compare Method by name because original equals method of Method class compare by class, I can't do it because original class replaced by proxy, Is it possible to compare two Method's in different way?
For the first part: one option is to use a List of the Throwables. And then throw them something like:
final RuntimeException theError = new RuntimeException(list.get(list.size() - 1));
for (int i = 0; i < list.size() - 1; i++) {
theError.addSuppressed(list.get(i));
}
throw theError;
This also gives the benefit of providing all the failures.
For the latter part, this could be complicated and expensive depending on whether there's gonna be generics, var-args, etc. on some of the methods.
Since you're already using spring, you could try a combination of: AopUtils.getTargetClass and AopUtils.getMostSpecificMethod to get what you want (would need to refactor what you pass to some of the test methods).
Something simple to provide some more (note, not infallible) tests in the vein of what you're already running with though:
return methods.stream().anyMatch(mthd -> {
if (!method.getName().equals(mthd.getName())) {
return false;
}
if (!method.getReturnType().isAssignableFrom(mthd.getReturnType())) {
return false;
}
final Class<?>[] parameterTypes = method.getParameterTypes();
if (mthd.getParameterTypes().length != parameterTypes.length) {
return false;
}
for (int i = 0; i < parameterTypes.length; i++) {
if (!parameterTypes[i].equals(mthd.getParameterTypes()[i])) {
return false;
}
}
return true;
});
I'm sure there are some more checks you can do (Method.getExceptionTypes() to confirm they could override; Method.getDeclaringClass() and work up the tree from there; Method.getModifiers() to determine if it could be overridden, etc.), but that depends on how safe you need to be.

Obtain java.lang.reflect.Executable of current or calling method?

How can one obtain objects of the following types from specific instances of their represented language feature in the code:
java.lang.reflect.Executable
java.lang.reflect.Parameter
Ideally the providing method would be a caller of the obtaining method or the obtaining method itself.
Note that I have found two kinds of answers on SO:
how to get a Parameter from a given Executable object (trivial!)
how to get the name (not signature!) of a method from the call stack
Neither helps to obtain the Parameter to a particular method whose name is not unique.
Consider in particular how this answer and this one to similar questions gloss over the selection of the desired method.
Now, there exists Class.getMethod(String, Class<?>... types) but it does not seem that one could generate the "types" parameter automatically from an existing method definition?
Use case:
public class MyAssertions
{
private static final String DEFAULT_MESSAGE_NOT_NULL = "Parameter must not be null: ";
/* Ideal. */
public static void notNull(Object ref, Parameter param)
{
if(ref == null)
throw new IllegalArgumentException(DEFAULT_MESSAGE_NOT_NULL + param.getName());
}
/* Still okay. */
public static void notNull(Object ref, Executable caller, int param)
{
if(ref == null)
throw new IllegalArgumentException(DEFAULT_MESSAGE_NOT_NULL
+ caller.getParameters()[param].getName());
}
/* Hell no! */
public static void notNull(Object ref, Class<?> caller, String method, Object[] paramTypes, int param)
{
if(ref == null)
throw new IllegalArgumentException(DEFAULT_MESSAGE_NOT_NULL
+ caller.getMethod(method, paramTypes)
.getParameters()[param].getName());
}
}
You can use bytecode utilities to get the bytecode infomation. And then use the line number info in StackTraceElement to get the method.
Here I use javassist.
private static Optional<Method> get(StackTraceElement e) throws NotFoundException, ClassNotFoundException {
Class<?> clz = Class.forName(e.getClassName());
int line = e.getLineNumber();
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get(clz.getName());
return Observable.fromArray(cc.getDeclaredMethods())
.sorted(Comparator.comparing(m -> m.getMethodInfo().getLineNumber(0)))
.filter(m -> m.getMethodInfo().getLineNumber(0) <= line)
.map(Optional::of)
.blockingLast(Optional.empty())
.map(m -> uncheck(() -> clz.getDeclaredMethod(m.getName(),
Arrays.stream(m.getParameterTypes()).map(c -> uncheck(() -> nameToClass(c.getName()))).toArray(Class[]::new))));
}
private static Class<?> nameToClass(String name) throws ClassNotFoundException {
switch (name) {
case "int":
return int.class;
case "short":
return short.class;
case "long":
return long.class;
case "double":
return double.class;
case "float":
return float.class;
case "boolean":
return boolean.class;
case "char":
return char.class;
case "byte":
return byte.class;
case "void":
return void.class;
}
if (name.endsWith("[]")) {
return Array.newInstance(nameToClass(name.substring(0, name.length() - 2)), 0).getClass();
}
return Class.forName(name);
}
uncheck is my utility only ignore the exception in lambda, you can simply use try-catch. see source here
then we test our code
public static void main(String[] args) throws Exception {
// test normal
System.out.println(get(new Exception().getStackTrace()[0]));
// test lambda
Runnable r = () -> System.out.println(uncheck(() -> get(new Exception().getStackTrace()[0])));
r.run();
// test function
testHere(1);
}
private static void testHere(int i) throws Exception {
System.out.println(get(new Exception().getStackTrace()[0]));
}
and output
Optional[public static void xdean.stackoverflow.java.reflection.Q44563354.main(java.lang.String[]) throws java.lang.Exception]
Optional[private static java.util.Optional xdean.stackoverflow.java.reflection.Q44563354.lambda$1() throws java.lang.Exception]
Optional[private static void xdean.stackoverflow.java.reflection.Q44563354.testHere(int) throws java.lang.Exception]
But note that this approach only works for class has bytecode in classpath. If you use dynamic proxy, it doesn't work.
Find complete sample code here
EDIT: You can filter synthetic and bridge methods to get the actual method.

How do I pass a class as a parameter in Java?

Is there any way to pass class as a parameter in Java and fire some methods from that class?
void main()
{
callClass(that.class)
}
void callClass(???? classObject)
{
classObject.somefunction
// or
new classObject()
//something like that ?
}
I am using Google Web Toolkit and it does not support reflection.
public void foo(Class c){
try {
Object ob = c.newInstance();
} catch (InstantiationException ex) {
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
}
}
Here are some good examples on Reflection API
How to invoke method using reflection
import java.lang.reflect.*;
public class method2 {
public int add(int a, int b)
{
return a + b;
}
public static void main(String args[])
{
try {
Class cls = Class.forName("method2");
Class partypes[] = new Class[2];
partypes[0] = Integer.TYPE;
partypes[1] = Integer.TYPE;
Method meth = cls.getMethod(
"add", partypes);
method2 methobj = new method2();
Object arglist[] = new Object[2];
arglist[0] = new Integer(37);
arglist[1] = new Integer(47);
Object retobj
= meth.invoke(methobj, arglist);
Integer retval = (Integer)retobj;
System.out.println(retval.intValue());
}
catch (Throwable e) {
System.err.println(e);
}
}
}
Also See
Java Reflection
public void callingMethod(Class neededClass) {
//Cast the class to the class you need
//and call your method in the class
((ClassBeingCalled)neededClass).methodOfClass();
}
To call the method, you call it this way:
callingMethod(ClassBeingCalled.class);
Construct your method to accept it-
public <T> void printClassNameAndCreateList(Class<T> className){
//example access 1
System.out.print(className.getName());
//example access 2
ArrayList<T> list = new ArrayList<T>();
//note that if you create a list this way, you will have to cast input
list.add((T)nameOfObject);
}
Call the method-
printClassNameAndCreateList(SomeClass.class);
You can also restrict the type of class, for example, this is one of the methods from a library I made-
protected Class postExceptionActivityIn;
protected <T extends PostExceptionActivity> void setPostExceptionActivityIn(Class <T> postExceptionActivityIn) {
this.postExceptionActivityIn = postExceptionActivityIn;
}
For more information, search Reflection and Generics.
Use
void callClass(Class classObject)
{
//do something with class
}
A Class is also a Java object, so you can refer to it by using its type.
Read more about it from official documentation.
This kind of thing is not easy. Here is a method that calls a static method:
public static Object callStaticMethod(
// class that contains the static method
final Class<?> clazz,
// method name
final String methodName,
// optional method parameters
final Object... parameters) throws Exception{
for(final Method method : clazz.getMethods()){
if(method.getName().equals(methodName)){
final Class<?>[] paramTypes = method.getParameterTypes();
if(parameters.length != paramTypes.length){
continue;
}
boolean compatible = true;
for(int i = 0; i < paramTypes.length; i++){
final Class<?> paramType = paramTypes[i];
final Object param = parameters[i];
if(param != null && !paramType.isInstance(param)){
compatible = false;
break;
}
}
if(compatible){
return method.invoke(/* static invocation */null,
parameters);
}
}
}
throw new NoSuchMethodException(methodName);
}
Update:
Wait, I just saw the gwt tag on the question. You can't use reflection in GWT
Adding <T> T as return type worked for me. Ex with json deserialize
public static <T> T fromJson(String json, Class<T> classOfT){
return gson().fromJson(json, classOfT);
}
I am not sure what you are trying to accomplish, but you may want to consider that passing a class may not be what you really need to be doing. In many cases, dealing with Class like this is easily encapsulated within a factory pattern of some type and the use of that is done through an interface. here's one of dozens of articles on that pattern: http://today.java.net/pub/a/today/2005/03/09/factory.html
using a class within a factory can be accomplished in a variety of ways, most notably by having a config file that contains the name of the class that implements the required interface. Then the factory can find that class from within the class path and construct it as an object of the specified interface.
As you said GWT does not support reflection. You should use deferred binding instead of reflection, or third party library such as gwt-ent for reflection suppport at gwt layer.
Se these:
http://download.oracle.com/javase/tutorial/extra/generics/methods.html
here is the explaniation for the template methods.
Have a look at the reflection tutorial and reflection API of Java:
https://community.oracle.com/docs/DOC-983192enter link description here
and
http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html
Class as paramater. Example.
Three classes:
class TestCar {
private int UnlockCode = 111;
protected boolean hasAirCondition = true;
String brand = "Ford";
public String licensePlate = "Arizona 111";
}
--
class Terminal {
public void hackCar(TestCar car) {
System.out.println(car.hasAirCondition);
System.out.println(car.licensePlate);
System.out.println(car.brand);
}
}
--
class Story {
public static void main(String args[]) {
TestCar testCar = new TestCar();
Terminal terminal = new Terminal();
terminal.hackCar(testCar);
}
}
In class Terminal method hackCar() take class TestCar as parameter.

Categories