简体   繁体   中英

Checking if object contains null values

I want to write a method that checks if given object contains fields of null value. What I've written works fine BUT the problem occurs with primitive types.

public static <T> List<String> checkIfNullsInObject(T ob) {

        List<String> fieldsAsNull = new LinkedList<>();

        for (Field f : ob.getClass().getDeclaredFields()) {
            f.setAccessible(true);
            try {
                if (Objects.isNull(f.get(ob))) {
                    fieldsAsNull.add(f.getName());
                }
            } catch (Exception e) {
                e.getMessage();
                e.printStackTrace();
            }
        }
        return fieldsAsNull;
    }

so eg.

class Dog:

public class Dog {
    private String name;
    private int age;
    private String owner;
///set get
}

given Object :

Dog dog = new Dog();
        // dog.setAge(44);
        // dog.setName("Maniek");
        // dog.setOwner("AZE");

the method should return "age , name ,owner", but it only returns two last one. I know that int is set to 0, and therfore it is not considered as null because of beeing primitive type and not a refrence to null.

The java doc about Field.get(Object o) method says :

Returns the value of the field represented by this Field, on the specified object. The value is automatically wrapped in an object if it has a primitive type.

If it's wrapped to object I'd expect it to return null, not zero what am I missing here? Is it unwrapped once again somewhere in between?

/////////////////////////////////////////////////////

I knew that changing type to Wrapper class would do the job, but I'm not sure if changing another class because of adding another class is good practice therefore I've decided to do soemthing like this:

public static <T> void  checkIfNullsInObject(T ob) throws DataInputException {
        try {
            for (Field f : ob.getClass().getDeclaredFields()) {
                f.setAccessible(true);
                if (Objects.isNull(f.get(ob)) || checkForZeroPrimitives(ob, f)) 
                    throw new DataInputException("Can not update entity with field \"" 
                            + f.getName() + "\" set to: " + f.get(ob));
            }
        } catch (IllegalArgumentException |IllegalAccessException e) {
            e.getMessage();
            e.printStackTrace();
        }

    }

    private static <T> boolean checkForZeroPrimitives(T ob, Field field) throws IllegalArgumentException, IllegalAccessException {
        if (field.getType().getName().equals("int") && field.getInt(ob) == 0)
            return true;
        if (field.getType().getName().equals("double") && field.getDouble(ob) == 0.0)
            return true;
        if (field.getType().getName().equals("float") && field.getFloat(ob) == 0)
            return true;
        if (field.getType().getName().equals("long") && field.getLong(ob) == 0)
            return true;
        if (field.getType().getName().equals("short") && field.getShort(ob) == 0)
            return true;
        if (field.getType().getName().equals("byte") && field.getByte(ob) == 0)
            return true;
        if (field.getType().getName().equals("char") && field.getChar(ob)=='\u0000')
            return true;
        return false;
            }

later on I intend to improve the -if ladder.

That's because it wrapped the primitive with the Object, not the other way around. Which means that age is 0 in your dog , then you get its value which is wrapper to an Integer. So the Integer contains 0 (when not set, an int automatically has a value of 0).

If you want your age to be able to be null, you have to use the wrapping object ( Integer ) instead of the primitive ( int ).

您可以使用{primitive type} .TYPE检查字段中的某些原始数据类型,例如long, Long.TYPE以及其他类型。

Your code will work if you'll use wrappers for primitive types like below:

public class Dog {
    private String name;
    private Integer age;
    private String owner;
}

It's because you declared that as primitive and it's (int) default value is zero. If you want to handle that as well in that case handle it in your method itself.

Objects.isNull(f.get(ob)) || (f.getType().getName().equals("int") && ((Integer)f.get(ob)).intValue() == 0)

Like this you will be able to get even if any int field is assigned to zero.eg. age (This field can never be zero)

If you will use Integer in that case you don't have to do any thing.

    private Integer age;

    private int number;

    private String role = "";

private void testNull(){
        Test ob = new Test();
        List<String> fieldsAsNull = new LinkedList<>();
        for (Field f : ob.getClass().getDeclaredFields()) {
            f.setAccessible(true);
            try {
                if (Objects.isNull(f.get(ob)) || (f.getType().getName().equals("int") && ((Integer)f.get(ob)).intValue() == 0)) {
                    fieldsAsNull.add(f.getName());
                }
            } catch (Exception e) {
                e.getMessage();
                e.printStackTrace();
            }
        }
        System.out.println(fieldsAsNull);
}

Output : [age, number]

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