Migrating from JBoss to Glassfish
I recently migrated a J2EE application from JBoss 4.0.4-GA to Glassfish and experienced a number of different issues.
In this post I will describe the issues and the solutions to them in the hopes that it will help solve others headaches.
Issue #1 JBoss EJBQL != Glassfish(J2EE Spec) EJBQL
Take for example the following EJBQL that will function under JBoss:
“select object(s) from Slab as s where s.branch =”+branch;
Does not work properly under Glassfish unless (I believe, but not tested) you @Override the equals(Object) method
in your persistent entities.
A simple work around for those of us that are LAZY and do not feel like @Overriding all of those equals(Object) methods is to change your EJBQL to something like the following:
“select object(s) from Slab as s where s.branch.id =”+branch.getId();
Issue #2 Embeddable objects some how get referenced to Entities in the Glassfish Cache
To be honest I think this is a horrible feature of Glassfish but by no means am I going to spend the time to try
to change the Glassfish developer communities mind on it (And it could just be J2EE spec).
Take for instance the following Object Model:
1 2 3 4 5 6 7 8 9 10 11 | @Entity public class Customer implements Serializable { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) private Long id; @Column(name="c_name") private String name; @Embedded private Address address; //Magical get/set methods here } |
1 2 3 4 5 6 7 8 9 10 | @Embeddable public class Address implements Serializable { private String streetLineOne; private String streetLineTwo; private String city; private String state; private String postalCode; private String country; //Magical get/set methods here } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | @Entity @Table(name="belt_order_header") public class OrderHeader implements Serializable { public enum OrderStatus { BID, ORDER, INVOICE, HOLD, CONSIGNMENT } @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) private Long id; private OrderStatus status; private String poNumber; private String internalNotes; private ShipVia shipVia; @Embedded @AttributeOverrides( { //Magical Overrides } ) private Address billTo; @Embedded @AttributeOverrides( { //Magical Overrides } ) private Address shipTo; @ManyToOne private Customer customer; @ManyToOne private Branch billingBranch; @ManyToOne private Branch fabricationBranch; //Magical get/set methods here } |
If I were to try the following in a Session Bean:
1 2 3 4 5 6 7 | public OrderHeader createOrderHeader(Customer customer) { OrderHeader oh = new OrderHeader(); oh.setBillTo(customer.getAddress()); oh.setShipTo(customer.getAddress()); em.persist(oh); return oh; } |
It would throw some narly unreadable and annoying Exception. The reason you ask? It happens because
the PersistentContext has associated the Address object to the Customer.
The work around is to create in the Address object a static method that copies the attributes
from one Address object to a new one. Like the following:
1 2 3 4 5 6 7 8 9 10 | public static Address copy(final Address address) { Address copy = new Address(); copy.setStreetLineOne(address.getStreetLineOne()); copy.setStreetLineTwo(address.getStreetLineTwo()); copy.setCity(address.getCity()); copy.setState(address.getState()); copy.setCountry(address.getCountry()); copy.setPostalCode(address.getPostalCode()); return copy; } |
And redo the OrderHeader method as such:
1 2 3 4 5 6 7 | public OrderHeader createOrderHeader(Customer customer) { OrderHeader oh = new OrderHeader(); oh.setBillTo(Address.copy(customer.getAddress())); oh.setShipTo(Address.copy(customer.getAddress())); em.persist(oh); return oh; } |
Issue #3 Once again the GlassFish cache
Since there is a great article on this I will just link it. Just remember REFRESH, REFRESH, REFRESH!
http://weblogs.java.net/blog/guruwons/archive/2006/09/understanding_t_1.html
Here is a example of what I mean:
1 2 3 4 5 6 7 8 9 10 11 12 13 | public BeltType find(Object pk) { BeltType beltType = (BeltType) em.find(BeltType.class, pk); try { em.refresh(beltType); } catch(EntityNotFoundException ex) { return null; } if(beltType == null) return null; loadLazyInitializations(beltType); return beltType; } |