I hava a POJO class which has a lot of getters. Now I’m using the class Method from the java.lang.reflect package to get all the get methods from that class. I want to invoke those getters but I don’t have idea how. arraylistFilter is an Arraylist<pojo> that contains the result from my request. Option is an Object Field data type which is the one that actually has like 100 getters. How can I get each of them without needed to call 1 by 1. what goes in my .??? there is where I want to be able to invoke my getters.
try {
Class<? extends Options> testObject = new Options().getClass();
Method[] methods = testObject.getMethods();
for (Method method : methods) {
String name = method.getName();
if (method.getName().startsWith("get") &&
method.getGenericParameterTypes().length == 0) {
for (int i = 0; i < arrayListFilter.size(); i++) {
arrayListFilter.get(i).getOptions().???;
}
}
}
} catch (Exception e) {
// do something with the exceptions
}
It will be something like this:
try {
Method[] methods = Options.class.getMethods();
for (Method method : methods) {
String name = method.getName();
if (method.getName().startsWith("get") &&
method.getParameterTypes().length == 0) {
for (int i = 0; i < arrayListFilter.size(); i++) {
Object value = method.invoke(arrayListFilter.get(i).getOptions());
// The actual type of 'value' will depend on the getter's
// formal return type AND the actual type it returns.
// When the return type is a primitive, it is mapped to
// the corresponding wrapper.
}
}
}
} catch (Exception e) {
// do something with the exceptions
}
We have simplified / fixed the code that gets the Method objects, and have changed getGenericParameterTypes() to getParameterTypes(). Generic type parameters are not relevant here, but you do need to filter out getters that require arguments, because there is no way to supply sensible argument values.
Related
I have a class like this:
public class Reza {
public Reza(Reza reza) {
}
}
I want to replace reza of input parameter of constructor to current object like this:
this = reza
How can i do?
is it possible?
No, it is not possible. this and reza represent different objects; you cannot replace the object being created in a constructor with an existing one.
However, you can copy the content of reza into this. For that, add a series of assignments like this:
public Reza(Reza reza) {
field1 = reza.field1;
field2 = reza.field2;
...
}
Impossible, but you can copy all your properties one by one (like other answer) or by reflection.
Something like this, hoping that you have getters and setters for the properties you mean to copy (I copied it from another stackoverflow answer and it looks correct):
public Reza(Reza reza) {
Method[] gettersAndSetters = reza.getClass().getMethods();
for (int i = 0; i < gettersAndSetters.length; i++) {
String methodName = gettersAndSetters[i].getName();
try{
if(methodName.startsWith("get")){
this.getClass().getMethod(methodName.replaceFirst("get", "set") , gettersAndSetters[i].getReturnType() ).invoke(this, gettersAndSetters[i].invoke(reza, null));
}else if(methodName.startsWith("is") ){
this.getClass().getMethod(methodName.replaceFirst("is", "set") , gettersAndSetters[i].getReturnType() ).invoke(this, gettersAndSetters[i].invoke(reza, null));
}
}catch (NoSuchMethodException e) {
// TODO: handle exception
}catch (IllegalArgumentException e) {
// TODO: handle exception
}
}
}
No, you cannot do that. this is, by design, a read-only constant. Assigning to it doesn't make any sense.
I am trying to get the method by java reflection, but i don't want to be specific about the parameters classes in getMethod().
public Object prepareFilter(String filter, String sort) {
Class filterClass = this.filterClass;
try {
Method createCriteriaMethod = filterClass.getMethod(CREATE_CRITERIA_METHOD);
Method orderByClauseMethod = filterClass.getMethod(ORDER_BY_CLAUSE_METHOD, String.class);
Class criteriaClass = createCriteriaMethod.getReturnType();
Object filterObject = filterClass.newInstance();
Object criteriaObject = createCriteriaMethod.invoke(filterObject);
for (ExtFilterRequest extFilter : ExtFilterRequest.decodeJson(filter)) {
StringBuilder sb = new StringBuilder()
.append(AND)
.append(WordUtils.capitalize(extFilter.getProperty()))
.append(extFilter.getCondition());
Method criteriaConditionMethod = criteriaClass.getMethod(sb.toString(), ????); // earlier extFilter.getTransformedValue().getClass()
criteriaConditionMethod.invoke(criteriaObject, extFilter.getTransformedValue());
}
String orderByClause = ExtSortRequest.getOrderByString(sort);
if (orderByClause != null)
orderByClauseMethod.invoke(filterObject, orderByClause);
return filterObject;
} catch (Exception e) {
// later
}
return null;
}
I have the methods generated by MyBatis and I want to call them by reflection with the decoded json that comes from extjs client. It looks like: operator, value and property. Following code is working with string values but i dont know what to put in the place of question marks when I call for example method which get a Date value (decoded value is always a string).
Is it possible to call getMethod with some hmm.. generic type and get the specific method? Or should I do it in another way?
Summarizing - if I have method like this:
public Criteria andSomeReferenceIsEqualTo(String value) {
addCriterion("some_ref =", value, "someRef");
return (Criteria) this;
}
and this
public Criteria andPrimDateEqualTo(Date value) {
addCriterionForJDBCDate("prim_date =", value, "primDate");
return (Criteria) this;
}
I want to call them in the same way by method I specify earlier - even if its boolean, list of values, string or integer.
To display all the methods of the class, whose name is entered through user-input at run-time in the form of a String, I do:
// String s is the class name entered
if (Class.forName(s).getDeclaredMethods().length > 0) {
for (int i = 0; i < Class.forName(s).getDeclaredMethods().length; i++) {
System.out.println(Class.forName(s).getDeclaredMethods()[i].toString());
}
}
However, if I need to display just the public methods, what do I add?
You can try like this:
if (Modifier.isPublic(method.getModifiers()))
{
//Yes the method is PUBLIC
}
Refer getModifier:
Returns the Java language modifiers for the method represented by this
Method object, as an integer. The Modifier class should be used to
decode the modifiers.
I might write it like this.
for (Method m : Class.forName(s).getDeclaredMethods()) {
boolean isPublic = (m.getModifiers() & Modifier.PUBLIC) != 0;
System.out.println(m + " isPublic: " + isPublic);
}
You can get the modifiers using getModifiers(). Here is an idea (not tested)
for(Method m : Class.forName(s).getDeclaredMethods()) {
if(m.getModifiers() == Modifier.PUBLIC) {
//Do something
}
}
There is also a isPublic method in the Modifier class (doc)
I am working with some code where the user sends in an object which can have upwards of 100 values to it. (Let's use a car for example).
updateDatabasePrep(carObject);
The car object COULD have things like name, milage, vin, color, etc... but say I only set the color and then pass the object.
In my method:
public void updateDatabasePrep(Car carObject){
NewObject myObject = newObject(); //Initialized, but empty
String x1 = carObject.getMilage();
String x2 = carObject.getColor();
String x3 = carObject.getName();
//These will hold null values no problem
//Once the rest of the data has been collected:
//These, however, will error out when I try to set the null values.
myObject.setMilage(x1);
myObject.setColor(x2);
myObject.setName(x3);
}
It uses accessor methods which will pull the data from the passed object and then tries to set said values. In the above situation, it will throw a null pointer error as the milage and name are null; only the color is not.
My goal is to update the database with ONLY the values that have been set. In this case, I COULD write a ton of if/ else or try/ catch statements for every single one, that would work, but I would prefer not to.
Is there a shorter way to do this in Java? Is there a method where you can ONLY set data if it is not-null other than if/ else, try/catch, and going through every single setter method and telling it to skip null values?
EDIT:
Just to clarify, the Nullpointerexception will get thrown on when it tries to set a null value. IE
myObject.setMilage(x1);
since people we asking.
Assuming myObject is always going to be the same type, you could use reflection to do a mapping phase that puts the getter and setter methods together in a hashmap like so:
private HashMap<Method, Method> methodMap;
private void doReflection()
{
Method[] carMethods = carObject.getClass().getDeclaredMethods();
ArrayList<Method> getters = new ArrayList<>();
for(int i = 0; i < carMethods.size(); i++)
if(carMethods[i].getName().startsWith("get")) getters.add(carMethods[i]);
methodMap = new HashMap<>();
for(Method m : getters)
{
String fieldName = m.getName().substring(3);
Method setter = myObject.class.getMethod("set" + fieldName, m.getParameterTypes());
if(setter != null) methodMap.put(m, setter);
}
}
Now you can iterate the HashMap to do assignments like so:
for(MapEntry<Method, Method> entry : methodMap.entrySet())
{
Method getter = entry.getKey();
Method setter = entry.getValue();
Object o = getter.invoke(carObject, null);
if(o != null) setter.invoke(myObject, getter.invoke(carObject, null));
}
Reflection is your answer. You may also try using some libraries making it a little more convenient (e.g. commons-beanutils).
So you may do something like:
private void copyIfSpecified(final Car from, final NewObject to, final String propName)
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
final Object value = PropertyUtils.getSimpleProperty(from, propName);
if (value != null) {
PropertyUtils.setSimpleProperty(to, propName, value);
}
}
and call it from your method:
public void updateDatabasePrep(Car carObject){
NewObject myObject = new NewObject(); //Initialized, but empty
try {
copyIfSpecified(carObject, myObject, "milage");
copyIfSpecified(carObject, myObject, "color");
copyIfSpecified(carObject, myObject, "name");
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException ex) {
throw new RuntimeException("Error while populating fields", ex);
}
}
This way you explicitly specify the properties to copy but avoid excessive if statements. In case you don't have to make sure all the fields you want are always copied (e.g. the fieldset is fixed and don't tend to be changed over time) you can do the whole copy thing via reflection (i.e. get all fields of the source object and copy non-null values to the destination object's fields - see PropertyUtils.copyProperties(..) implementation).
ps: note that using this method applies additional restrictions to your classes (Car and NewObject) - they should be java beans: see What is a JavaBean exactly?
pps: and also note that using reflection takes A LOT more time than plain if-statements boilerplate - if you need performance you should think twice.
I am not sure how you are updating DB, using procedure or prepared call. However, below might be helpful to you.
You can get list of fields having null value -
public List<String> getNullFields(Car car) {
Field[] fields = car.getClass().getDeclaredFields();
List<String> result = new ArrayList<String>();
for (Field field : fields) {
try {
field.setAccessible(true);
Object value = field.get(car);
if(value == null) {
result.add(field.getName());
}
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
}
return result;
}
Or else, you can get fields having not null value as well (exact values as well) using similar approach.
Then, you can construct your prepared statement dynamically based on this result. Good luck!
working & optimized code for only getters & setters (including "is" for boolean types)
public void copyCabInfo(CabInfo pCabInfo){
for(Map.Entry<Method, Method> entry : doReflection().entrySet())
{
Method getter = entry.getKey();
Method setter = entry.getValue();
Object o=null;
try {
o = getter.invoke(pCabInfo, null);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) {
e1.printStackTrace();
}
if(o != null)
try {
setter.invoke(this, getter.invoke(pCabInfo, null));
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
private static HashMap<Method, Method> methodMap;
private static HashMap<Method, Method> doReflection()
{
if(methodMap!=null && !methodMap.isEmpty())
return methodMap;
Method[] carMethods = CabInfo.class.getDeclaredMethods();
ArrayList<Method> getters = new ArrayList<>();
for(int i = 0; i < carMethods.length; i++)
if(carMethods[i].getName().startsWith("get") || carMethods[i].getName().startsWith("is") ) getters.add(carMethods[i]);
methodMap = new HashMap<>();
for(Method m : getters)
{
String methodName=m.getName();
String fieldName = methodName.startsWith("is")?methodName.substring(2):methodName.substring(3);
Method setter=null;
try {
setter = CabInfo.class.getMethod("set" + fieldName, m.getReturnType());
} catch (NoSuchMethodException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(setter != null) methodMap.put(m, setter);
}
return methodMap;
}
I am having a domain object with over 90 attributes. In all these attributes there are ., which I want to replace with an empty string.
I could do now:
for (int i = 0; i < list.size(); i++) {
list.get(i).getProp1().replace(".", "");
list.get(i).getProp2().replace(".", "");
//yadadada ...
list.get(i).getProp90().replace(".", "");
}
However, that is extremely boring and takes a lot of code to write. Is there a way to do this much more elegantly and faster?
I appreciate your ideas
What about making a method updateProp (since that's what you need) in your Domain class like this:
public void updateProp(int index) {
prop[index] = prop[index].replace(".", "");
}
and then calling it in a loop
for (int i = 0; i < list.size(); i++) {
for(int j=0; j < prop.length; j++) { /*use a getter, instance or class
reference for obtaining prop.length*/
list.get(i).updateProp(j);
}
}
Storing the Prop in its own Object could also do the trick, but I guess it'll break more code than it will fix.
You have to use java reflection:
Method[] methods = DomainObject.class.getDeclaredMethods();
for (Method method : methods) {
if (method.getName().startsWith("getProp")) {
String result = (String) method.invoke(object, new Object[0]);
result = result.replace(".", "");
Method setter = DomainObject.class.getMethod(method.getName()
.replace("get", "set"), String.class);
setter.invoke(object, result);
}
}
Also don't forget String is immutable, the replace method doesn't change it, the call simply returns the changed version.
You're suggesting that you have a Java class which has up to 90 properties with a consistently incorrectly formatted data field. This question is possibly an X-Y Problem
There is a reason the attributes are stored with a ., and a reason you need them without the .
By understanding these reasons better, and their context, a cleaner solution will present itself.
For example, is the removal of the . purely for display purposes? Perhaps consider a generic function at the point of output to strip the .'s
Or maybe it's some kind of behaviour side-effect during data capture, in which case this needs to be part of an input filter.
Or is this a one-off ETL routine? In which case perhaps it could be done on the data columns direct by some generic SQL or grep / sed script.
If you cannot modify your object (maybe is auto-generated or something) you can achieve your goal through reflection:
for(MyObject a: list){
Field[] fields = MyObject.class.getDeclaredFields();
for (Field f : fields) {
try {
if (f.get(a) instanceof String) {
String str = ((String) f.get(a)).replace(".", "");
f.set(a, str);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
If you don't want to modify the values of your objects you can create The Monster:
List<Map<String, String>> monster = new ArrayList<Map<String, String>>();
for(MyObject a: list){
Field[] fields = MyObject.class.getDeclaredFields();
Map<String, String> map = new HashMap<String, String>();
for (Field f : fields) {
try {
if (f.get(a) instanceof String) {
String str = ((String) f.get(a)).replace(".", "");
map.put(f.getName(), str);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
monster.add(map);
}
Now you have a beatiful list of maps for fields created through reflection. You can access to prop1 of first object via
String obj1prop1 = monster.get(0).get("prop1"); //Value of prop1 for first object in list.
I guess the best way for me would be to create a method in your Object (the one from your List) and in this method, you directly change all the properties as you did here. Than you call your method instead of all of those.
The treatment will be directly on your Object ;)
for (int i = 0; i < list.size(); i++) {
list.set(i,list.get(i).update());
}
in your Object :
public void update()
{
prop1 = prop1.replace(".","");
etc for all the properties
}
Or you could use something like : Field[] getFields() if your attribute are public.
But actually, I think you should do this replace when you are creating your object, so before you already add it in the list. It would be better.