Generics - re-writed version

Hello all. I am building a small app that requires a persistence manager to save objects in an xml repository file.

I am trying to use generics to see if I can avoid casting objects from a general super class to concrete class. Lets say Entity and Person.

For a store method. I wrote this:

public <Eextends Entity>void store(E entity);

Lets say that inside store method I delegate the translation from the entity Person or whatever to a Node element. Somewhere you would have to cast the E type (from generics) to Person. right? like:

persistence manager code:

privatevoid save(Person person){

..transform the object to xml and save it

}

public <Eextends Entity>void store(E entity){

this.save((Person)entity);

}

client code:

Person person =new Person("Jon","Stewart");

myStorage.store(person);

May be the GET statement would be easier to understand. My get looks something like this:

persistence manager code:

public <Eextends Entity> E getEntity(int id){

returnnull;

}

client side code:

Person person = myStorage.get(32);

I avoid casting from the client side by using generics here.

How can I best avoid casting?

You see, I am trying to avoid Casting as much as I can.

I have to translate an entity to an xml node, then append the node to a parent node, thus persisting it to the original document.

I created some XmlTranslators. and a subclass for each different type of entity. I don't think this is such a good aproach. But I didn't had any better Idea at the time (would be great to hear sugestions).

I have a Switch statement that evaluates the entity.entityType (an enumerator type) and as I showed before in the example I cast to the subclass type (Person).

Am I doing this the right way? or just the complicated way.

My goal is to reduce code in store methods and avoid as much casting as I can.

May be by trying to do it all I got a little lost. If some one could share his/her views on the matter and maybe show me a better practice, I would appreciate it very much.

[2867 byte] By [franciscodiaztrepata] at [2007-11-27 9:27:44]
# 1

I am not sure, what you try to achieve. Why do you define the Generic parameter on store and get methods? If the class/interface stores various subtypes of Entity, there is no further use for generics as far as I can see your code. If you can have typed persistance managers, the Generic parameter should be defined for the class, so the methods will "inherit" the concrete type.

stefan.schulza at 2007-7-12 22:30:27 > top of Java-index,Core,Core APIs...
# 2

You are right.

And for the return type of the get method?

I mean I would like a way to avoid casting without saying:

public Person getPerson()

public Home getHome()

etc. that is why I thought that this would work.

public <E extends Entity> E getEntity();

Home home = getEntity();

Person per= getEntity();

What do you think I should do?

I have the clasic

Client

ServiceInterface

ServiceImp

In the form of:

Client

Storage

XmlStorage

f(t)

franciscodiaztrepata at 2007-7-12 22:30:27 > top of Java-index,Core,Core APIs...
# 3

To make use of generics, you must have knowledge about the types at compile time. If the instance you call getEntity on does not have this information, there is no real use to provide a method implicitly casting to your type (as this may fail any time). If the instance knows about it, you can implement something like follows:public interface EntityProvider<E extends Entity> {

public E getEntity(int id);

public void store(int id, E entity);

}

public class PersonProvider implements EntityProvider<Person> {

public Person getEntity(int id) { ... }

public void store(int id, Person person) { ... }

}

Alternatively a generic Provider class, operating on E that will be instantiated with the concrete Entity-type as generic parameter.

stefan.schulza at 2007-7-12 22:30:27 > top of Java-index,Core,Core APIs...
# 4
Right. But still the client code or the store would have to cast from Entity to Person anyways.Is this correct?You are bound to Casting. Or writing all the method for it.f(t)
franciscodiaztrepata at 2007-7-12 22:30:27 > top of Java-index,Core,Core APIs...
# 5
In a client-server scenario I'd guess you will have to cast on both ends, as you will receive serialized data. But if the above applies to your scenario, you might hight the casting from users of your code.
stefan.schulza at 2007-7-12 22:30:27 > top of Java-index,Core,Core APIs...
# 6

Right. My conclussion exactly.

Now. If I have a :

public <E extends entity> void save(E entity){

if(entity.type==person)

this.doSave((Person)entity)l;

}

And I call:

save(person);

Wouldn't that constitute a cast of (Person)personType?

If that is the case, that the java vm reduces the cost of casitng to the same object?

And if so, that the same applies to a super class and a subclass;

Person person; save(Entity entity) cast Person;

f(t)

franciscodiaztrepata at 2007-7-12 22:30:27 > top of Java-index,Core,Core APIs...
# 7

> Wouldn't that constitute a cast of (Person)personType?

Yes

.

> If that is the case, that the java vm reduces the

> cost of casitng to the same object?

No. It doesn't know it's the same type until it tries the cast.

This sounds like a job for the Visitor pattern actually.

ejpa at 2007-7-12 22:30:27 > top of Java-index,Core,Core APIs...
# 8

> > Wouldn't that constitute a cast of

> (Person)personType?

>

> Yes

> .

> > If that is the case, that the java vm reduces the

> > cost of casitng to the same object?

>

> No. It doesn't know it's the same type until it tries

> the cast.

>

> This sounds like a job for the Visitor pattern

> actually.

I'll check it out.

Thanks, there must be a way without having to go to squeak.

>_>

<_<

f(t)

franciscodiaztrepata at 2007-7-12 22:30:27 > top of Java-index,Core,Core APIs...
# 9

You could have the Person entity declare methods which can be called back from the storate.store(E entity)

Something like :

class Peson extends Entity{

@PreSave

void preSave() {

}

@PostSave

void preSave() {

}

}

And then in storage

class EntityStorage {

public <E extends Entity> void store(E entity) {

invokePreSave(entity);

save(entity)

invokePostSave(entity);

}

}

This way you will not need to cast entity to Person.

HTH

-Prashant

cprashantreddya at 2007-7-12 22:30:27 > top of Java-index,Core,Core APIs...