Java – How to validate many JSON fields without cluttering up the code with if-checks on each field

designdesign-patternsjavajsonobject-oriented

I have a class which contains various fields and they could be accessed with the help of getters and setters like the following

public class Student {

    private String name;
    private int age;
    private int sibblingsCount;
    private String elderSibblingName;
    private String youngerSibblingName;

    public String getName() {
        return this.name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return this.name;
    }
    public void setAge(int age) {
        this.age = age;
    }

    public void setSibblingsCount(int count) {
        this.sibblingsCount = count;
    }
    public int getSibblingsCount() {
        return this.sibblingsCount;
    }

    public void setElderSibblingName(String name) {
        this.elderSibblingName = name;
    }
    public String getElderSibblingName() {
        return this.elderSibblingName;
    }

    public void setYoungerSibblingName(String name) {
        this.youngerSibblingName = name;
    }
    public void getYoungerSibblingName() {
        return this.youngerSibblingName;
    }

    public String getStudentDetails() {    
        JSONObject json = new JSONObject();
        if(name != null && !name.isEmpty()) {
            json.put("name", this.name);
        }

        if(this.age != 0) {
            json.put("age", this.age);
        }

        if(this.sibblingsCount != 0) {
            json.put("sibblingsCount", this.sibblingsCount);
        }

        if(this.elderSibblingName != null && !this.elderSibblingName.isEmpty()) {
            json.put("elderSibblingName", this.elderSibblingName);
        }

        if(this.youngerSibblingName != null && !this.youngerSibblingName.isEmpty() {
            json.put("youngerSibblingName", this.youngerSibblingName);
        }
        return json.toString();
    }
}

All I need is to pack the valid fields in the class Student. The field is said to be valid when it contains some value in it. Say age should not be 0 and it must be a valid number. Say elderSibblingName it must not be null or empty. How to check for valid fields while packing the resultant JSON?

It is really painful to check for validity against each and every filed of the class which makes the code looks clumsy when there are too many fields in the class.

Best Answer

If you're bothered by your repetitive checks, extract them into a function to make them less repetitive. For example:

private static <T> void putIf(JsonObject json, String name, T value, Predicate<T> isValid) {
  if (isValid.test(value)) json.put(name, value);
}

private boolean isNonEmpty(String s) {
  return s != null && !s.isEmpty();
}

private boolean isNonZero(int i) {
  return i != 0;
}

public String getStudentDetails() {    
    JSONObject json = new JSONObject();

    putIf(json, "name", name, x -> isNonEmpty(x));
    putIf(json, "age", age, x -> isNonZero(x));
    putIf(json, "siblingsCount", siblingsCount, x -> isNonZero(x));
    putIf(json, "elderSiblingName", elderSiblingName, x -> isNonEmpty(x));
    putIf(json, "youngerSiblingName", youngerSiblingName, x -> isNonEmpty(x));

    return json.toString();
}

However, that doesn't address a fundamental problem of your class: The fields can contain invalid values! In many cases, that can be avoided by fully initializing the object in a constructor, and avoiding setters unless they also fully validate their values.

If your validation constraints are more complicated, you can also create your own types that represent a particular validation constraint, e.g.:

final class Name {
  private final String name;

  public Name(String name) {
    if (name == null || name.isEmpty())
      throw ...;
    this.name = name;
  }

  public String get() { return name; }
}

If a value has a particular meaning in your domain model, you should prefer a simple class like this over built-in or primitive types.

You can now use that class throughout your code, though you still have to check that the object is non-null:

public class Student {

    private Name name;
    ...
    private Name elderSibblingName;
    private Name youngerSibblingName;

    public Name getName() {
        return this.name;
    }
    public void setName(Name name) {
        this.name = name;  // assuming null is valid
    }

    ...

    public String getStudentDetails() {    
        JSONObject json = new JSONObject();

        if(name != null) {
            json.put("name", name.get());
        }
        ...
    }
}
Related Topic