I want to create some utility method and I want it to be able to work on different objects as long as they can provide an Integer property that is read/write.
I know the "Standard" way would be to:
declare some interface IProvidesAccessToInteger that has setInteger and getInteger.
declare MyUtility.doSomethingWonderful(IProvidesAccessToInteger obj)
make calls to obj.setInteger and obj.getInteger.
But this has a very strong downside that it requires the cooperation of all those classes that I want MyUtility to work with and not only that but even if some class wants to cooperate MyUtility would still only be able to .doSomethingWonderful() to just a single predetermined field of that classes.
I am looking for some syntax that would allow for something like MyUtility.doSomethingWonderful(T obj, Method<Integer> getter, Method<Integer,Integer> setter) maybe using generics somehow to specify the requirement that objhas two methods that get set and set an Integer and have some way to call them on the instance of obj.
It might also be interesting to do something similar with static methods that do not need an object.
UPDATE:
As I was pointed to reflection, I want to clarify that I know close things can be done using reflection.
However since I don't need to resolve the actual interface in runtime I had the hope that JAVA has some way to specify sort of an "Interface fulfilment map" such that If my requirement would be an object that has two methods int ?() and void ?(int) I could specify something like .doSomethingWonderful(?<int getter(),void setter(int)> obj) and call it once with some object1 that has int getInt() and void setInt(int) and once with some other object2 that has int getIntValue() and void setIntValue(int) by specifying in the calls that object fulfills the requirements for getInteger by getInt and fulfills the requirements for setInteger by setInt and so on. maybe with a call syntax like `.doSomethingWonderful((?)object1)
At least in theory I think it should be possible to do all at compile time and not require any runtime reflection.
maybe the right name for this would by an anonymous interface.
that said, I accept that a runtime solution via reflection might also be a solution.
The thing closest to your description will come with Java 8. You still need interfaces but the caller does not need to care about them and even better, there are plenty of default interfaces for typical tasks. For example, you can define a method like this:
static void increment(IntSupplier in, IntConsumer out)
{
out.accept(in.getAsInt()+1);
}
and use it like that to access different properties of an object:
class ClassWithInProperties {
int a, b;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public int getB() {
return b;
}
public void setB(int b) {
this.b = b;
}
#Override
public String toString() {
return "a="+a+", b="+b;
}
}
ClassWithInProperties obj=new ClassWithInProperties();
increment(obj::getA, obj::setA);
increment(obj::getA, obj::setA);
increment(obj::getB, obj::setB);
System.out.println(obj);
or with static methods:
public class Test {
static int DATA = 42;
static int getData() {
return DATA;
}
static void setData(int i) {
DATA=i;
}
}
increment(Test::getData, Test::setData);
System.out.println(DATA);
Your getter and setter are pretty Paradigm of reflection. But that would be import much risk and lose performance. Interface Oriented Programming are pretty common "standard" to handle this scenario.
You cannot do this with generics.
You can do this with reflection. Using a utility such as BeanUtils would of course be easier, but you can write it by hand too.
public void doSomethingWonderful(final Object in, final String fieldName)
throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
final String upperCased = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
final Method getter = in.getClass().getMethod("get" + upperCased);
final Method setter = in.getClass().getMethod("set" + upperCased, Integer.TYPE);
//to invoke getter
final int val = (int) getter.invoke(in);
//to invoke setter
setter.invoke(in, val);
}
I have assumed that you are using an int rather than an Integer, you will need to change the code slightly in the latter case.
You can see that it throws a massive number of exceptions, I would recommend wrapping them all in a custom exception type to simplify client code.
EDIT
Op wants the break down the method into three overloaded methods:
public void doSomethingWonderful(final Object in, final String fieldName)
throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
final String upperCased = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
doSomethingWonderful(in, "get" + upperCased, "set" + upperCased);
}
public void doSomethingWonderful(final Object in, final String getterName, final String setterName)
throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
final Method getter = in.getClass().getMethod(getterName);
final Method setter = in.getClass().getMethod(setterName);
doSomethingWonderful(in, getter, setter);
}
public void doSomethingWonderful(final Object in, final Method getter, final Method setter)
throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//to invoke getter
final int val = (int) getter.invoke(in);
//to invoke setter
setter.invoke(in, val);
}
Related
In Java, is it possible to access class defined in method by some means (reflections or so)? And How?
For example, i want to create instance of InnerClass in example below:
class Example {
public void outerMethod() {
class InnerClass {
double d = 0;
}
}
public void testMethod() {
outerMethod::InnerClass instance = new outerMethod::InnerClass();
}
}
Thanks for answers.
Technically it is possible.
Practically this is a kind of a hack and you should avoid such practice in the production code.
Example:
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
class Example {
public void outerMethod() {
class InnerClass {
private double d = 7.62;
#Override
public String toString() {
return String.format("[%s] d = %f", this.getClass().getName(), d);
}
}
}
public void testMethod() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
final Class<?> clazz = Class.forName("Example$1InnerClass");
final Constructor<?> constructor = clazz.getDeclaredConstructor(Example.class);
constructor.setAccessible(true);
final Object instance = constructor.newInstance(this);
System.out.println(instance);
}
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
Example instance = new Example();
instance.testMethod();
}
}
Here we first get Class<?> for our local class by their name.
The local class name generation rules is a compiler implementation detail and may vary. AFAIK javac and ECJ use different approaches.
Then we get constructor of our class of interest via reflection.
Since class does not define constructor explicitly compiler generate it automacically and this constructor is not public. So we use getDeclaredConstructor() method here.
Since this class is not static (local classes cannot be defined static) the first and the only parameter of constructor is outer class reference. Example in our case.
After that we creating instance of a class by calling constructor.newInstance(this)
this is passed as a parameter to the constructor. See note above about constructor parameters.
Finally, we print just created object implicitly invoking InnerClass::toString()
No, that is not possible. Names declared inside a method can only be referenced inside the method itself. Local classes (which your case is an example) are defined in section 14.3 of the Java 8 Language Specification.
https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-Block.
I'm trying to delegate a private method in bytebuddy - but how do I call the 'overriden' version? If I have
TypePool typepool = TypePool.Default.ofClassPath();
new ByteBuddy()
.rebase(typepool.describe("Foo").resolve(), ClassFileLocator.ForClassLoader.ofClassPath())
.method(named("getNum"))
.intercept(MethodDelegation.to(typepool.describe("FooInterceptor").resolve()))
.make()
.load(typepool.describe("Foo").resolve().getClass().getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
Foo foo1 = new Foo();
System.out.println("Foo says " + foo1.getMessage());
and
public class Foo
{
private int num = 0;
public String getMessage()
{
return "Message is Foo " + getNum();
}
private int getNum()
{
return num++;
}
}
and
import net.bytebuddy.implementation.bind.annotation.Super;
public class FooInterceptor
{
public static int getNum(#Super Foo foo)
{
// This won't work!
return foo.getNum() + 100;
}
}
As far as the compiler is concerned, even if #Super Foo foo is going to become something else at runtime, I'm not allowed to call a private method on Foo. I don't seem to be able to reflect/invoke getNum() either - whatever #Super Foo becomes, it doesn't seem to have a getNum() method (although it does have a getMessage() method).
Can someone perhaps point me in the right direction here?
Update:
#Rafael's answer is technically a very good solution to the question I asked; unfortunately I guess my example was bad. Mea culpa. What I was really hoping for was a solution that would let me manipulate the arguments to getNum() before passing them. But it turns out that for my application I might be able to get by without doing that, so if that changes then perhaps I'll post that exact example.
Update 2:
Question completely answered! Hurray!
You probably want to use #SuperCall Callable. This would allow you to do invoke the overridden method from the method itself. It does however not allow you to invoke any method from within a proxied class.
public class FooInterceptor
{
public static int getNum(#SuperCall Callable<Integer> c) throws Exception
{
// This will work!
return c.call() + 100;
}
}
If you need to manipulate the arguments, this is possible by using the Morph annotation. It allows you to invoke a method whilst supplying explicit arguments:
public interface Morphing<T> {
T invoke(Object[] args);
}
public class FooInterceptor
{
public static int getNum(#Morph Morphing<Integer> m, #AllArguments Object[] args)
{
// This will work!
return m.invoke(args) + 100;
}
}
Note that you need to install the interface explicitly:
MethodDelegation.to(FooInterceptor.class)
.appendParameterBinder(Morph.Binder.install(Morphing.class));
I was wondering, what if I have the following case:
public class MyObject<T> {
private T myTObject;
public void setMyTObject(T m) {
myTObject = m;
}
public T getMyTObject() {
return myTObject;
}
}
And now I want that class to react something like these:
MyObject<ObjectA> objA = new MyObject<ObjectA>();
ObjectA objAInstance = objA.getObjectA();
or
objA.setObjectA(otherObjectAInstance);
Is there a way to dynamically create methods based on T class name?
Or should I better extend ObjectA to MyObject and create those methods using super.get/seMyObject()?
For clarification:
The idea is to have a getter and setter method generated dynamically
so, if I create an instance of:
MyObject<A> objA = new MyObject<A>();
I would be able to call method:
objA.getA();
getA() will call internally getMyTObject() or just return myTObject
so MyObject may react based on T class and generate the corresponding method.
I have updated member attribute to differentiate from MyObject class, it may lead to confusion. also fixed Method return and parameter Type.
Update Answer is completely changed.
Sounds like you want to use something through reflection. The problem with truly dynamically generating the method names is that, as others have commented, it would have to be done in bytecode which means that other classes trying to use your dynamic classes don't have Java code to refer to. It can be done, but it would be a mess.
Instead, here's a possible solution using generics. Please note that this is something of a quick and dirty hack; I leave it to you to refine it. You define an interface with the getters and setters you want, with whatever you want them named:
package com.example.dcsohl;
public interface IntegerWrapper {
public Integer getInteger();
public void setInteger(Integer i);
}
And then, to use them, you use this class to do the heavy lifting. Note that the error checking isn't very good; for example, it doesn't check that "getFoo" at all corresponds to the name of the class being passed in; nor does it validate that the "foo" in "getFoo" matches the "setFoo" method. This is something you can improve on.
package com.example.dcsohl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyWrapper<T> implements InvocationHandler {
Class<T> clazz = null;
T myvalue = null;
public static <W,T> W getInstance(Class<W> clazz, Class<T> clazz2) {
ProxyWrapper<T> wrapper = new ProxyWrapper<T>();
wrapper.setClass(clazz2);
#SuppressWarnings("unchecked")
W proxy = (W)Proxy.newProxyInstance(clazz.getClassLoader(), new Class[] {clazz}, wrapper);
return proxy;
}
private void setClass(Class<T> clazz) {
this.clazz = clazz;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// getter has no arguments
if (method.getName().startsWith("get") && (args == null || args.length == 0)) {
return myvalue;
} else if (method.getName().startsWith("set") && args.length == 1) {
Object o = args[0];
if (o.getClass().isAssignableFrom(clazz)) {
#SuppressWarnings("unchecked")
T val = (T)o;
myvalue = val;
return null;
}
} else {
throw new Exception();
}
return null;
}
}
Finally, to use it, here's a quick sample:
package com.example.dcsohl;
public class Main {
public static void main(String[] args) {
Integer foo = 5;
IntegerWrapper wrapper = ProxyWrapper.getInstance(IntegerWrapper.class, Integer.class);
wrapper.setInteger(foo);
Integer bar = wrapper.getInteger();
System.out.println(bar);
}
}
It seems like a lot of work just to avoid writing simple wrapper classes, and you'd be right, but reflection has its uses, and this is something of a sampler.
I want to call a method by using a string. I get that this is possible; from what I understand reflection is the way to go. However, I'm having a hard time getting it to work and this is what I want.
For instance:
String method ="punch";
int punch(){
return 1;
}
I want to call the method by the string name. Can someone show me an example?
public class foo {
String method ="punch";
int punch() {
return 1;
}
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Class<?> myClass = Class.forName("foo");
Method myMethod = myClass.getMethod("punch");
Object retObject = myMethod.invoke(null);
}
}
What do I need to do so that I can get the number 1?
Object retObject = myMethod.invoke(null);
That would only work for a static method.
For an instance method, you need to pass in the instance that you want to invoke the method on.
Object retObject = myMethod.invoke(instanceOfFoo);
Also, the method may need to be public (or be made accessible separately).
Guys is there a way to pass a Annotation as a direct parameter (rather by doing all the reflection overhead)? For example in the following code, I have a annotation Number that holds a int value, I want to pass as a parameter to the addImpl method, how can I do that (other than by reflection)?
Code Snippet:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
public #interface Number {
int value();
}
public void add(int x2) {
addImpl(#Number(value = 10) lol, x2);
}
public void addImpl(Number a, int b) {
System.out.println(a.value() + b);
}
public static void main(String[] args) {
new TestClass().add(3);
}
Yes, you can pass around annotations like this (just as if they were normal interfaces).
The only thing you can't do is to create instances of that interface at runtime. You can only take existing annotations and pass them around.
import java.lang.annotation.*;
public class Example {
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public static #interface Number {
int value();
}
#Number(value = 42)
public int adder(final int b) throws SecurityException, NoSuchMethodException {
Number number = getClass().getMethod("adder", int.class).getAnnotation(Number.class);
return addImpl(number, b);
}
public int addImpl(final Number a, final int b) {
return a.value() + b;
}
public static void main(final String[] args) throws SecurityException, NoSuchMethodException {
System.out.println(new Example().adder(0));
}
}
You can do it like:
public void add(int x2) {
addImpl(new Number() {
#Override
public int value() {
return 10;
}
#Override
public Class<? extends Annotation> annotationType() {
return Number.class;
}
}, x2);
}
Since Number is basically an interface, you have to create an instance of an anonymous class that implements that interface, and pass that to the method.
Although why you want to do this is beyond me. If you need to pass a value to something, you should really use a class.
To the best of my knowledge, there's no such thing as an "annotation literal" as you want to use it in your add implementation.
I think the closest thing to this would be to declare the method to take a parameter of type java.lang.annotation.Annotation - but then you'd still need to obtain those instances via reflection from the class/method objects.
Number is also a good old interface, you can implement a concrete class.
Guys, this is useful. While a module mostly deals with annotations which are fixed at compile time, sometimes we need to feed it other info obtained at runtime from other sources(like xml, gush!) We can over-architect the thing, or we can simply creat a runtime object of the annotaion type.
If you need to pass annotation in test, you can make mock of it.
For example test of JSR 303 validator could look like this:
public void test() {
final TextLengthValidator validator = new TextLengthValidator();
validator.initialize(mock(TextLength.class));
final boolean valid = validator.isValid("some text", mock(ConstraintValidatorContext.class));
assertThat(valid, is(true));
}