1

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.

  • 2
    Is there a reason you're reinventing the wheel, rather than using one of the numerous JSON libraries already available? – Philip Kendall Jul 2 '17 at 9:49
  • Possible duplicate of Style for control flow with validation checks – gnat Jul 2 '17 at 10:45
  • Why is this a JSON problem? Isn't an object valid or invalid at a point in time, both as individual properties as they are set and as a while (siblingCount==0 and elderSiblingName not null) the validity is a general property no matter how the object is populated/constructed. – LoztInSpace Aug 2 '17 at 15:11
  • 1
    I'm with Philip and LotzInSpace. This sounds like a job for the Bean validation API. – Friek Aug 2 '17 at 20:28
2

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());
        }
        ...
    }
}
  • +1 for using lambdas to make the code easier to read. Not a fan of the rest, though. – Kent A. Aug 2 '17 at 14:03
  • Nitpicking: You can make your utility functions static as the don't use this for anything – Darkhogg Aug 2 '17 at 14:22
  • @amon: In Haskell you would simplify \x -> isNonEmpty x to isNonEmpty (pointfree style). Is it possible to do the same in Java with x -> isNonEmpty(x)? – Giorgio Oct 31 '17 at 18:31
  • 1
    @Giorgio You can use method references in Java, like this::isNonEmpty. However, I find those harder to teach than explicit lambdas. Java cannot use a method name on its own since variables and methods live in different namespaces: the syntax isNonEmpty would always be a variable or field, whereas isNonEmpty() or this::isNonEmpty always refers to a method. That makes Java a bit clumsy for functional programming. – amon Oct 31 '17 at 18:51
  • @Giorgio since this got bumped, you can also declare your predicate as a variable instead of a function like this: private Predicate<String> isNonEmpty = s -> s != null && !s.isEmpty(); and then you can refer to it by the variable name which is similar. – JimmyJames Nov 30 '17 at 17:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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