In the last post, I was discussing about the solutions to the ClassCastException caused by typecasting the child entity to the parent entity. Using the proxy interfaces did solve the issue but not a better solution. The second solution Proxy Visitor Pattern is being discussed in the hibernate user forums.
Before discussing the Proxy Visitor Pattern, let me explain the other possible solution (but again not a great one). The main issue that we are stuck with is we can’t cast the child class to the proxy object as the proxy doesn’t extend the child class but the actual child entity is hidden within the proxy object. Fortunately hibernate does allow us to retrieve the actual entity being held by the proxy object.
Seller seller = (Seller)((HibernateProxy)proxyEntity).getHibernateLazyInitializer().getImplementation();
If you would like to hide the hibernate usage in your application layer, you can always move this to the DAO layer. But just imagine, whenever you are going to refer to the polymorphic entity, you have to get the implementation and work with it.
Now back to the Proxy Visitor Pattern, the example being discussed there is in reference to a collection of polymorphic entities. I have to admit that it did took some time to understand how it would work. I had a similar kind of requirement, but its not something to deal with a collection but rather a single entity. In fact the visitor pattern looks powerful when dealing with collections but not the case with a single entity (at least from what I have understood
). In my requirement, I had to deal with the payment account chosen by the buyer for an order.
public class PaymentAccount {
public String getName(){};
public void setName(String name){};
public String getPaymentType(){};
public void setPaymentType(String type){};
}
public class OnlinePaymentAccount extends PaymentAccount {
public String getServiceUrl(){};
}
public class OfflinePaymentAccount extends PaymentAccount {
public boolean isMoneyOrderAllowed(){};
public void setMoneyOrderAllowed(boolean allowed){};
}
public class XyzPaymentAccount extends OnlinePaymentAccount {
public String getMerchantApiToken(){};
public void setMerchantApiToken(String token){};
public String getMerchantId(){};
public void setMerchantId(String id){};
}
public class AbcPaymentAccount extends OnlinePaymentAccount {
public String getUserName(){};
public void setUserName(String userName){};
public String getPassword(){};
public void setPassword(){};
}
So say I do a find by id for this payment entity and assume the row corresponds to AbcPaymentAccount, how would I get the username/Password ??? If I were to follow what’s being explained in the proxy visitor pattern, I should have a Visitor interface being used by the PaymentAccount class as below,
public interface PaymentAccountVisitor {
public void visit(OfflinePaymentAccount account);
public void visit(XyzPaymentAccount account);
public void visit(AbcPaymentAccount account);
}
public class PaymentAccount {
public String getName(){};
public void setName(String name){};
public String getPaymentType(){};
public void setPaymentType(String type){};
// to accept the visitor
public void accept(PaymentAccountVisitor visitor) {
visitor.visit(this);
}
}
So in my application I have to do some thing like this to get the username/password,
PaymentAccount account = order.getPaymentAccount();
if(account.getPaymentType().equals("Abc")) {
String username = null;
String password = null;
PaymentAccountVisitor visitor = new PaymentAccountVisitor() {
public void visit(OfflinePaymentAccount account) {
// do nothing
}
public void visit(XyzPaymentAccount account) {
// do nothing
}
public void visit(AbcPaymentAccount account) {
username = account.getUserName();
password = account.getPassword();
}
};
}
Uhh… just to call a couple of getters, I have to write such a huge code
Though its an elegant solution certainly not a solution I would like to go with. I would prefer going with the proxy interfaces for both the class and joined-subclass and cast them to the class I’m interested in instead of writing a huge piece of code just for calling a getter.
I’m eagerly waiting for someone to come up with a better solution (or shout at me that my understanding of the Visitor Pattern solution is wrong
) for this problem !!











2010 in review « Dumb Programmer said
[...] Hibernate inheritance ClassCastException (Part 2) February 2009 [...]