Search code examples
javajsongsonbuilder

Gson not honouring rules in builder


I have a class called Student which has some required fields and others are optional. To make sure no object of the class Student is created without having provided required fields, I'm using a builder. Here's the class Student:

package prj1.dob;

import java.util.Date;

public class Student {
   private final int id;
   private final String name;
   private final String surname;
   private final Date dob;
   private final Double gpa;
   private final String email;

   public static class Builder {
      //required fields
      private int id;
      private String name;
      private String surname;

      //optional fields
      private Date dob;
      private Double gpa;
      private String email;

      public Builder(int id, String name, String surname) {
         this.id = id;
         this.name = name;
         this.surname = surname;
      }

      public Builder dob(Date dob) {
         this.dob = dob;
         return this;
      }

      public Builder gpa(Double gpa) {
         this.gpa = gpa;
         return this;
      }

      public Builder email(String email) {
         this.email = email;
         return this;
      }

      public Student build() throws Exception {
         return new Student(this);
      }
    }

    private Student(Builder b) throws Exception {
         this.id = b.id;
         this.name = b.name;
         this.surname = b.surname;
         this.dob = b.dob;
         this.gpa = b.gpa;
         this.email = b.email;
         validate();
     }

   private void validate() throws Exception {
      if (id < 10 || name == null || surname == null) {
        throw new Exception("You should provide an id, name and surname.");
   }
 }

 @Override
 public String toString() {
  return "Student [id=" + id + ", name=" + name + ", surname=" + surname + ", dob=" + dob + ", gpa=" + gpa  + ", email=" + email + "]";
    }
}

Having this implementation of the class Student, I would expect that there should not be a way of creating an invalid Student object (i.e. required fields should not be null). However, the code provided below does not throw an Exception and when I print the contents of Student the required fields are null.

JSON object:

{"id":-1,"name":null,"surname":null,"dob":null,"gpa":null,"email":null}

Here's the code that creates a POJO from JSON:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  try {
       String param = request.getParameter("std").toString();
       Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd").serializeNulls().create();
       Student student = gson.fromJson(param, Student.class);
       // student.validate();
       response.getWriter().write(student.toString());
  } catch (Exception ex) { 
       response.getWriter().write(ex.getMessage());
  }
}

I would expect it to throw an Exception but it creates an object of Student and when printed this is the contents:

Student [id=-1, name=null, surname=null, dob=null, gpa=null, email=null]

Is this a bug in the Gson library or am I not doing something right?

If this is how it should be, then what's the point of using the builder approach when one can still create an object of the class without following the rules (providing the required fields)?


Solution

  • GSON uses reflection and not your builder to construct the Student.

    While you can't stop other users of Student creating stuff willy-nilly using reflection, you can supply an JsonDeserializer which knows the rules for Student and creates one using your builder.