I would like to access the usual reflection properties of a specific method without relying on Strings.
Is there any way to get from the method-Identifier to its reflection properties, like parameter types?
void run() {
java.lang.reflect.Method m = myMethod.getMethod(); // how?
Class<?>[] argClasses = m.getParameterTypes();
}
int myMethod(String arg) {
// ...
}
The piece myMethod.getMethod() is not valid. It is my way of saying "get from the method-identifier to the java.lang.reflect.Method object".
The string-way I do not want to use would be similar to m = getClass().getDeclaredMethod("myMethod", ...)
I use myMethod like a regular identifier and not as a String, i.e. "myMethod". I think this would be beneficial for refactoring, where someone renames myMethod to hisMethod -- the relation via the String-name would break, where the relation via the identifier would be refactored as well.
In java methods aren't first class citizens, so there is no solutions in Java for this problem.
Yet I had a similar problem and forged a small tool named picklock for this purpose.
Related
C# 6.0 introduced the nameof() operator, that returns a string representing the name of any class / function / method / local-variable / property identifier put inside it.
If I have a class like this:
class MyClass
{
public SomeOtherClass MyProperty { get; set; }
public void MyMethod()
{
var aLocalVariable = 12;
}
}
I can use the operator like this:
// with class name:
var s = nameof(MyClass); // s == "MyClass"
// with properties:
var s = nameof(MyClass.OneProperty); // s == "OneProperty"
// with methods:
var s = nameof(MyClass.MyMethod); // s == "MyMethod"
// with local variables:
var s = nameof(aLocalVariable); // s == "aLocalVariable".
This is useful since the correct string is checked at compile time. If I misspell the name of some property/method/variable, the compiler returns an error. Also, if I refactor, all the strings are automatically updated. See for example this documentation for real use cases.
Is there any equivalent of that operator in Java? Otherwise, how can I achieve the same result (or similar)?
It can be done using runtime byte code instrumentation, for instance using Byte Buddy library.
See this library: https://github.com/strangeway-org/nameof
The approach is described here: http://in.relation.to/2016/04/14/emulating-property-literals-with-java-8-method-references/
Usage example:
public class NameOfTest {
#Test
public void direct() {
assertEquals("name", $$(Person.class, Person::getName));
}
#Test
public void properties() {
assertEquals("summary", Person.$(Person::getSummary));
}
}
Sadly, there is nothing like this. I had been looking for this functionality a while back and the answer seemed to be that generally speaking, this stuff does not exist.
See Get name of a field
You could, of course, annotate your field with a "Named" annotation to essentially accomplish this goal for your own classes. There's a large variety of frameworks that depend upon similar concepts, actually. Even so, this isn't automatic.
You can't.
You can get a Method or Field using reflection, but you'd have to hardcode the method name as a String, which eliminates the whole purpose.
The concept of properties is not built into java like it is in C#. Getters and setters are just regular methods. You cannot even reference a method as easily as you do in your question. You could try around with reflection to get a handle to a getter method and then cut off the get to get the name of the "property" it resembles, but that's ugly and not the same.
As for local variables, it's not possible at all.
You can't.
If you compile with debug symbols then the .class file will contain a table of variable names (which is how debuggers map variables back to your source code), but there's no guarantee this will be there and it's not exposed in the runtime.
I was also annoyed that there is nothing comparable in Java, so I implemented it myself: https://github.com/mobiuscode-de/nameof
You can simply use it like this:
Name.of(MyClass.class, MyClass::getProperty)
which would just return the String
"property"
It's also on , so you can add it to your project like this:
<dependency>
<groupId>de.mobiuscode.nameof</groupId>
<artifactId>nameof</artifactId>
<version>1.0</version>
</dependency>
or for Gradle:
implementation 'de.mobiuscode.nameof:nameof:1.0'
I realize that it is quite similar to the library from strangeway, but I thought it might be better not to introduce the strange $/$$ notation and enhanced byte code engineering. My library just uses a proxy class on which the getter is called on to determine the name of the passed method. This allows to simply extract the property name.
I also created a blog post about the library with more details.
Lombok has an experimental feature #FieldNameConstants
After adding annotation you get inner type Fields with field names.
#FieldNameConstants
class MyClass {
String myProperty;
}
...
String s = MyClass.Fields.myProperty; // s == "myProperty"
Is there anyway to find a property descriptor recursively using Java reflection?
Imagine a scenario where a User class has a field called profile, which itself is another class which has the email attribute.
By having the user object, I need to have access to profile.email so the desirable method signature should be something similar to this:
public PropertyDescriptor findPropertyDescriptor(Class<?> clazz, String path)
{
// Code!
}
And the call would be something like:
findPropertyDescriptor(User.class, "profile.email")
I'm also thinking that calls like below should be possible as well:
findPropertyDescriptor(User.class, "addresses[2].postCode")
Since nobody has come up with a solution, I have to answer my question here.
Thanks to Spring, this has been already implemented:
public static <T> PropertyDescriptor getPropertyDescriptor(T rootObject, String path)
{
BeanWrapperImpl wrapper = new BeanWrapperImpl(rootObject);
return wrapper.getPropertyDescriptor(path);
}
In addition to the requirement, mentioned in the question, it also supports Maps.
There are two classes A and B in the same package.
how to get name of the functions of class A called by class B.
Restriction is that the code of A and B cannot be modified.
You cannot use Java reflection to do static code analysis tasks like this. The reflection APIs don't provide the information that is needed.
Off the top of my head, I can think of two approaches that will work:
If you only have the ".class" files, then you can use a bytecode library such as BCEL to load the classes and traverse them to identify all of the method calls.
If you have source code, you could also use some existing Java parser library to create ASTs for your code and analyse them.
(The first approach is probably simpler if all you want is a list of class and method names.)
Reflection can be very useful, but very complicated if you don't understand it.
If you have the name of the class, and want to print the methods:
Class c = Class.forName(the_class_name);
for(Method m : c.getMethods()) {
System.out.println(m.toString());
}
If you want the name of a class given any Object:
String className = the_object.getClass().getName();
A combination of the two could look like this:
for(Method m : the_object.getClass().getMethods())
System.out.println(m.toString());
I think what you are asking for is the names of all the methods from A that B calls.
That can't really be done with reflection, mostly because Java doesn't provide any method for doing this.
The API, as always, provides more information. If you look through there, you might come up with a simple work around.
"Class of all the functions called by class A or class B" is confusing. But, If You want to get the class and function name of caller to a method detectsName described in your class A , then following code will be useful to you.
public class A {
public void detectsName() {
Throwable t = new Throwable();
StackTraceElement traceLine = t.getStackTrace()[1];
// t.printStackTrace();
String className = traceLine.getClassName();
String methodName = traceLine.getMethodName();
int lineNumber = traceLine.getLineNumber();
System.out.println(className);
System.out.println(methodName);
System.out.println(lineNumber);
}
}
If you call this method from any other class say - B, it will be detected.
public class B {
public static void main(String[] args) {
A a = new A();
a.detectsName();
}
}
Dependency Finder can do queries for this. Its approach is to generate meta data in XML and then use regexp based comparison. You may be specifically looking for feature called 'closure' with inbound reference..
Is there any way to read and print the object attribute dynamically(Java) ? for example if I have following object
public class A{
int age ;
String name;
float income;
}
public class B{
int age;
String name;
}
public class mainA{
A obj1 = new A();
method(A);
method(B);
}
the output should be like
While running method(A):
Attribute of Object are age,name,income;
While executing method(B):
Attribute of Objects are age,name;
My question is I can pass various object in method(), is there any way I can access the attribute of the differnt object in general.
You want to use The Reflection API. Specifically, take a look at discovering class members.
You could do something like the following:
public void showFields(Object o) {
Class<?> clazz = o.getClass();
for(Field field : clazz.getDeclaredFields()) {
//you can also use .toGenericString() instead of .getName(). This will
//give you the type information as well.
System.out.println(field.getName());
}
}
I just wanted to add a cautionary note that you normally don't need to do anything like this and for most things you probably shouldn't. Reflection can make the code hard to maintain and read. Of course there are specific cases when you would want to use Reflection, but those relatively rare.
Using org.apache.commons.beanutils.PropertyUtils we can do this. If the proper getters and setters are defined for the bean we can also dynamically set the value:
import org.apache.commons.beanutils.PropertyUtils;
import java.beans.PropertyDescriptor;
public class PropertyDescriptorTest {
public static void main(String[] args) {
// Declaring and setting values on the object
AnyObject anObject = new AnyObject();
anObject.setIntProperty(1);
anObject.setLongProperty(234L);
anObject.setStrProperty("string value");
// Getting the PropertyDescriptors for the object
PropertyDescriptor[] objDescriptors = PropertyUtils.getPropertyDescriptors(anObject);
// Iterating through each of the PropertyDescriptors
for (PropertyDescriptor objDescriptor : objDescriptors) {
try {
String propertyName = objDescriptor.getName();
Object propType = PropertyUtils.getPropertyType(anObject, propertyName);
Object propValue = PropertyUtils.getProperty(anObject, propertyName);
// Printing the details
System.out.println("Property="+propertyName+", Type="+propType+", Value="+propValue);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
To set the value of a particular property:
// Here we have to make sure the value is
// of the same type as propertyName
PropertyUtils.setProperty(anObject, propertyName, value);
Output will be:
Property=class, Type=class java.lang.Class, Value=class genericTester.AnyObject
Property=intProperty, Type=int, Value=1
Property=longProperty, Type=class java.lang.Long, Value=234
Property=strProperty, Type=class java.lang.String, Value=string value
You can use reflection to get every field from your object (if security configuration allows you).
If you need it not for the sake of self-education, then it may be worth using ReflectionUtils from Apache Commons.
You can use reflection, but the API is not very nice to use. But what you are trying to do is not at all object-oriented. The A and B should have method "print yourself" which would output their values (you should specify the method in superclass/interface to call the method using polymorphism).
I think I would consider a different approach.
If you really want to treat these like data is there any reason they couldn't be hashtables (Do they have associated code)?
Reflection will do it but it's a last resort--you should always seriously consider different approaches before dropping to reflection.
Cases where you must access variables like that exist--like database mapping (Hibernate) and injection (Spring). You might want to consider if a packaged solution like that fits your need so that future programmers can understand what you did without learning everything about your specific solution.
Also, Spring injection can do things that might fit your needs.
Also also if you are going to use reflection, seriously consider annotations so that you aren't tying your functionality to what should be simple arbitrary attribute names.
While setting up Hudson for continous integration testing (on a JeOS server), I've come across some strange behaviour I'm hoping the fine people at SO can explain to me.
Our unit tests depend heavily on the use of domain objects, with lots of properties that must be set (due to null constraints in the database). In order to keep our tests readable, we have created a class InstantiationUtils that can instantiate an object and set a series of properties through reflection:
public static <T> T newInstance(final Class<T> type, final KeyValuePair<?>... propertyValues) {
return ReflectionUtils.reflectionOperation(new ReflectionOperation<T>() {
#Override
public T perform() throws Exception {
T object = type.newInstance();
for (KeyValuePair<?> propertyValue : propertyValues) {
String propertyName = propertyValue.getKey();
Object value = propertyValue.getValue();
String setterName = "set" + StringUtils.capitalize(propertyName);
ReflectionUtils.invoke(object, setterName, value);
}
return object;
}
});
}
public static void invoke(final Object target, final String methodName, final Object... params) {
List<Class<?>> parameterTypes = ListUtils.map(asList(params), "class");
Class<?> targetClass = target.getClass();
Method method = MethodUtils.getMatchingAccessibleMethod(targetClass, methodName,
parameterTypes.toArray(new Class<?>[] {}));
invoke(target, method, params);
}
public class Foo {
private String foo;
public void setFoo(final String foo) {
this.foo = foo;
}
}
public class Bar extends Foo {
private String bar;
public void setBar(final String bar) {
this.bar = bar;
}
}
The person who wrote this code unfortunately no longer works for us, but as far as I can see, there is nothing wrong with it. Which is also true for Windows - we use InstantiationUtils throughout our unit tests without any problems.
Linux, however, is different. It turns out that in Linux, the newInstance() method only works for direct (i.e. not inherited) members of the class we want to instantiate.
InstantiationUtils.newInstance(Bar.class, "bar", "12345"); will work, while InstantiationUtils.newInstance(Bar.class, "foo", "98765"); will fail on Linux, with the following exception:
xxx.xxx.xxx.ReflectionUtils$ReflectionException: java.lang.NoSuchMethodException: Property 'foo' has no setter method
On Windows, both calls will work (I know the newInstance signature doesn't match; we have several overloaded newInstance() methods that convert the parameters to KeyValuePairs).
I had a hard time accepting that inherited public methods are treated differently, so I have tested this in all ways I can think of. And it always ends up with the conclusion that under Linux, at least with the above usage of Reflection, we can't access public inherited methods.
On Windows, I use Sun's JRE 1.6.0.11, in Linux it's also Sun, but version 1.6.0.7.
Can anyone confirm if this is correct? Or is the Reflection usage somehow flawed?
You are using MethodUtils, and it has some limitations :
Known Limitations
Accessing Public Methods In A Default Access Superclass
There is an issue when invoking public methods contained in a default access superclass. Reflection locates these methods fine and correctly assigns them as public. However, an IllegalAccessException is thrown if the method is invoked.
Another thing to check is if the setFoo() method is overloaded, this may also cause the problem...
Could it be that the SecurityManager settings are different between the different Java runtimes?
Certainly I doubt that this is a platform issue - it is almost certainly something to do with the JRE version/setup between the two environments
You really need to post the source code to MethodUtils.getMatchingAccessibleMethod
A couple of things to try...
On Linux, try comping the code without a reflective call to getFoo() - if it will not compile then reflection has no hope of working (well it does depending on how yoiu setup the CLASSAPTH at runtime...)
Try adding the code below and run it on both Linux and Windows.
final Properties properties;
properties = System.getProperties();
for(final Entry<Object, Object> entry : properties.entrySet())
{
System.out.println(entry.getKey() + " " + entry.getValue());
}
The check the output to make sure that you are using the smae JDK/JRE. Also check to make sure that the classpath is correct so that you are actually loading what you think you are loading.
Mystery partially solved:
MethodUtils.getMatchingAccessibleMethod() apparently works differently on Linux and Windows.
By using MethodUtils.getAccessibleMethod() instead, it works. Why, I don't know, but I'm guessing that MethodUtils somehow misinterprets the parameter list when figuring out what signature the Method should have.
I'd like to spend more time investigating this, but as always there are things to do and projects to deliver, so I just have to accept that getAccessibleMethod works, and move on :-)
Thanks to everyone for their input!
Which JVM do you use on Linux, Sun, GCJ etc? If you use something else than Sun's JVM, you could try installing it and see if that makes a difference.
Do you have different locales? StringUtils.capitalize(propertyName) may be producing different output.
Have you checked your CLASSPATH ? Are you picking up different versions of the class you want to instantiate depending on which platform you're on ? (e.g. old codebases lying around etc.?)