How I can empty values get and set together in java? - java

I have get and set class :
public static class Structure{
private String YOne = null;
private String YTwo = null;
public String getYOne() {
return YOne;
}
public void setYOne(String YOne) {
this.YOne = YOne;
}
public String getYTwo() {
return YTwo;
}
public void setYTwo(String YTwo) {
this.YTwo = YTwo;
}
}
Then I fill that in my class :
Structure.setYOne("my value");
Structure.setYTwo("my value");
How I can empty all of them ?
Notice : I don't like empty that one by one .

You can implement a method in your Structure class that sets all the fields to null using Reflection:
public void clearFields() throws IllegalArgumentException, IllegalAccessException {
Field[] properties = this.getClass().getDeclaredFields();
for (Field f : properties) {
f.setAccessible(true);
f.set(this, null);
}
}

Rebuild your object, no other choice if you don't want to do it one by one
Structure s = new Structure();
// YOne and YTwo are null
s.setYOne("my value");
s.setYTwo("my value");
// YOne and YTwo are not null;
s = new Structure();
// YOne and YTwo are null again
edit : be careful though, it could mess up your reference if your object is used in another class.

You are lacking basic class and object concept here. You need to create an array of objects of Structure class. The use a foor loop to loop through all the objects and set methods.
for(Structure x : your_array_of_Structures ){
x.set(whatever);
x.get(whatever);
}
Go to http://www.tutorialspoint.com/java/java_loop_control.htm where you can get more tutorials on how to do these basic things in Java.

Related

Choose which methods to run, with user input

I have a list of methods within my class. And then want to have input string array, where the user can choose which methods they want to run. We are running expensive insurance calculations. And have over say eg 20 methods. Is there a way to conduct this without do an if check on each? maybe with reflection or interface?
#Override
public void ProductTest(ProductData productData, String[] methodNames) {
public void methodA(ProductData productData){...};
public void methodB(ProductData productData){...};
public void methodC(ProductData productData){...};
public void methodD(ProductData productData){...};
public void methodE(ProductData productData){...};
}
I am willing to change the Array into a different ObjectType if needed, to execute properly. Using SpringBoot, has it has a library of utility classes.
Use a Map<String, Consumer<ProductData>>, not separate method handles. Main reason - reflection is slow and dangerous when given user "input"
Use map.get(input).accept(product) to call it.
https://docs.oracle.com/javase/8/docs/api/index.html?java/util/function/Consumer.html
Example
Map<String, Consumer<ProductData>> map = new HashMap<>();
map.put("print_it", System.out::println);
map.put("print_id", data -> System.out.println(data.id));
map.put("id_to_hex", data -> {
int id = data.getId();
System.out.printf("0x%x%n", id);
});
ProductData data = new ProductData(16);
map.get("print_it").accept(data);
map.get("print_id").accept(data);
map.get("id_to_hex").accept(data);
Outputs
ProductData(id=16)
16
0x10
If you are planning on chaining consumers using andThen, you'd be better having an Optional<ProductData>, and using a Function<ProductData, ProductData> with Optional.map()
One way to do it is via reflection. You can iterate over methods in the class object and look for ones to run by name. Here's some example code--this would print out a list of names the user could type in:
myObject.getClass().getDeclaredMethods().each((method)->System.out.println(method.getName()))
And this is how you would call it once the user had made a selection:
productTest.getDeclaredMethods().each((method)->
if(method.getName().equals(userSelectedName))
method.invoke(productTest, productData)
)
The ONLY advantage to this approach is that you don't have to maintain a second structure (Switch, Map, etc...) and add to it every time you add a new method. A personality quirk makes me unwilling to do that (If adding something one place forces you to update a second, you're doing it wrong), but this doesn't bother everyone as much as it bothers me.
This isn't dangerous or anything, if you don't have a method in the class it can't call it, but if you are relying on users "Typing", I'd suggest listing out the options and allowing a numeric selection--or using reflection to build a map like OneCricketeer's.
I've used this pattern to write a testing language and fixture to test set-top TV boxes, it was super simple to parse a group of strings, map some to methods and other to parameters and have a very flexible, easily extensible testing language.
The method object also has a "getAnnotation()" which can be used to allow more flexible matching in the future.
You can use method invocation.
For example, you can have two methods, first one will loop through your methodNames array and call the second method:
public void callPassedMethods(ProductData productData, String[] methodNames) {
for (String m : methodNames) {
callMethod(productData, m)
}
}
And the second method will actually find a method in your class that matches the string passed and invoke it:
public void callMethod(ProductData productData, String methodName) {
try {
ClassName yourObj = new ClassName(); // Class where your methods are
Method method = yourObj.getClass().getDeclaredMethod(methodName, ProductData.class);
method.invoke(yourObj, productData);
} catch(NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
// handle exceptions
}
}
Or, you can always use the good old switch statement:
for (String m : methodNames) {
switch (m) {
case "methodA":
methodA();
break;
case "methodB":
methodB();
break;
// ... continue with as many cases as you need
}
}
If you go with the reflection route, you don't really want to expose your method names to the end users. They might not be end user-friendly, and if they are, there is no reason for users to know this information and there might be methods, which are not supposed to be invoked by users. I would use custom annotations to build more flexible matching.
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface UserChoice {
String userFriendlyOption();
int optionNumber();
}
optionNumber will be used for matching the method to invoke, userFriendlyOption is some user friendly text.
Annotate only the methods, supposed to be used by users.
#RequiredArgsConstructor
public class ProductData {
private final double data;
#UserChoice(userFriendlyOption = "see result for option a", optionNumber = 1)
public void methodA() {
System.out.println(data + 1);
}
#UserChoice(userFriendlyOption = "see result for option b", optionNumber = 2)
public void methodB() {
System.out.println(data + 2);
}
#UserChoice(userFriendlyOption = "see result for option c", optionNumber = 3)
public void methodC() {
System.out.println(data);
}
public void methodNotForUser() {
System.out.println("Should not be seen by users");
}
}
Like this methodNotForUser() can't be invoked by end users.
Simplified matcher might look like this.
#RequiredArgsConstructor
public class ProductTester {
private final ProductData data;
private Map<Integer, MethodData> map;
public void showOptions() {
if (this.map == null) {
this.map = new HashMap<>();
for (Method method : this.data.getClass().getMethods()) {
UserChoice userChoice = method.getAnnotation(UserChoice.class);
if (userChoice != null) {
String userRepresentation = userChoice.optionNumber() + " - " + userChoice.userFriendlyOption();
this.map.put(userChoice.optionNumber(), new MethodData(userRepresentation, method));
}
}
}
this.map.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.forEach(entry -> System.out.println(entry.getValue().getUserRepresentation()));
}
public void showOptionResult(int choice) {
MethodData methodData = this.map.get(choice);
if (methodData == null) {
System.out.println("Invalid choice");
return;
}
System.out.println("Result");
try {
methodData.getMethod().invoke(this.data);
} catch (IllegalAccessException | InvocationTargetException ignore) {
//should not happen
}
}
}
MethodData is simple pojo with the sole purpose to not recalculate user representation.
#RequiredArgsConstructor
#Getter
public class MethodData {
private final String userRepresentation;
private final Method method;
}
Short main to illustrate the idea and play around:
public class Temp {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Write initial value");
double data = scanner.nextDouble();
ProductData myData = new ProductData(data);
ProductTester tester = new ProductTester(myData);
tester.showOptions();
System.out.println("Write option number");
int userChoice = scanner.nextInt();
tester.showOptionResult(userChoice);
}
}

Java Android, loop through all getters

I have a model like below:
public class Shifts{
private double h00;
private double h01;
private double h02;
private double h03;
public Shifts() {
}
public Shifts(double h00, double h01, double h02, double h03) {
this.h00 = h00;
this.h01 = h01;
this.h02 = h02;
this.h03 = h03;
}
public double getH00() {
return h00;
}
public void setH00(double h00) {
this.h00 = h00;
}
public double getH01() {
return h01;
}
public void setH01(double h01) {
this.h01 = h01;
}
public double getH02() {
return h02;
}
public void setH02(double h02) {
this.h02 = h02;
}
public double getH03() {
return h03;
}
public void setH03(double h03) {
this.h03 = h03;
}
}
I'm calling this model in a recycle adapter to update the UI and on the onBindViewHolder, I do like this:
holder.h00.setText(fooList.get(position).getH00()));
holder.h01.setText(fooList.get(position).getH01()));
holder.h02.setText(fooList.get(position).getH02()));
holder.h03.setText(fooList.get(position).getH03()));
In reality, this model has a lot of getters and setters and I was trying to loop through them so I can do something like this:
for (int i = 0; i < holder.shift_layout.getChildCount(); i++) {
//shift_layout is the Layout which holds all the views
View v = holder.shift_layout.getChildAt(i);
if (v instanceof TextView) {
v.setText(Hour(fooList.get(position).getGetter()));
}
}
Is there a way to use Java reflection or any method to loop through all getters of a model and then invoke them?
Looking over the SO I found some answers but with not any success to invoke the getters.
The other answers provided, especially Magnus, definitely get the job done. They are valid answers. The only difference between this solution and the others is that this will ensure that the method name starts with getH which seems to be pattern. It also checks if the return type is of type double to help ensure the correct method is being returned.
Shifts shifts = new Shifts(1, 2, 3, 4);
Method[] methods = shifts.getClass().getDeclaredMethods();
for (Method method : methods) {
if (method.getName().startsWith("getH") && method.getReturnType() == double.class) {
double value = (double) method.invoke(shifts);
}
}
This code iterates over all methods of the class obj and if method name starts with 'get' it invokes the method m on instance obj and assigns the result to object:
final Object obj;
for (Method m : obj.getClass().getMethods())
if (m.getName().startsWith("get") && m.getParameterTypes().length == 0) {
final Object object = m.invoke(obj);
// do something
}
}
Yes, there is a way you can loop through getters by reflections. You should first make some kind of list with names of attributes.
I did it once with HashMap and setters, then I iterated through that hash map with:
for (Map.Entry<String, Integer> entry : myMap.entrySet()) {
var setterName = "set" + entry.getKey().toUpperCase();
Method setter = instanceOfMyClassWithSetters.getClass().getMethod(setterName, Integer.class);
setter.invoke(instanceOfMyClassWithSetters, entry.getValue());
}
That Integer.class is a setter parameter so I suppose you don't need that part.

Java Array of InnerClass throwing java.lang.NoSuchFieldError

I am trying to brushup java after a long time.
Any help is much appreciated.
For demonstration I have Animal Class that has an array of innerclass of Organs.
public class Animal
{
String nameOfAnimal;
Organs [] vitalOrgans = new Organs[3];
public Animal()
{
}
public String getNameOfAnimal() {
return nameOfAnimal;
}
public void setNameOfAnimal(String nameOfAnimal) {
this.nameOfAnimal = nameOfAnimal;
}
#Override
public String toString() {
return "Animal{" + "nameOfAnimal=" + nameOfAnimal + "}";
}
class Organs{
String nameOfOrgan;
public String getNameOfOrgan() {
return nameOfOrgan;
}
public void setNameOfOrgan(String nameOfOrgan) {
this.nameOfOrgan = nameOfOrgan;
}
#Override
public String toString() {
return "Organs{" + "nameOfOrgan=" + nameOfOrgan + '}';
}
}
}
Now in driver file when I make call there is no syntactical error but I get "Exception in thread "main" java.lang.NoSuchFieldError: vitalOrgans"
Animal mamal = new Animal();
mamal.setNameOfAnimal("Chimp");
mamal.vitalOrgans[0].setNameOfOrgan("Heart");
System.out.println(mamal.vitalOrgans[0].getNameOfOrgan());
What would be the way to make this (or similar idea) to work.
Thanks.
You would need to initialize the vitalOrgrans with new Organs(). Like:
public Animal() {
for (int i = 0; i < vitalOrgans.length; i++) {
vitalOrgans[i] = new Organs();
}
}
Because when you say :
Organs[] vitalOrgans = new Organs[3];
You are creating an array of 3 null Organs. Hence the null pointer exception, when accessing "vitalOrgans[i].".
Taking the relevant bit of code:
public class Animal
{
//...
Organs [] vitalOrgans = new Organs[3];
//...
}
Since your declaration of vitalOrgans was never given an access modifier (i.e. one of private, public, protected) it took on default access, which means only other classes in the same package can see it. Since your other block of code is not in the same package, it cannot see the field.
A minimally viable modification to just make it work would be to set the access to public:
public class Animal
{
//...
public Organs [] vitalOrgans = new Organs[3];
//...
}
While this works, it's not necessarily the best solution, as if you ever change how vitalOrgans is represented, or need to perform any validation, those edits would have to be done throughout the application. Thus, a better solution (and also, a major stylistic convention in Java for those exact reasons) is to make it (and all your fields, in fact) private and access via methods:
public class Animal {
private String nameOfAnimal;
private Organs[] vitalOrgans = new Organs[3];
//...
public Organs[] getVitalOrgans() {
return vitalOrgans;
}
//Alternative accessor that fetches only one organ.
public Organs getVitalOrgan(int index) {
if(index >= 0 && index < vitalOrgans.length)
return vitalOrgans[index];
else
return null;
}
public void setVitalOrgans(Organs[] vitalOrgans) {
this.vitalOrgans = vitalOrgans
}
//...
}
Your caller could then access Organs via either form of the get method (note, you probably want Organs to be public):
Animal.Organs futureMammalHeart = mamal.getVitalOrgan(0); //Animal.Organs due to Organs being an inner class.
if(futureMammalHeart != null) //Demonstration of null check. Safety first!
futureMammalHeart.setNameOfOrgan("Heart");
Animal.Organs[] mammalianVitalOrgans = mamal.getVitalOrgans();
if(mammalianVitalOrgans != null) //Just in case...
System.out.println(mamal.mammalianVitalOrgans[0].getNameOfOrgan());
Also, as Ari mentioned in his answer, don't forget to initialize the organs in your array, otherwise you will get a NullPointerException!

Copy non-null properties from one object to another using BeanUtils or similar

my aim is to copy fields of one object into another, but only those that aren't null. I don't want to assign it explicitly. A more generic solution would be very useful and easier to maintain i.e. for implementing PATCH in REST API where you allow providing only specific fields.
I saw this similar thread and I'm trying to implement some of the ideas from here: Helper in order to copy non null properties from object to another ? (Java)
But the objects aren't altered in any way after the program execution.
So here are my example classes created for example:
class Person {
String name;
int age;
Pet friend;
public Person() {
}
public Person(String name, int age, Pet friend) {
this.name = name;
this.age = age;
this.friend = friend;
}
// getters and setters here
}
class Pet {
String name;
int age;
public Pet(String name, int age) {
this.name = name;
this.age = age;
}
// getters and setters here
}
Here is my overridden copyProperty method:
import org.apache.commons.beanutils.BeanUtilsBean;
import java.lang.reflect.InvocationTargetException;
public class MyBeansUtil extends BeanUtilsBean {
#Override
public void copyProperty(Object dest, String name, Object value)
throws IllegalAccessException, InvocationTargetException {
if(value == null) return;
super.copyProperty(dest, name, value);
}
}
... and here is the place I'm trying to test it on some examples:
public class SandBox {
public static void main(String[] args) {
Person db = new Person("John", 36, new Pet("Lucy", 3));
Person db2 = new Person("John", 36, new Pet("Lucy", 2));
Person db3 = new Person("John", 36, new Pet("Lucy", 4));
Person in = new Person();
in.age = 17;
in.name = "Paul";
in.friend = new Pet(null, 35);
Person in2 = new Person();
in2.name = "Damian";
Person in3 = new Person();
in3.friend = new Pet("Lup", 25);
try {
BeanUtilsBean notNull =new MyBeansUtil();
notNull.copyProperties(db, in);
notNull.copyProperties(db2, in2);
notNull.copyProperties(db3, in3);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
Unfortunately, the original objects db, db1, db2 stay the same as they were. Am I doing something wrong here?
I ended up using Spring BeanUtils library. Here is my working method:
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import java.lang.reflect.Field;
import java.util.Collection;
public class MyBeansUtil<T> {
public T copyNonNullProperties(T target, T in) {
if (in == null || target == null || target.getClass() != in.getClass()) return null;
final BeanWrapper src = new BeanWrapperImpl(in);
final BeanWrapper trg = new BeanWrapperImpl(target);
for (final Field property : target.getClass().getDeclaredFields()) {
Object providedObject = src.getPropertyValue(property.getName());
if (providedObject != null && !(providedObject instanceof Collection<?>)) {
trg.setPropertyValue(
property.getName(),
providedObject);
}
}
return target;
}
}
It works fine, but notice that it ignores fields that are collections. That's on purpose, I handle them separately.
You can create your own method to copy properties while ignoring null values.
public static String[] getNullPropertyNames (Object source) {
final BeanWrapper src = new BeanWrapperImpl(source);
java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();
Set<String> emptyNames = new HashSet<String>();
for(java.beans.PropertyDescriptor pd : pds) {
Object srcValue = src.getPropertyValue(pd.getName());
if (srcValue == null) emptyNames.add(pd.getName());
}
String[] result = new String[emptyNames.size()];
return emptyNames.toArray(result);
}
// then use Spring BeanUtils to copy and ignore null
public static void myCopyProperties(Object src, Object target) {
BeanUtils.copyProperties(src, target, getNullPropertyNames(src))
}
Using BeanUtils and java8 we can achieve this:
BeanUtils.copyProperties(Object_source, Object_target, getNullPropertyNames(Object_source));
private String[] getNullPropertyNames(Object source) {
final BeanWrapper wrappedSource = new BeanWrapperImpl(source);
return Stream.of(wrappedSource.getPropertyDescriptors()).map(FeatureDescriptor::getName)
.filter(propertyName -> wrappedSource.getPropertyValue(propertyName) == null).toArray(String[]::new);
}
Using ProprtyUtils, we can achieve this using:
private void copyNonNullProperties(Object destination,
Object source) {
try {
PropertyUtils.describe(source).entrySet().stream()
.filter(source -> source.getValue() != null)
.filter(source -> !source.getKey().equals("class"))
.forEach(source -> {
try {
PropertyUtils.setProperty(destination, source.getKey(), source.getValue());
} catch (Exception e22) {
log.error("Error setting properties : {}", e22.getMessage());
}
});
} catch (Exception e1) {
log.error("Error setting properties : {}", e1.getMessage());
}
}
I have faced a similar problem recently. I was asked to implement a generic solution for implementing PATCH in REST API where you allow providing only specific field.
The project is a Java one with MongoDB.
In the beginning I thought would be possible to solve using the Mongo java driver and the operation $set passing the document with only the fields that should be modified. After extensive researching I realized that it doesn't work this way. If you have nested classes it won't update selectively the inner class but instead replace it. I have tried several options using directly the Mongo java driver and SpringMongoDB java API.
Then I went to the BeanUtils solution as described by the author #kiedysktos.
public class MyBeansUtil extends BeanUtilsBean {
#Override
public void copyProperty(Object dest, String name, Object value)
throws IllegalAccessException, InvocationTargetException {
if(value == null) return;
super.copyProperty(dest, name, value);
}
}
It turns out that doing only this it won't work properly as well. Imagine you call your PATCH in the following way
{ "name": "John Doe",
"friend": {
"age":2
}
}
The intent of this call is to update the age of the single pet of John Doe to 2. However the overridden code above will replace the entire Pet structure to
{ "name": null,
"age" : 2
}
erasing the name information.
My final solutions was to call recursively where I found a nested inner class. This way each one will be copied maintaining the previous information. To do that each class involved should implement a marking interface.
Person implements NonNullCopy
Pet implements NonNullCopy
Finally, the code:
class NullAwareBeanUtils extends BeanUtilsBean {
#Override
public void copyProperty(Object dest, String name, Object value)
throws IllegalAccessException, InvocationTargetException {
if (value == null)
return;
else if(value instanceof NonNullCopy) {
Class<?> destClazz = value.getClass();
Class<?> origClazz = dest.getClass();
String className = destClazz.getSimpleName();
//Recursively invokes copyProperties
for(Method m : origClazz.getDeclaredMethods()) {
if(m.getReturnType().equals(destClazz)) {
copyProperties(m.invoke(dest, Collections.EMPTY_LIST.toArray()),value);
}
}
return;
}
super.copyProperty(dest, name, value);
}
}
Notice that this solution is generic if the class implements the marking interface.

Calling a method with an argument trough reflection

I have the following code which allows me to input in the scanner the Employee getter method that I want to call and it will do it using reflection (the name of the method should not appear anywhere in the code). This works for getter methods but I now need to modify the code to do something similar for setter methods. I have been trying to figure how to do it for the past week but I have been unable. Any help would be appreciated.
Thanks.
public static void main(String[] args) {
Employee e = Employee.testEmployee(); // a sample employee
Class cls = e.getClass();
Scanner scanner = new Scanner (System.in); // to parse data the user types in
String nextCommand;
// until the user enters "quit", get the next input from the user, and if it matches
// a given command, get the desired information from the employee object
do {
System.out.print("Enter command >> ");
nextCommand = scanner.next();
Method method = null;
try{
method = cls.getMethod(nextCommand);
}
catch(NoSuchMethodException x) {
}
try{
System.out.println(method.invoke(e));
}
catch(IllegalAccessException x) {
}
catch(java.lang.reflect.InvocationTargetException x) {
}
catch(NullPointerException x) {
}
} while (! nextCommand.equals("quit"));
}
Here's a code sample that does what you want to achieve:
public class Test {
private static HashSet<Class<?>> classes = new HashSet<>();
static {
classes.add(String.class);
classes.add(Integer.class);
classes.add(GregorianCalendar.class);
}
public static void main(String[] args) throws NoSuchMethodException,
SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
X obj = new X();
obj.setField("lala");
Method method = obj.getClass().getMethod("getField", null);
System.out.println(method.invoke(obj, null));
Method setMethod = getWorkingMethod(obj);
setMethod.invoke(obj, "who let the dogs out");
System.out.println(obj.getField());
}
private static Method getWorkingMethod(Object obj) {
Method method = null;
for (Class<?> c : classes) {
try {
method = obj.getClass().getMethod("setField", c);
} catch (NoSuchMethodException | SecurityException e) {
continue;
}
if(method != null){
return method;
}
}
throw new IllegalArgumentException("No such method found!");
}
}
class X {
private String stringField;
public void setField(String s) {
stringField = s;
}
public String getField() {
return stringField;
}
}
Output:
lala
who let the dogs out
Notes:
Create a collection (I used a HashSet) that stores Class<?> objects. You will use these to iterate over the possibilities and see if a method with that argument exists.
Use a try-catch to see if the method exists (an exception is thrown when it can't find it).
This will not work for overloaded methods. If this is your scenario, you'll have to make adjustments. I expect it to be no problem though, since you said this was meant for setters (which typically don't have overloads).
You can avoid calling the getter and setter methods by directly accessing the Field through reflection.
The Field object has various get and set methods that can be used to manipulate field values.
See: http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getField%28java.lang.String%29
EXAMPLE
import java.lang.reflect.Field;
public class MyObject {
private String fieldA;
public String getFieldA() {
return fieldA;
}
public void setFieldA(String fieldA) {
this.fieldA = fieldA;
}
public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
MyObject myObject = new MyObject();
myObject.setFieldA("Test");
Class clazz = myObject.getClass();
Field field = clazz.getDeclaredField("fieldA");
field.setAccessible(true);
String fieldA = (String) field.get(myObject);
System.out.println(fieldA);
field.set(myObject, "Test2");
fieldA = (String) field.get(myObject);
System.out.println(fieldA);
field.setAccessible(false); //be sure to return field to private
}
}
Resolution (method or field resolution) in java slows down you execution time by 'orders of 10 or 100', hence not a smart design decision. So, resolve once at start time, cache method instance, and execute it from cache. Avoid frequent lookups using reflection.

Categories

Resources