Qwello Lee
Qwello Lee

Reputation: 41

Is there a way to send instances of different subclasses of a serializable class?

I've built a client-server application, with working connection setup and handling. I would like the client to send requests of different types, each with unique fields but all of which inheriting from a "Request" superclass. Is there a way to do this?

For example I have a Foo class that implements serializable

class Foo implements Serializable{

public String name;

public Foo() {
    this.name = "Default";
}

public Foo(String name) {
    this.name = name;
}
}

and two subclasses that extend it

class BarOne extends Foo {

public String name;
public int id;

public Bar(String name, int id) {
    super(name);
    this.id = id;
}
}

class BarTwo extends Foo {

public String name;
public String lastName;

public Bar(String name, String lastName) {
    super(name);
    this.lastName = lastName;
}
}

Is there a way to have the client send instances of BarOne and BarTwo through an ObjectOutputStream and have the server figure out whether what it receives is an intance of one or the other?

Upvotes: 1

Views: 67

Answers (1)

AxelH
AxelH

Reputation: 14572

There is no restriction here, you can serialize a subclass without difficulties.

Here, I provide a quick example using a the same structure as yours (but with specific example).

The abstract class.

public abstract class Pojo implements Serializable {

    private static final long serialVersionUID = -4947411931465651278L;

    protected int id;

    public Pojo() {
        // TODO Auto-generated constructor stub
    }

    public Pojo(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

The first subclass Person

class Person extends Pojo {

    private static final long serialVersionUID = -7814628079202659483L;

    private String name;
    private int age;

    public Person(int id, String name, int age) {
        super(id);
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", id=" + id + "]";
    }
}

The second subclass Address

class Address extends Pojo {

    private static final long serialVersionUID = -8266402026827561883L;

    private String address;
    private String city;

    public Address(int id, String address, String city) {
        super(id);
        this.address = address;
        this.city = city;
    }

    @Override
    public String toString() {
        return "Address [address=" + address + ", city=" + city + ", id=" + id
                + "]";
    }
}

You can then create a collection for this example that will hold both type of instance :

List<Pojo> pojos = new ArrayList<>();
pojos.add(new Address(1, "Address 1", "city1"));
pojos.add(new Address(2, "Address 2", "city2"));
pojos.add(new Person(1, "Name1", 5));
pojos.add(new Person(2, "Name2", 10));
pojos.add(new Person(3, "Name3", 15));

You can use a file for the serialization (because I don't have time to create a socket system ;) ) using :

private static void serialize(String filename, Serializable data)
        throws IOException {
    try (OutputStream outStream = new FileOutputStream(filename);
            ObjectOutputStream fileObjectOut = new ObjectOutputStream(
                    outStream)) {
        fileObjectOut.writeObject(data);
    }
}

private static Object deserialize(String filename) throws IOException,
        ClassNotFoundException {
    try (InputStream inStream = new FileInputStream(filename);
            ObjectInputStream fileObjectIn = new ObjectInputStream(inStream)) {
        return fileObjectIn.readObject();
    }
}

Let serialize and deserialize the list to see if the type are recovered :

serialize("data.ser", pojos);
List<Pojo> tmp = deserialize("data.ser");
System.out.println(tmp);

And you will see the result with the correct type of instance :

[
    Address [address=Address 1, city=city1, id=1], 
    Address [address=Address 2, city=city2, id=2], 
    Person [name=Name1, age=5, id=1], Person [name=Name2, age=10, id=2], 
    Person [name=Name3, age=15, id=3]
]

So you could do the same with anything, serialize just a Person, you will need to recover the Object first and use an instanceof to see what is the type recovered.

Pojo p1 = new Person(1, "Name1", 10);
serialize("person.ser", p1);
Object o1 = deserialize("person.ser");

System.out.println(o1);
System.out.println(o1.getClass());
System.out.println(o1 instanceof Person);

Output

Person [name=Name1, age=10, id=1]
class serial.Person
true

Upvotes: 1

Related Questions