简体   繁体   中英

Check if any field is null

I'm wondering if there is a shorter version for checking if any field of my ProfileDto is blank.

Upon searching the internet, I only found questions about how to check if a field is null or if all fields are null which is something totally different.

For context, if blank, it should take the respective field of the user object (which is just a call to the database). If notBlank, then it should take the ProfileDto field

private void setEmptyFieldsForUpdatedUser(User user, ProfileDto profileDto) {
    String newFirstName = profileDto.getFirstName();
    String newLastName = profileDto.getLastName();
    String newEmailAdres = profileDto.getEmail();
    String oldPassword = profileDto.getPassword();
    String newPassword = profileDto.getNewPassword();

    if (newFirstName == null) {
        profileDto.setFirstName(user.getFirstName());
    }
    if (newLastName == null) {
        profileDto.setLastName(user.getLastName());
    }
    if (newEmailAdres == null) {
        profileDto.setEmail(user.getEmail());
    }
}

This ProfileDto gives a JSON object. Which can have null-values. If it is null, I want to set the value with the previous user field which is in my database.

My database user has the following properties:

firstname: dj
lastname : test
email : dj@mail.com
password : qwerty

Input example:

{
    "firstName": "freeman",
    "lastName": null,
    "email": null
    "password": null,
    "newPassword" : null
}

My output should become:

{
    "firstName": "freeman",
    "lastName": "test",
    "email": "dj@mail.com",
    "password": "qwerty"
}

Obviously, we can see that if I have 20 more variables that I need a lot of if's so I was wondering if there was a better way.

Solution using JSON

As OP doesn't want to use reflection, another solution using jackson-databind dependency to do this with JSON:

Firstm we convert the class instances into a JsonTree . After that, we iterate over the fields of ProfileDto JSON, which also includes the null values and replace the null values with what we can find in the JSON for the User . We check that the user JSON has the field as to not cause exceptions. Finally, we convert the JsonTree back into an instance of ProfileDto :

ObjectMapper mapper = new ObjectMapper();
JsonNode userTree = mapper.valueToTree(user);
JsonNode dtoTree = mapper.valueToTree(dto);

Iterator<Entry<String, JsonNode>> fields = dtoTree.fields();
while (fields.hasNext()) {
    Entry<String, JsonNode> e = fields.next();
    if (e.getValue().isNull() && userTree.has(e.getKey())) {
        ((ObjectNode) dtoTree).put(e.getKey(), userTree.get(e.getKey()).asText());
    }
}
dto = mapper.treeToValue(dtoTree, ProfileDto.class);

I used following maven dependency:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.3</version>
</dependency>

Solution using Java reflection

A possible solution includes reflection. That way you can check all fields by just iterating them. This solution however requires that both classes have the same field names, or at least that those in the DTO are present in the user class

User user = new User();
user.setFirstName("dj");
user.setLastName("test");
user.setEmail("dj@mail.com");
user.setPassword("qwerty");
ProfileDto dto = new ProfileDto();
dto.setFirstName("test");

System.out.println(user);
System.out.println(dto);
System.out.println();

for (Field f : dto.getClass().getDeclaredFields()) {
    if (f.get(dto) == null) {
        try {
            f.set(dto, user.getClass().getDeclaredField(f.getName()).get(user));
        } catch (NoSuchFieldException e) {
            System.out.println("Field missing: " + f.getName());
        }
    }
}

System.out.println(user);
System.out.println(dto);

You can use the isBlank() method from the StringUtils class to check if a string is empty or contains only whitespace.

private void setEmptyFieldsForUpdatedUser(User user, ProfileDto profileDto) {
    String newFirstName = profileDto.getFirstName();
    String newLastName = profileDto.getLastName();
    String newEmailAdres = profileDto.getEmail();

    if (StringUtils.isBlank(newFirstName)) {
        profileDto.setFirstName(user.getFirstName());
    }
    if (StringUtils.isBlank(newLastName)) {
        profileDto.setLastName(user.getLastName());
    }
    if (StringUtils.isBlank(newEmailAdres)) {
        profileDto.setEmail(user.getEmail());
    }
}

This will check if any of the strings are empty or contain only whitespace, and if so, it will set the value of the corresponding field in the ProfileDto object to the value from the User object.

In case the number of variables increases, then to avoid checking explicitly for every variable, you can use the Map class to store the fields of the ProfileDto object and the corresponding setter methods for each field. Then you can just iterate over the Map and use the StringUtils.isBlank() method to check if a field is blank. If it is blank, you can use the setter method to set the corresponding field of the user object.

private void setEmptyFieldsForUpdatedUser(User user, ProfileDto profileDto) {
    Map<String, BiConsumer<ProfileDto, String>> setters = new HashMap<>();
    setters.put("firstName", ProfileDto::setFirstName);
    setters.put("lastName", ProfileDto::setLastName);
    setters.put("email", ProfileDto::setEmail);

    for (Map.Entry<String, BiConsumer<ProfileDto, String>> entry : setters.entrySet()) {
        String fieldName = entry.getKey();
        BiConsumer<ProfileDto, String> setter = entry.getValue();

        try {
            Method getter = ProfileDto.class.getMethod("get" + StringUtils.capitalize(fieldName));
            String fieldValue = (String) getter.invoke(profileDto);

            if (StringUtils.isBlank(fieldValue)) {
                Method userGetter = User.class.getMethod("get" + StringUtils.capitalize(fieldName));
                String userValue = (String) userGetter.invoke(user);
                setter.accept(profileDto, userValue);
            }
        } catch (Exception e) {
            
        }
    }
}

I guess it's not possible to check if any field is empty without using reflection (which is not very elegant).

To make your code shorter and more readable I recommend you to use Objects.requireNonNullElse() :

profileDto.setFirstName(Objects.requireNonNullElse(profileDto.getFirstName(), user.getFirstName()));

If you hava java 9 or later you can minimize your code a bit with the following

Optional.ofNullable(profileDto.getFirstName()).or(() -> Optional.ofNullable(user.getFirstName())).ifPresent(profileDto::setFirstName);
 //...same for each field

This way

  • If Dto field and entity field are both null there would be no assignment.
  • If Dto field has non null value it will always remain as it's current value as the first operator would be true and reassigned to DTO.
  • If Dto field has null value and entity field not null, the entity field would be assigned to Dto.

You could go with ternary expression, and just do it all in one line. (StringUtils class comes from apache commons)

String newFirstName = StringUtils.isBlank(profileDto.getFirstName()) ? user.getFirstName() : profileDto.getFirstName();
String newLastName = StringUtils.isBlank(profileDto.getLastName()) ? user.getLastName() : profileDto.getLastName();
String newEmailAdres = StringUtils.isBlank(profileDto.getEmail()) ? user.getEmail() : profileDto.getEmail();

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