Dynamic Casting Using Java Reflection - java

I have two classes, as follows:
public class Person {
private String dob;
private PersonName personName;
}
public class PersonName {
private String firstName;
private String lastName;
}
I am setting these values dynamically using Java Reflection.
First, I create an instance of Person and I set the value for dob. After that, I need to set a PersonName value in Person. So I created another instance of PersonName and I set the values in that PersonName. After that, I am trying to set the PersonName instance in the Person entity.
For that I used code like this:
Class componentClass = Class.forName(clazz.getName());
Field field = parentClass.getDeclaredField(Introspector
.decapitalize(clazz.getSimpleName()));
field.setAccessible(true);
field.set(parentClass, componentClass);
Here, parentClass is a Person instance and componentClass is a PersonName instance. I am trying to set the PersonName in the Person, but I am getting the following exception:
java.lang.IllegalArgumentException: Can not set com.rise.common.model.PersonName field
com.rise.common.model.Person.personName to java.lang.Class
So how can I set the values dynamically?
Thanks.
My Whole Code:
protected void assignProperties(List<Object[]> argResults,
List<Class> argAllClassesList, Class argParentClass)
throws ClassNotFoundException, NoSuchFieldException,
SecurityException, IllegalArgumentException,
IllegalAccessException, InvocationTargetException, InstantiationException {
List<Object[]> results = (List<Object[]>) Precondition.ensureNotEmpty(
argResults, "Output List");
List<Class<?>> personClassList = new ArrayList<Class<?>>();
for (Object[] recordValues : results) {
Class parentClass = Class.forName(this.getPersistentClass()
.getName());
parentClass.newInstance();
int count = 0;
count = assignValues(recordValues, parentClass, count);
for (Class clazz : argAllClassesList) {
Class componentClass = Class.forName(clazz.getName());
componentClass.newInstance();
String decapitalize = Introspector.decapitalize(clazz
.getSimpleName());
Field field = parentClass.getDeclaredField(decapitalize);
field.setAccessible(true);
assignValues(recordValues, componentClass, count);
field.set(parentClass, componentClass);
}
personClassList.add(parentClass);
}
for (Class<?> class1 : personClassList) {
Class<Person> person = (Class<Person>) class1;
System.out.println(person);
}
}
private int assignValues(Object[] argRecordValues, Class argClass,
int argCount) {
String paramName = Introspector.decapitalize(argClass.getSimpleName());
if (Precondition.checkNotEmpty(paramName)) {
List<Field> fieldNames = TenantConfigHelper.getInstance()
.getModelNameVsFieldsMap().get(paramName);
try {
for (Field field : fieldNames) {
BeanUtils.setProperty(argClass, field.getName(),
argRecordValues[argCount]);
++argCount;
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
return argCount;
}

The message explains what's wrong: componentClass is not an instance of PersonName. It's an object of type Class (probably Class<PersonName>). You probably forgot to instantiate the class.
Edit:
Your code does:
parentClass.newInstance();
and
componentClass.newInstance();
This is the equivalent of doing
new Parent();
and
new ParentName();
So it creates an instance, but doesn't assign it to any variable, and thus doesn't do anything with the created instance, which will be garbage-collectable immediately.
You want
Object parent = parentClass.newInstance();
Object component = componentClass.newInstance();
field.set(parent, component);

I think there may be some confusion over the difference between Java class definitions and instances at work here. You want to set the values of fields on particular instances, not the classes themselves. Something like this may work:
Object parentClassInstance = parentClass.newInstance();
Class componentClass = Class.forName(clazz.getName());
Object componentClassInstance = componentClass.newInstance();
Field field = parentClass.getDeclaredField(Introspector
.decapitalize(clazz.getSimpleName()));
field.setAccessible(true);
field.set(parentClassInstance, componentClassInstance);
Looking at the whole code sample, however, it is a little hard to follow. Why have a List of Classes, with a name like personClassList, which would seem to indicate that each class should be the same class, Person? I feel it should probably instead be a List<Person> or perhaps List<Object>, which you would populate with your Person instances, not the Class objects themselves.
Edit to answer the following question in a comment:
I have to return List instances insetad of List so how can I type case from Class to Person dynamically...?
You can't cast from Class to Person, since Person is probably not a subclass of Class.
Instead, declare your list as a List<Person> instead of a List<Class<?>>
List<Person> personList = new ArrayList<Person>();
Then add the Person objects instead of the Class objects to your list at the bottom of your first for loop.
personList.add((Person)parentClassInstance);
And the loop at the bottom will need to change too:
for (Person person : personList) {
System.out.println(person);
}

I was looking for this same type of answer and basically what everyone is specifying with the Object is correct. I also created a generic list like List<Object> instead of the actual class name. Below is a function that returns a List of type Object's. I pass in the class name and load that with the .loadClass. Than create a new object with that new class instance with the .newInstance. The dList gets loaded with all the information for each objectClass which is the class I pass in with the className variable. The rest is basically just dynamically invoking all of the "set" methods within that particular class with the values from the result set.
protected List<Object> FillObject(ResultSet rs, String className)
{
List<Object> dList = new ArrayList<Object>();
try
{
ClassLoader classLoader = GenericModel.class.getClassLoader();
while (rs.next())
{
Class reflectionClass = classLoader.loadClass("models." + className);
Object objectClass = reflectionClass.newInstance();
Method[] methods = reflectionClass.getMethods();
for(Method method: methods)
{
if (method.getName().indexOf("set") > -1)
{
Class[] parameterTypes = method.getParameterTypes();
for(Class pT: parameterTypes)
{
Method setMethod = reflectionClass.getMethod(method.getName(), pT);
switch(pT.getName())
{
case "int":
int intValue = rs.getInt(method.getName().replace("set", ""));
setMethod.invoke(objectClass, intValue);
break;
case "java.util.Date":
Date dateValue = rs.getDate(method.getName().replace("set", ""));
setMethod.invoke(objectClass, dateValue);
break;
case "boolean":
boolean boolValue = rs.getBoolean(method.getName().replace("set", ""));
setMethod.invoke(objectClass, boolValue);
break;
default:
String stringValue = rs.getString(method.getName().replace("set", ""));
setMethod.invoke(objectClass, stringValue);
break;
}
}
}
}
dList.add(objectClass);
}
}
catch (Exception e)
{
this.setConnectionMessage("ERROR: reflection class loading: " + e.getMessage());
}
return dList;
}

The type system is verified by the compiler. While there is some additional safety possible during runtime, that additional safety is not even close to the safety the compiler imposes. Which begs the question, Why?
Assuming you could get the stuff to work, exactly how would you be able to justify casting class1 below into a Class<Person> type? You declared it to be a Class<?>!
for (Class<?> class1 : personClassList) {
Class<Person> person = (Class<Person>) class1;
System.out.println(person);
}

Related

How to "merge" two objects of the same class

The code is groovy but the answer can be both, Groovy or Java.
I have a Person class with this fields:
class Person(){
String name
String lasName
}
I have a method that returns two objects from the same class. One object with some fields and the other with the rest, in my example it would be like this:
person1 = "name : Jon"
person2 = "lastName : Snow"
What I need is to replace all the null fields of person1 with the person2 field if this is not null, in our example, the output would be:
person1.merge(person2)
person1= "name : Jon, lastName : Snow"
Is there any method on Java or Groovy to do something similar to this without writing all my fields(using some kind of loop)?
If there isn't any default method to use, how can I iterate through all the fields from a class?
Just tested using reflection. The desired output is
merged person:Person{name=John, lastName=Snow}
public static void testReflection() {
Person p1 = new Person("John", null);
Person p2 = new Person(null, "Snow");
Person merged = (Person) mergePersons(p1, p2);
System.out.println("merged person:" + merged);
}
public static Object mergePersons(Object obj1, Object obj2) throws Exception {
Field[] allFields = obj1.getClass().getDeclaredFields();
for (Field field : allFields) {
if (Modifier.isPublic(field.getModifiers()) && field.isAccessible() && field.get(obj1) == null && field.get(obj2) != null) {
field.set(obj1, field.get(obj2));
}
}
return obj1;
}
mergePersons accepts two Objects.
Then it go through all fields and validate if the first object has a null value.
If yes, then it verify if the second object is not nulled.
If this is true it assigns the value to the first Object.
Providing this solution you only access public data. If you want to access private data aswell, you need to remove the Modifier verification and set if accessible before like:
public static Object mergePersons(Object obj1, Object obj2) throws Exception {
Field[] allFields = obj1.getClass().getDeclaredFields();
for (Field field : allFields) {
if (!field.isAccessible() && Modifier.isPrivate(field.getModifiers()))
field.setAccessible(true);
if (field.get(obj1) == null && field.get(obj2) != null) {
field.set(obj1, field.get(obj2));
}
}
return obj1;
}
This is a quick (and presumptuous) approach that is basically the same as using reflection on the fields but instead uses:
Groovy's built-in getProperties() method on java.lang.Object, which provides us with a Map of its property names and values
Groovy's default Map constructor, which allows use to create instances of an Object given a Map of properties.
Given these two features, you can describe each object you want to merge as a Map of their properties, strip out the null-valued entries, combine the Maps together (and remove the pesky 'class' entry which is readonly), and use the merged Map to construct your merged instance.
class Person {
String first, last, middle
}
def p1 = new Person(first: 'bob')
def p2 = new Person(last: 'barker')
Person merged = (p1.properties.findAll { k, v -> v } // p1's non-null properties
+ p2.properties.findAll { k, v -> v }) // plus p2's non-null properties
.findAll { k, v -> k != 'class' } // excluding the 'class' property
assert merged.first == 'bob'
assert merged.last == 'barker'
assert merged.middle == null
Given Groovy fields are implemented as a getter/setter pair with a backing field you can probably do it this way in Groovy:
static <T> void merge(T from, T to) {
from.metaClass.properties.findAll { p ->
p.getProperty(to) == null &&
p.getProperty(from) != null &&
to.respondsTo(MetaProperty.getSetterName(p.name))
}
.each {
p -> p.setProperty(to, p.getProperty(from))
}
}
You're going to have to go the reflection route. I'm assuming you have a default constructor, otherwise the following won't work. Also, it needs two same types.
public static <T> T mergeObjects(T first, T second) throws IllegalAccessException, InstantiationException {
Class<?> clazz = first.getClass();
Field[] fields = clazz.getDeclaredFields();
Object returnValue = clazz.newInstance();
for (Field field : fields) {
field.setAccessible(true);
Object value1 = field.get(first);
Object value2 = field.get(second);
Object value = (value1 != null) ? value1 : value2;
field.set(returnValue, value);
}
return (T) returnValue;
}
Here is example
import java.lang.reflect.Field;
public class Merge2Obj {
private String name;
private String lasName;
public Merge2Obj() {
super();
}
public Merge2Obj(String name, String lasName) {
super();
this.name = name;
this.lasName = lasName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLasName() {
return lasName;
}
public void setLasName(String lasName) {
this.lasName = lasName;
}
public static <T> T mergeObjects(T first, T second) throws IllegalAccessException, InstantiationException {
Class<?> clazz = first.getClass();
Field[] fields = clazz.getDeclaredFields();
Object returnValue = clazz.newInstance();
for (Field field : fields) {
field.setAccessible(true);
Object value1 = field.get(first);
Object value2 = field.get(second);
Object value = (value1 != null) ? value1 : value2;
field.set(returnValue, value);
}
return (T) returnValue;
}
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
Merge2Obj obj1 = new Merge2Obj("ABC", null);
Merge2Obj obj2 = new Merge2Obj("PQR", "LMN");
Merge2Obj obj3 = mergeObjects(obj1, obj2);
System.out.println(obj3.name);
System.out.println(obj3.lasName);
}
}
Assuming a mutable data class with getters and setters, Apache BeanUtils may suit your needs.
By default BeanUtilBeansBean.copyProperties(Object dest, Object orig) looks for pairs of T orig.get*() and dest.set*(T value), and calls the latter with the result of the former.
But you can inject a custom PropertyUtilsBean, so you could wrap the default one to prevent it from replacing non-null properties:
public NoClobberPropertyUtilsBean extends PropertyUtilsBean {
#Override
public void setSimpleProperty((Object bean,
String name,
Object value)
throws IllegalAccessException,
InvocationTargetException,
NoSuchMethodException {
if(getProperty(bean,name) == null) {
super.setSimpleProperty(bean,name,value);
}
}
}
Now you can merge with:
BeanUtilsBean beanUtils = new BeanUtilsBean(new ConvertUtilsBean(), new NoClobberPropertyUtilsBean());
Person merged = new Person();
beanUtils.copyProperties(person1);
beanUtils.copyProperties(person2);
If a property is non-null in both sources, the first copyProperties wins.
You could of course change the semantics, for example it would behave a different way if the guard was if(value != null).
At one level BeanUtils is just a wrapper around the kind of Reflection operations other answers suggest. It's up to you whether you want the extra level of abstraction. You may need to override more methods if you want to support map/list members, or BeanUtils' DynaBean class.

Converting Mongo DBObject to Entity POJO using Reflection

First I want to say that yes - I know there are ORMs like Morphia and Spring Data for MongoDB. I'm not trying to reinvent the weel - just to learn. So basic idea behind my AbstractRepository is to encapsulate logic that's shared between all repositories. Subclasses (repositories for specific entities) passes Entity class to .
Converting entity beans (POJOs) to DBObject using Reflection was pretty streightforward. Problem comes with converting DBObject to entity bean. Reason? I need to convert whatever field type in DBObject to entity bean property type. And this is where I'm stuck. I'm unable to get entity bean class in AbstractRepository method T getEntityFromDBObject(DBObject object)
I could pass entity class to this method but that would defeat the purpose of polymorphism. Another way would be to declare private T type property and then read type using Field. Defining additional property just so I can read doesn't sound right.
So the question is - how would you map DBObject to POJO using reflection using less parameteres possible. Once again this is the idea:
public abstract class AbstractRepository<T> {
T getEntityFromDBObject(DBObject object) {
....
}
}
And specific repository would look like this:
public class EntityRepository extends AbstractRepository<T> {
}
Thanks!
Note: Ignore complex relations and references. Let's say it doesn't need to support references to another DBObjects or POJOs.
You need to build an instance of type T and fill it with the data that comes in ´DBObject´:
public abstract class AbstractRepository<T> {
protected final Class<T> entityClass;
protected AbstractRepository() {
// Don't remember if this reflection stuff throws any exception
// If it does, try-catch and throw RuntimeException
// (or assign null to entityClass)
// Anyways, it's impossible that such exception occurs here
Type t = this.getClass().getGenericSuperclass();
this.entityClass = ((Class<T>)((ParameterizedType)t).getActualTypeArguments()[0]);
}
T getEntityFromDBObject(DBObject object) {
// Use reflection to create an entity instance
// Let's suppose all entities have a public no-args constructor (they should!)
T entity = (T) this.entityClass.getConstructor().newInstance();
// Now fill entity with DBObject's data
// This is the place to fill common fields only, i.e. an ID
// So maybe T could extend some abstract BaseEntity that provides setters for these common fields
// Again, all this reflection stuff needs to be done within a try-catch block because of checked exceptions
// Wrap the original exception in a RuntimeException and throw this one instead
// (or maybe your own specific runtime exception for this case)
// Now let specialized repositories fill specific fields
this.fillSpecificFields(entity, object);
return entity;
}
protected abstract void fillSpecificFields(T entity, DBObject object);
}
If you don't want to implement the method .fillSpecificFields() in every entity's repository, then you'd need to use reflection to set every field (including common ones such as ID, so don't set them manually).
If this is the case, you already have the entity class as a protected attribute, so it's available to every entity's repository. You need to iterate over ALL its fields, including the ones declared in superclasses (I believe you have to use method .getFields() instead of .getDeclaredFields()) and set the values via reflection.
As a side note, I really don't know what data comes in that DBObject instance, and in what format, so please let me know if extracting fields' values from it results to be non trivial.
First I want to apologies for answering to your comments almost two months later. I did managed to figure it out on my own and here is how I've implemented it (and tested) so maybe someone will make a use of it:
public abstract class AbstractRepository<T> {
#Inject
private MongoConnectionProvider provider;
// Keeps current repository collection name
protected String collectionName;
#PostConstruct
public abstract void initialize();
public String getCollectionName() {
return this.collectionName;
}
protected void setCollectionName(String collectionName) {
this.collectionName = collectionName;
}
protected DBCollection getConnection() {
DB conn = this.provider.getConnection();
DBCollection collection = conn.getCollection(this.collectionName);
return collection;
}
private void putFieldToDbObject(T source, DBObject target, Field field) {
// TODO: Think more elegant solution for this
try {
field.setAccessible(true);
// Should we cast String to ObjectId
if (field.getName() == "id" && field.get(source) != null
|| field.isAnnotationPresent(DBRef.class)) {
String key = field.getName().equals("id") ? "_id" : field.getName();
target.put(key, new ObjectId(field.get(source).toString()));
} else {
if(!field.getName().equals("id")) {
target.put(field.getName(), field.get(source));
}
}
} catch (IllegalArgumentException | IllegalAccessException exception) {
// TODO Auto-generated catch block
exception.printStackTrace();
} finally {
field.setAccessible(false);
}
}
#SuppressWarnings("rawtypes")
protected DBObject getDbObject(T entity) {
DBObject result = new BasicDBObject();
// Get entity class
Class entityClass = entity.getClass();
Field[] fields = entityClass.getDeclaredFields();
// Update DBobject with entity data
for (Field field : fields) {
this.putFieldToDbObject(entity, result, field);
}
return result;
}
#SuppressWarnings({ "unchecked", "rawtypes" })
public T getEntityFromDBObject(DBObject object) throws MappingException {
Type superclass = this.getClass().getGenericSuperclass();
Type entityClass = ((ParameterizedType) superclass).getActualTypeArguments()[0];
T entity;
try {
entity = ((Class<T>) entityClass).newInstance();
// Map fields to entity properties
Set<String> keySet = object.keySet();
for(String key : keySet) {
String fieldName = key.equals("_id") ? "id" : key;
Field field = ((Class<T>) entityClass).getDeclaredField(fieldName);
field.setAccessible(true);
if(object.get(key).getClass().getSimpleName().equals("ObjectId")) {
field.set(entity, object.get(key).toString());
} else {
// Get field type
Type fieldType = field.getType();
Object fieldValue = object.get(key);
Class objectType = object.get(key).getClass();
if(!fieldType.equals(objectType)) {
// Let's try to convert source type to destination type
try {
fieldValue = (((Class) fieldType).getConstructor(objectType)).newInstance(object.get(key));
} catch (NoSuchMethodException exception) {
// Let's try to use String as "man-in-the-middle"
String objectValue = object.get(key).toString();
// Get constructor for destination type that take String as parameter
Constructor constructor = ((Class) fieldType).getConstructor(String.class);
fieldValue = constructor.newInstance(objectValue);
}
}
field.set(entity, fieldValue);
}
field.setAccessible(false);
}
} catch (InstantiationException | IllegalAccessException | NoSuchFieldException | SecurityException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException e) {
throw new MappingException(e.getMessage(), MappingExceptionCode.UNKNOWN_ERROR);
}
return entity;
}
public List<T> getAll() {
DBCollection conn = this.getConnection();
DBCursor cursor = conn.find();
List<T> result = new LinkedList<T>();
while (cursor.hasNext()) {
DBObject obj = cursor.next();
try {
result.add(this.getEntityFromDBObject(obj));
} catch (MappingException e) {
}
}
return result;
}
public T getOneById(String id) {
DBObject idRef = new BasicDBObject().append("_id", new ObjectId(id));
DBCollection conn = this.getConnection();
DBObject resultObj = conn.findOne(idRef);
T result = null;
try {
result = this.getEntityFromDBObject(resultObj);
} catch (MappingException e) {
}
return result;
}
public void save(T entity) {
DBObject object = this.getDbObject(entity);
DBCollection collection = this.getConnection();
collection.save(object);
}
}
You've stumbled onto the problem of object mapping. There are a few libraries out there that look to help with this. You might check out ModelMapper (author here).

Return object based on input string name in java

I have a requirement wherein I've to write a method which accepts "string" and based on this string i need to return an object of type MyObject. This can be done with using switch case, but how could this be achieved dynamically.
In below case method can be called by giving "myObject1" as string, then this method should return myObject1 object. How could this be done.
public class HelloWorld {
MyObject myObject1 = new MyObject();
MyObject myObject2 = new MyObject();
MyObject myObject3 = new MyObject();
public MyObject getMyObject(String string)
{
return <<myObject1 or 2 or 3 based on string parameter name>>;
}
}
class MyObject {
}
This can be done dynamically via reflection, but it would be highly impractical and unnecessary. You should either use a switch or a Map to associate your string identifiers with your actual objects.
Map<String, MyObject> identifiers = new HashMap<>();
...
identifiers.put("myObject1", myObject1);
identifiers.put("myObject2", myObject2);
identifiers.put("myObject3", myObject3);
...
public MyObject getMyObject(String string) {
return identifiers.get(string);
}
If you really want to do things like this reflection is your friend. You can look up declared fields by name, and then use them to look up an instance variable.
I've modified your example to include a main method that looks up each instance of MyObject and also has a failure case. I've also modified MyObject so you can easily tell which instance has been found.
import java.lang.reflect.Field;
public class Reflection {
MyObject myObject1 = new MyObject("1");
MyObject myObject2 = new MyObject("2");
MyObject myObject3 = new MyObject("3");
public MyObject getMyObject(final String string) {
try {
final Field declaredField = this.getClass()
.getDeclaredField(string);
final Object o = declaredField.get(this);
if (o instanceof MyObject) {
return (MyObject) o;
}
} catch (final Exception e) {
}
return null;
}
class MyObject {
final String name;
public MyObject(final String name) {
this.name = name;
}
#Override
public String toString() {
// TODO Auto-generated method stub
return name;
}
}
public static void main(final String[] args) {
final Reflection r = new Reflection();
System.out.println(r.getMyObject("myObject1"));
System.out.println(r.getMyObject("myObject2"));
System.out.println(r.getMyObject("myObject3"));
System.out.println(r.getMyObject("invalid"));
}
}
There is some useful information about reflection in the Oracle Java documentation.
I would look at implementing a Strategy pattern to do this.
You can use:
Class<?> clazz = Class.forName(className);
Object object = clazz.newInstance();
where className - the fully qualified name of the desired class
see http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html for details

Access Class Variable on general Object of that class

I have a lots of classes for example this one:
public class DepartmentST {
public Long id = null;
public String name = null;
public String comments = null;
public Long[] profiles = null;
public Boolean default_val = false;
}
In main class I create objects of those classes and sent it to general method for example:
DepartmentST mydepartment = new DepartmentST();
generalMethod(mydepartment);
In general Method I want to access to object fields (this my question how?)
public generalMethod(Object myObj) {
Field[] fields = myObj.getClass().getFields();
for(Field field : fields) {
String fieldName = field.getName();
// I want to access that field how can i tell myObj.fielName ?
}
}
I'm new in Java I don't know it's stupid question or not.
thanks for any help in advance.
see http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Field.html#get(java.lang.Object)
public generalMethod(Object myObj) {
Field[] fields = myObj.getClass().getFields();
for(Field field : fields) {
String fieldName = field.getName();
// I want to access that field how can i tell myObj.fielName ?
Class c = field.getType();
if (c instanceOf Integer) {
Integer value = field.getInt (myObj);
}
// or
Object value = field.get (myObj);
}
}
You need to "cast" the object to a DepartmentST object:
if (myObj instanceof DepartmentST) {
DepartmentST department = (DepartmentST) myObj;
// continue with code
Then use that object instead of myObj.
Basically this code breaks the encapsulation. You need private fields, and you access them through getters and setters. Reflection is another way to go (depending on the context).

Dynamically calling a class method in java?

Is it possible to dynamically call a method on a class from java?
E.g, lets say I have the reference to a class, e.g either the string: 'com.foo.Bar', or com.foo.Bar.class, or anything else which is needed..). And I have an array / list of strings, e.g [First, Last, Email].
I want to simply loop through this array, and call the method 'validate' + element on the class that I have a reference to. E.g:
MyInterface item = //instantiate the com.foo.Bar class here somehow, I'm not sure how.
item.validateFirst();
item.validateLast();
item.validateEmail();
I want the above lines of code to happen dynamically, so I can change the reference to a different class, and the names in my string list can change, but it will still call the validate + name method on whichever class it has the reference to.
Is that possible?
The simplest approach would be to use reflection
Given...
package com.foo;
public class Bar {
public void validateFirst() {
System.out.println("validateFirst");
}
public void validateLast() {
System.out.println("validateLast");
}
public void validateEmail() {
System.out.println("validateEmail");
}
}
You could use something like...
String methodNames[] = new String[]{"First", "Last", "Email"};
String className = "com.foo.Bar";
try {
Class classRef = Class.forName(className);
Object instance = classRef.newInstance();
for (String methodName : methodNames) {
try {
Method method = classRef.getDeclaredMethod("validate" + methodName);
method.invoke(instance);
} catch (NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException ex) {
ex.printStackTrace();
}
}
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
ex.printStackTrace();
}
To look up the methods and execute them.
You will need to decide the best way to handle errors and what they mean to you, but it wouldn't be a difficult them to expand the idea to a reusable method...
Updated with idea of concept discussed in comments
Given....
public interface Validator {
public boolean isValid(Properties formProperties);
}
We can create one or more...
public class UserRegistrationValidator implements Validator {
public boolean isValid(Properties formProperties) {
boolean isValid = false;
// Required fields...
if (formProperties.containsKey("firstName") && formProperties.containsKey("lastName") && formProperties.containsKey("email")) {
// Further processing, valid each required field...
}
if (isValid) {
// Process optional parameters
}
return isValid;
}
}
Then from our input controller, we can look and valid the required forms
public class FormController ... {
private Map<String, Validator> validators;
public void validForm(String formName, Properties formProperties) {
boolean isValid = false;
Validator validator = validators.get(formName);
if (validator != null) {
isValid = validate.isValid(formProperties);
}
return isValid;
}
}
Of course you need to provide some way to register the Validators and there may be differences based on the backbone framework you are using and the parameters you can use (you don't have to use Properties, but it is basically just a Map<String, String>...)
You can write something like this... it takes name of a class as string as an argument, the method name and its arguments
private static String invoke(String aClass, String aMethod, Class<?>[] params,
Object[] args) throws Exception {
String resp = "";
Class<?> c = Class.forName(aClass);
Method m = c.getDeclaredMethod(aMethod, params);
Object i = c.newInstance();
resp = m.invoke(i, args).toString();
return resp;
}
You can also refer to the oracle tutorial on reflection ... which demonstrates how to call methods
http://docs.oracle.com/javase/tutorial/reflect/member/methodInvocation.html
It's possible using reflection.
First, you create a new class from the FQN (fully qualified name, which is the class name including the package).
Then you iterate through your elements and invoke the "validate" methods on your item.
Class<?> clazz = Class.forName("com.foo.Bar");
Object item = clazz.newInstance();
for (String element : elements) {
Method method = clazz.getDeclaredMethod("validate" + element);
method.invoke(item);
}
You can use reflection, but my favorite method is to use beanutils, eg:
Bar b1 = //...
BeanUtils.getProperty(b1, "first");
BeanUtils.getProperty(b1, "last");
Note that your class has to conform to javabean convention. You can read more about beanutils on this blog post (disclaimer I'm the blog author)
If you know the name of the class beforehand, use Class.forName(yourClassname)
That way, you can invoke the class, and then, you can invoke its methods.
Yes, using reflection.
Using Class.getDeclaredMethod on your object
Object validator = <your object instance>;
final String[] values = {
"Item1","Item2","Item3"
}
for(final String s : values) {
Method m = validator.getDeclaredMethod("validate" + s,String.class);
try {
Object result = m.invoke(validator, s);
}
catch(ex) {}
}

Categories