简体   繁体   中英

How to null check and return a value in a generic way

I have a long list of object mapping to do from classes auto generated by JAXB.

 customer.setCustomerId(rentalCustomer.getCustomerid().getValue()));
 customer.setCustomerName(rentalCustomer.getTradingname().getValue());
 customer.setVatNumber(rentalSearchCustomer.getVatNumber().getValue());
 ....
 ....

Basically I need to make a null check for ALL fields:

getValue(RentalCustomerIDType idType){
  if(idType != null){
    return idType.getValue();
  }
  else {
   return "";
 }
}

Problem is there are too many of these and they all have different types: RentalCustomerIDType, TradingType, VatNumberType..etc

Is there an elegant way to this by creating a GENERIC method that makes null check and return proper values for ALL maybe using Functional Libraries for Java?

Perhaps use reflection on the class when it's generated and eliminate all nulls by assigning non-null values to the fields?

Check an replace null values in multiple variables java

They say (the guy who answered) that they strongly disagree with using reflection for this purpose... but... meh. I've done it and it works.

You could use a generic method to declare the getValueFromAllObjects method and then use reflection to invoke the getValue method

public static <T> String getValueFromAllObjects(T t) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
  if(t != null){
    return (String) t.getClass().getDeclaredMethod("getValue").invoke(t);
  }
  else {
   return "";
 }
}

Refer to https://stackoverflow.com/a/54883454/442256 for reflection alternatives. I've just inlined an example in your code above

From what I understand, you do not want to be changing existing auto-generated classes. What you can do is create a CustomerWrapper class that wraps Customer and inserts defaults when a null is set to a field. This is the idea in code:

public class CustomerWrapper() {

    private final Customer customer;

    public CustomerWrapper(Customer customer) {
        this.customer = customer;
    }

    public void setCustomerId(String id) {
        this.customer.setCustomerId(id == null ? "" : id);
    }

    // Insert other methods here.

}

This does what you want. But there is a caveat. Each type must implement the same interface that provides the getValue() method. Otherwise, you will probably need reflection to get the method as you suspected. But here is a solution for posterity.

setType(rentalSearchCustomer::getCustomerid,
        customer::setCustomerId);
setType(rentalSearchCustomer::getTradingname,
        customer::setCustomerName);
setType(rentalSearchCustomer::getVatNumber,
        customer::setVatNumber);
System.out.println(customer);
        
    
    
public static <T extends GetValue> void setType(Supplier<T> sup,
        Consumer<String> con) {
    if (sup.get() == null) {
        con.accept("");
    } else {
        con.accept(sup.get().getValue());
    }
}
    
interface GetValue {
    public String getValue();
}

I guess you want to use something like. here I have taken ResponseUserDto as my Pojo Class for null checks of it's properties.

private ResponseUserDto getValidNotNullPropertyObject(Object source) {
    final BeanWrapper src = new BeanWrapperImpl(source);
    Map < String, Object > result = new HashMap<>();
    for (PropertyDescriptor property: src.getPropertyDescriptors()) {
        if (src.getPropertyValue(property.getName()) == null) {
            /* if(property.getPropertyType() == ?) {
                    //maybe do somethig here
                }*/
            result.put(property.getName(), ""); // this is start
        } else {
            result.put(property.getName(), src.getPropertyValue(property.getName()));
        }
    }
    final ObjectMapper mapper = new ObjectMapper(); // Jackson's ObjectMapper
    final ResponseUserDto finalResult = mapper.convertValue(result, ResponseUserDto.class);
    return finalResult;
}

and to use this, you can call it like this

return this.getValidNotNullPropertyObject(responseUserDto);

maybe a case for Aspect Oriented Programming, if its use is an option:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM