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