Search code examples
javagenericsbounded-types

Java bounded types


I'm trying to understand bounded types in Java. I think that my reasoning is almost correct but I get an error and I don't understand why it gives me that error if A (JsonPerson) is a subclass of T (Person). The error is the following (also commented in the code):

Error:(22, 16) error: incompatible types: JsonPerson cannot be converted to A
where A is a type-variable:
A extends Person declared in method <A>fromJson(JSONObject)

The error "happens" in the return line.

I've made a simple example, here is the code

Person.java

public class Person {

    private String name;

    private String surname1;

    private String surname2;

    private String phone;

    private String email;

    public Person(String name, String surname1, String surname2, String phone, String email) {
        this.name = name;
        this.surname1 = surname1;
        this.surname2 = surname2;
        this.phone = phone;
        this.email = email;
    }

    public String getName() {
        return name;
    }

    public String getSurname1() {
        return surname1;
    }

    public String getSurname2() {
        return surname2;
    }

    public String getPhone() {
        return phone;
    }

    public String getEmail() {
        return email;
    }

}

JsonPerson.Java

public class JsonPerson extends Person implements JSONSerializableInterface<Person> {

    public JsonPerson(String name, String surname1, String surname2, String phone, String email) {
        super(name, surname1, surname2, phone, email);
    }

    /**
     * Error:(22, 16) error: incompatible types: JsonPerson cannot be converted to A
     * where A is a type-variable:
     * A extends Person declared in method <A>fromJson(JSONObject)
     * */
    @Override
    public <A extends Person> A fromJson(JSONObject json) throws JSONException {
        String name = json.getString("name");
        String surname1 = json.getString("surname1");
        String surname2 = json.getString("surname2");
        String phone = json.getString("phone");
        String email = json.getString("email");
        return new JsonPerson(name, surname1, surname2, phone, email);
    }

    @Override
    public JSONObject toJson(Person object) {
        return null;
    }
}

JSONSerializableInterdace.java

public interface JSONSerializableInterface<T> {

    public <A extends T> A fromJson(JSONObject json) throws JSONException;

    public JSONObject toJson(T object);
}

Solution

  • Signatures like

    public <A extends T> A fromJson(JSONObject json)
    

    don't really make a lot of sense. This says that the type of the object returned is decided by the caller. The caller could supply a type witness e.g. <CleverPerson> to the method, and expect a CleverPerson to be returned, but there's no way this could work unless the type is explicitly passed to the method (otherwise the type A is not even available at runtime). Something like this would make sense:

    public <A extends T> A fromJson(Class<A> clazz, JSONObject json)
    

    However, I think it may be preferable to go for this instead:

    public T fromJson(JSONObject json)