1

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.

2
  • 1
    Why would you expect it to return null? The value of age is 0, so the wrapped value is an Integer with a value of 0. If you're expecting to be able to tell the difference between having called dog.setAge(0); and not having called anything, then you need a different field type.
    – Jon Skeet
    Commented Sep 29, 2016 at 9:20
  • As @JonSkeet said, why are you expecting it to return null? When your int loads with the default value of 0 then when you wrap it in an Integer class it will still be 0...
    – px06
    Commented Sep 29, 2016 at 9:28

4 Answers 4

3

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).

1

You can check your fields for some of the primitive data types , using {primitive type}.TYPE , like for long, Long.TYPE and the same for others.

4
  • despite the voting down i think this is way better practice than changing the fields to non primitives Commented Sep 29, 2016 at 9:27
  • 1
    It depends what the requirements are. If the OP needs to tell the difference between the value having been set and it being the default, they need to change the field type. If they don't, that's a different matter.
    – Jon Skeet
    Commented Sep 29, 2016 at 9:29
  • I knew that changing the type to non-primitive would solve the problem, what I dont know is if it's the only solution. So following your answer I'd have to do checks for every primitive there is? And if object contains different types (primitive and non primitive) doing it would cause exceptions Commented Sep 29, 2016 at 9:33
  • As far as i know you will have to check all the primitives here which are 8 as i think, and no wont cause exception if you check for primitives after checking for null values, you only need to add the 8 primitive types to a list or map and check for its existance Commented Sep 29, 2016 at 9:39
1

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;
}
0

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]

Not the answer you're looking for? Browse other questions tagged or ask your own question.