Java : method that takes in argument any attribute of any class - java

I need to create a method that takes in argument any attribute of any class. But i dont want it to be of type String, to avoid refactoring problems while renaming an attribute and to get the errors in Markers Tab of eclipse, and not while running my application.
Having a class Person :
public class Person {
private String name;
// other attributes...
// getters and setters...
}
Now the needed method :
void getAnAttributeOfAClass( <which_type_or_class_here?> attr_as_arg){
// Now I need to get the name of attribute that would be of class Strin...
}
Is there a function or a method, by which we can specify an attribute?
For example :
Person.class.name
Would it be of class Property ?
EDIT
More exactly (#Smallhacker answer helped me), I need to verify at compile time if the argument is really an attribute of the specified class.
Person.class.name // no compile time error
Person.class.nameXXX // compile time error

The closest to what you want is Reflection API's Field or JavaBeans Introspector API's PropertyDescriptor.
But usually things like that are not needed in Java projects because there are libraries which handle these concerns.
You could pass a Class object along with a String name, then let your method use Introspector internally to read that property.

Not sure I understand you well, but there is a class java.lang.reflect.Field, that has a method getName() that would give your the name of the field.
In your example, to get field name, you would do: Person.class.getDeclaredField("name").
EDIT: to get the value of a field in an object, you would do: field.get(obj);
OK, let's say You have the following variables:
Person person = ...; // initialized with some Person
Field nameField = Person.class.getDeclaredField("name");
Now to get the name of person, you would do:
String personName = (String)nameField.get(person);
Actually, this would throw an exception because name is a private field. You can however bypass the protection by doing:
nameField.setAccessible(true);

Unfortunately, Java lacks an ability to reference member variables in a way that can be analyzed at compile time.
There may be some kind of library to simplify this somewhat, but it wouldn't provide a full solution due to limitations in the language itself.

Maybe java generics can help you with this.
You can do something like:
class YourClass<E> {
void getAnAttributeOfAClass(E attr_as_arg){
// some code
}
}
someVariable = new YourClass<Person>();
someVariable.getAnAtributeOfAClass(someObject); //this will not compile if someObject is not an instance of Person
But I still don't know what you want to do exactly inside the method.

Related

Java - passing an object as a parameter vs. using it's qualified name

I am writing a Java program where a method in one class needs to access a method of an object that is a member of another class. I can do this in at least two different ways, passing as a parameter, or directly accessing the object using the name of the class it is a member of. I find a lot of questions about pass-by-reference vs. pass-by-value, but I can't find anything that addresses this scenario.
Here is some pseudo-code showing what I mean:
// class of object to pass
class MyPrefs {
public String getPref(int i){
String s = ... //some code to get a String indexed by i
return s;
}
}
// class where object is instantiated
class Main {
protected static MyPrefs prefs = new MyPrefs();
}
Here are the two options I am looking at. In a third class, Toolbar, I can do either of these:
// pass as parameter
class Toolbar{
public void applyPrefs(MyPrefs p){
String s = p.getPref(1);
...
}
//or use qualified name of object
class Toolbar{
public void applyPrefs(){
String s = Main.prefs.getPref(1);
...
}
}
It works either way, what I would like to know is what are the merits or problems associated with each method, and if there is another way of doing this that I hadn't considered.
I hope this question doesn't get closed for being opinion-based because technically it is. So, I am not going to claim my answer is based on some undisputed best-practice, but I do believe it is generally accepted as the correct approach.
In my opinion, it would be either a variant of the first, and/or a combination of the two. For example:
public static String getProp(String prop) {
// use java.util.Properties to retrieve the property.
}
This works well when your application has a single property file. In cases you have multiple property files, you need to override this method and pass the path to the correct file.
public static String getProp(String filename, String prop) {
// use java.util.Properties to retrieve the property.
}
Where filename could be just the file name or the fully qualified name (with the path). I tend to keep all my property files in the same folder, so I "hard-code" the path and use that as the base location for my files, so most of the time when using this approach, I only need the actual file name.
I also have created utility methods to obtain specific properties where the name of the method implies what property I am obtaining. This is useful for people that are not too familiarized with the property keys.
public static String getXYZProp() {
// use java.util.Properties to load the properties.
return prop.getProperty("XYZ");
}
Alternatively, you should take advantage of the genetic method you created to do the same
public static String getXYZProp() {
return getProp("XYZ");
}
Or even something like
public static String getXYZProp() {
return getProp("someProps.properties", "XYZ");
}
It is OK to have multiple method that ultimately do the same thing. Think that some users will call the generic ones because they are more familiarized with the property keys while others will rely on method with names that help them figure out what properties they need to retrieve.

Is there a better way of obtaining an object's field getters other than java reflection api or i am misusing PropertyDescriptor's getReadMethod?

Context:
I am building an Excel document in a generic way with data i receive from a SOAP service endpoint. I receive the data as a List and i have the model (JavaBeans) for every Object i receive according to the method called.
So I set the first row of the sheet as the header from the object's fields (getDeclaredFields).
Then i go on filling up the column row by row with values from the list of objects.
The problem:
I haven't found a workable way of getting the object's field values.
I have tried using the getters with the java reflection API with something like this answer's https://stackoverflow.com/a/5503534/4807777 findGetterName , findGetter however the PropertyDescriptor's getName sometimes is a different letter case from the field name as obtained from the class's getDeclaredFields.
Let's say i overcome this by capitalizing both names, the getReadMethod stil fails - doesn't seem to find getters for the fields which use the is prefix (i.e boolean fields). I don't know if i am misusing it or it is a bug (debugging the getReadMethod appears to only work with the get prefix, even though it appears to handle the is prefix case for booleans).
Considering the fact the fields aren't accesible outside of the object's package, therefore solely through invoking getters.
Is there a better way of obtaining the object's field getters or i am missing something with the getter methods?
Update: Spring's BeanUtils seems to be better for getting the properties with it's getPropertyDescriptors is better than java Class's getDeclaredFields, when the JavaBean properties are mapped to XML elements.
This fixes the different letter cases situation. However it stil doesn't find it's readMethod when not using the get prefix.
Edited - to show an example of getReadMethod not finding the is prefixed getter, as Laszlo Lugosi requested.
A simple class:
class Test {
private String assignmentType;
private Boolean conserved;
public String getAssignmentType() {return assignmentType;}
public void setAssignmentType(String assignmentType) {this.assignmentType = assignmentType;}
public Boolean isConserved() {return conserved;}
public void setConserved(Boolean conserved) {this.conserved = conserved;}
}
Run this with the findGetter and findGetterName written in the answer linked above:
{
Test obj = new Test();
obj.setAssignmentType("someType");
obj.setConserved(true);
Field[] fields = obj.getClass().getDeclaredFields();
String fieldName;
for (int i=0;i<fields.length;i++){
fieldName = fields[i].getName();
java.lang.reflect.Method method;
Object val = null;
try {
method = obj.getClass().getMethod(findGetterName(obj.getClass(),fieldName));
val = method.invoke(obj);
}
catch (Exception e){
e.printStackTrace();
}
}
}
Edited 2
While i could simply write a getReadMethod following the convention Laszlo Lugosi highlighted i do prefer finding an API for handling accessors.
As you know only the object field name, and JavaBean has convention, you can figure out the getters easily. The rules are getUpperfieldname() and isUpperfieldname if field is boolean. And you can find out the return type as well from the object field.

How to get the name of a property as string?

I have a class Car that has a Field named trunk. How can I retrieve that name only with the property that is assigned to it and without any fixed String.
Something working like this fiction would be great:
System.out.println(new Car().getTrunk().getField().getName());
Output:
trunk
I don't want to use a fixed String to retrieve the Field and it's name because that would not refactor well. If I decide to rename from trunk to boot I want this to be handled completely by my IDE's refactoring tool.
UPDATE Car class:
public class Car{
String trunk;
// getters + setters
}
BACKGROUND:
I want to use Primefaces' Dynamic Columns for a CRUD-UI for several entities which uses a columnTemplate containig the names of the Fields/properties to be evaluated by Expression Language.
Consider introducing a enum holding all the properties (without values), for example
enum CarProperty {
TRUNK, HOOD, WHATEVER;
}
and storing them in Car as EnumMap:
class Car {
private Map<CarProperty, String> propsToValues = new EnumMap<>(...);
public String getValue(CarProperty property) { ... }
}
property name could be accessed by
((CarProperty) anyPropery).toString()
And obviously it is easy to refactor
Is not a good idea access to the property name.
With reflection you are breaking OOP principles.
getTrunk() not allways need to access a trunk property
You can have a
private Trunk trunk;//remember to change the TRUNK_FIELD
public static final TRUNK_FIELD = "trunk"
but... try to avoid this solution.

How to convert String type to Class type in java

I want to print all the class names in a package and also to print the corresponding attributes and their data types in each package.
In one code, I am able to get the classnames in the form of string.
In another code I am able to get the attributes and their data types using Classname.class.getAttribute();
However I want to merge the two codes. Since in the first code I got the classnames in the form of string , I can't use Classname.class.getAttribute() since here Classname will be of type String.
So I want a method which will convert the "Classname" from String type to Class type.
I tried Class.forName() but it didn't work.
Class<?> classType = Class.forName(className);
Make sure className is fully qualified class name like com.package.class Also, please share your error message that you see.
If the fully-qualified name of a class is available, it is possible to get the corresponding Class using the static method Class.forName().
Eg:
Class c = Class.forName("com.duke.MyLocaleServiceProvider");
Note: Make sure the parameter you provide for the function is fully qualified class name like com.package.class
Check here for any reference.
EDIT:
You could also try using loadClass() method.
Eg:
ClassLoader cl;
Class c = cl.loadClass(name);
It is invoked by the Java virtual machine to resolve class references.
Syntax:
public Class<?> loadClass(String name)
throws ClassNotFoundException
For details on ClassLoader check here
Here
is an implementation of ClassLoader.
Please try as following.
String str = "RequiredClassName";
Class <?> Cref = Class .forName("PackageNaem."+str );

Java Using Strings as Code

Okay, so, here's what I have in code:
public void makeObject(int i){
String s = getString(i); //This returns the name of a class
new s(); //This is what I want to do
}
Can I do this?
No you can't do this, but what you're probably looking for is called 'reflection'.
Look at these series of (free) slides: http://www.slideshare.net/CiaranMcHale/java-reflection-explained-simply especially slide 11, but read the ones before that as well. It will give you an idea of what reflection is and a way to make a class by knowing the name (as a string) and how to instantiate a new instance of that class.
You can also find methods and fields by name, you can even modify existing classes in code.
Edit: for example the following code will return a class by string name
Class cls = Class.ForName("MyPackage.MyClassName");
return cls.NewInstance();

Categories