Reputation: 7788
I'm trying to figure out how to dynamically call a method. I have a string that describes the method name, but I'm not sure how to do it. I thought this could be done with reflection, but haven't had any success. Example
set.add(vehicleConfiguration.getVehicleYear.getName());
set.add(vehicleConfiguration.getVehicleMake().getName());
set.add(vehicleConfiguration.getVehicleModel().getName());
You'll notice all the method calls are the same with the exception of the getVehicleYear, etc
I have a string that describes the method names, just not sure how to use it.
I got as far as this with reflection, but failed.
set.add(Class.forName("VehicleConfiguration").getMethod("vehicleMake", null).getName());
Thanks in advance.
Upvotes: 3
Views: 19821
Reputation: 7788
This ended up being my final solution which is a combination of MrLore and Sotirios Delimanolis solutions. This solution is completely dynamic without the use of any conditions.
This class performs the search for the name by passing in the property name;
String propertyName = "vehicleYear";
vehicleConfiguration.getInfo(propertyName).getName()
propertyName = "vehicleMake";
vehicleConfiguration.getInfo(propertyName).getName()
This class represents the VehicleConfiguration
@Entity
public class VehicleConfiguration extends StatefulEntity {
@ManyToOne
@JoinColumn(name = "year_id")
private VehicleYear vehicleYear;
@ManyToOne
@JoinColumn(name = "make_id")
private VehicleMake vehicleMake;
public LookupBaseEntity getInfo(final String fieldName) {
try {
String methodName = WordUtils.capitalize(fieldName);
Method method = VehicleConfiguration.class.getMethod("get" + methodName);
return (LookupBaseEntity) method.invoke(this);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
Logger.getLogger(VehicleConfiguration.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
This class represents the VehicleYear
@Entity
public class VehicleYear extends LookupBaseEntity {
}
This class represents the VehicleMake
@Entity
public class VehicleMake extends LookupBaseEntity {
}
Which both extend LookupBaseEntity
public class LookupBaseEntity extends StatefulEntity {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Upvotes: 0
Reputation: 3780
Expanding on my comment, As all the methods you showed have a getName()
method, let's create a simple class which defines this:
class Nameable
{
private String name;
public Nameable(final String name)
{
this.name = name;
}
public String getName()
{
return this.name;
}
}
Now when you create the object for Make, Model and Year, they can all use this class so they can be used interchangeably, and can then be combined into a Car
:
class Car
{
public final Nameable make;
public final Nameable model;
public final Nameable year;
public Car(Nameable make, Nameable model, Nameable year)
{
this.make = make;
this.model = model;
this.year = year;
}
public Nameable getInfo(final String info)
{
switch(info)
{
case "make": return this.make;
case "model": return this.model;
case "year": return this.year;
}
return null;
}
}
Then a simple implementation would be:
class PaganiZonda2006 extends Car
{
public PaganiZonda2006()
{
super(new Nameable("Pagani"), new Nameable("Zonda"), new Nameable("2006"));
}
}
And finally, when you want to get the information out, you can read it like so:
public static void main(String[] args)
{
Car car = new PaganiZonda2006();
System.out.println(car.getInfo("make").getName()); //Pagani
System.out.println(car.getInfo("model").getName()); //Zonda
System.out.println(car.getInfo("year").getName()); //2006
}
Upvotes: 1
Reputation: 279890
The class you are looking for is Method
. Please read the appropriate javadoc carefully.
You can get a method with, for example
// assumign `getVehicleMake` is the name of the method and it accepts no parameters
Method method = VehicleConfiguration.class.getMethod("getVehicleMake");
// VehicleConfiguration.class can be replaced by
// Class.forName("VehicleConfiguration")
// if VehicleConfiguration is the fully qualified, ie. with packages, name of the class
// other you need Class.forName("com.yourpackage.VehicleConfiguration")
You then need to invoke()
this method on an instance of your class.
VehicleConfiguration instance = new VehicleConfiguration();
Object returnObject = method.invoke(instance); // assuming no parameters
To then call getName()
, you need to cast the returned object to the type that has the method. Assuming getMake()
is a method of the type VehicleMake
, call it like this
((VehicleMake)returnObject).getMake();
Upvotes: 4
Reputation: 77177
You have to use actual method name: getVehicleMake
, not vehicleMake
.
Additionally, if you're using this as anything other than an exercise, don't roll your own. Use Commons BeanUtils
or Spring's BeanWrapper
.
Upvotes: 2