How to check if Runtime Object passed is empty or not in Java

In this tutorial you will learn how to check if Object passed during runtime is empty or not.

If we take a look at Spring IO documentation there is Utility named ObjectUtils which has isEmpty method which handles to an extent.

More info can be found below.

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/util/ObjectUtils.html

Also, Apache commens has one more implementation which checks for object emptiness.

Below is documentation extract which apache says:-

 public static boolean isEmpty(Object object)
Checks if an Object is empty or null.
 The following types are supported:
CharSequence: Considered empty if its length is zero.
Array: Considered empty if its length is zero.
Collection: Considered empty if it has zero elements.
Map: Considered empty if it has zero key-value mappings.
ObjectUtils.isEmpty(null) = true
ObjectUtils.isEmpty("") = true
ObjectUtils.isEmpty("ab") = false
ObjectUtils.isEmpty(new int[]{}) = true
ObjectUtils.isEmpty(new int[]{1,2,3}) = false
ObjectUtils.isEmpty(1234) = false 

Now, lets take scenario where we have custom class say Employee.java as below.

@Data
public class Employee {
    private Long id;
    private String name;
    private Department dept;
    private Integer sal;
}

And now if we use inbuilt ObjectUtils then it wont work and returns ‘false’ when employee object is passed as below.

public class ObjectEmptyCheckerApp {
    public static void main(String[] args) {
        Employee emp = new Employee();
        System.out.println("ObjectUtils.isEmpty(emp) ->"+ObjectUtils.isEmpty(emp));
    }
}

O/p:- ObjectUtils.isEmpty(emp) ->false

So plain old reflection is resuce,

We can start our solution with below simple reflection code to handle above scenario.

    public static boolean isEmpty(Object obj){
        for(Field field : obj.getClass().getDeclaredFields()){
            try{
                field.setAccessible(true);
                if(field.get(obj) != null){
                    return false;
                }
            } catch (IllegalAccessException e) {
              // log exception here
            }
        }
        return true;
    }

If we check with above method call it prints true, meaning object is empty.

Lets take next step and enhance our Employee.java to accomodate Serializable interface

@Data
public class Employee implements Serializable {
    private static final long serialVersionUID = 123762933382L;
    private Long id;
// others
}

Now if we check isEmpty then it will fail, reason being serialVersionUID is not empty but functionally we expect object to be null.

So isEmpty(Object obj) method needs to be enhanced as below

public static boolean isEmpty(Object obj){
    for(Field field : obj.getClass().getDeclaredFields()){
        try{
            field.setAccessible(true);
            if(field.get(obj) != null && !field.getName().equals("serialVersionUID")){
                return false;
            }
        } catch (IllegalAccessException e) {
            // log exception here
        }
    }
    return true;
}

Now what if we have Logger inside Employee.java as below ? It fails again and so on.

import com.sun.org.slf4j.internal.Logger;
import com.sun.org.slf4j.internal.LoggerFactory;
import lombok.Data;

import java.io.Serializable;

@Data
public class Employee implements Serializable {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    private static final Boolean letsFailReflection = Boolean.TRUE;
    private static final long serialVersionUID = 123762933382L;

    private Long id;
    private String name;
    private Department dept;
    private Integer sal;
}

So we can upgrage isEmpty again as below(which is generic in nature) also making use of ObjectUtils as below.

import com.google.common.collect.ImmutableSet;
import com.sun.org.slf4j.internal.Logger;
import dtos.Employee;
import org.apache.commons.lang3.ObjectUtils;

import java.lang.reflect.Field;
import java.util.Set;

public class ObjectEmptyCheckerApp {

    //Add fields and classes which needs to be excluded to determine object emptyness
    private static Set<String> excludedFieldNames = ImmutableSet.of("serialVersionUID");
    private static ImmutableSet<Class<? extends Object>> excludedFieldTypes = ImmutableSet.of(Logger.class, Boolean.class);

    public static void main(String[] args) {
        Employee emp = new Employee();
        System.out.println( "isEmpty(emp) ->"+isEmpty(emp)); // Returns true
        System.out.println( "isEmpty(new int[]{}) ->"+isEmpty(new int[]{})); // Returns true
    }
    public static boolean isEmpty(Object obj){
        //Making use of ObjectUtils
        if(ObjectUtils.isNotEmpty(obj)){

            //Making use of reflection
            for(Field field : obj.getClass().getDeclaredFields()){
                try{
                    field.setAccessible(true);
                    if(field.get(obj) != null && !excludedFieldNames.contains(field.getName())
                            && !excludedFieldTypes.contains(field.getType())){
                        return false;
                    }
                } catch (IllegalAccessException e) {
                    // log exception here
                }
            }
        }
        return true;
    }
}

Also, if in case if findbugs complains about security issue, then use below code.

AccessController.doPrivileged(new PrivilegedAction() {
    @Override
    public Object run() {
        field.setAccessible(true);
        return null;
    }
});

Leave a Reply

Your email address will not be published. Required fields are marked *

16 − 14 =