@SuppressWarnings("unchecked") seems too broad (you have to annotate a whole method for just a line of code) this has an interesting suggestion. Interesting java syntax, too.
My adventures as a Java dev, but expect other techs I explore to show up here from time to time
Saturday, May 26, 2007
Annoying warnings
If you are annoyed by warnings about unchecked conversions and the
Tuesday, May 22, 2007
All about singletons
Thursday, May 17, 2007
Field access vs Property access in JPA
JPA allows for two types of access to the data of a persistent class. Field access which means that it maps the instance variables (fields) to columns in the database and Property access which means that is uses the getters to determine the property names that will be mapped to the db. What access type it will be used is decided by where you put the @Id annotation (on the id field or the getId() method).
I have developed a preference for field access mainly for two reasons. First, because I frequently define getter methods that are not property accessors e.g. a getter that does not just return the value of a field but does a calculation and returns the result. In that case (and if you use property access) you have to annotate the getter with @Transient. If you forget to do this (as I did many times) you are looking for trouble. JPA will think that the getter corresponds to a property and funny things will happen.
The second reason I prefer field access is that with property access you have to define getter methods for every field just for use by JPA even if your code will never call them.
Until now I haven't find any argument in favor of property access but I would like to hear if anybody has.
I have developed a preference for field access mainly for two reasons. First, because I frequently define getter methods that are not property accessors e.g. a getter that does not just return the value of a field but does a calculation and returns the result. In that case (and if you use property access) you have to annotate the getter with @Transient. If you forget to do this (as I did many times) you are looking for trouble. JPA will think that the getter corresponds to a property and funny things will happen.
The second reason I prefer field access is that with property access you have to define getter methods for every field just for use by JPA even if your code will never call them.
Until now I haven't find any argument in favor of property access but I would like to hear if anybody has.
Wednesday, May 2, 2007
Transaction management and JPA
My current project is a web application with Struts in the web tier, a stateless session ejb (EJB3) in the middle tier and various entity pojos (JPA) that model the data. The application server is Jboss 4.2.0.CR2 that uses Hibernate as the persistence provider.
In this configuration with container-managed transactions, the transaction boundary is the ejb method call. Struts action classes make calls to the session ejb methods in order to retrieve data for display in various jsps. The problem is that after the ejb method returns, the transaction is over, the persistence context has ended and the pojos returned are detached. If the jsp that displays the data tries to access any lazily loaded associations an exception occurs. One solution might be to load every association eagerly but this could become very expensive in terms of performance and is definitely not scalable. Another approach might be to write different ejb methods that initialize the associations needed in different views but this will make the API between the web and middle tier very complicated.
What I finally did was borrowed by Hibernate. Hibernate suggests the use of the HibenateUtil class that manages transactions and is called usually in an HttpFilter. In this configuration the transaction boundary is the http request. In my case, I extended the Struts RequestProcessor and overridden the
At the beginning of the processing the UserTransaction is initialized and after the processing it is committed. If an exception happens it is rolled back. By using this approach we make sure that the transaction and the persistence context are active after the ejb method returns and during the action and jsp execution thus enabling us to traverse association from inside the jsps. This approach has a problem though. If a forward is done from a struts action to another the request processor is called again in the same thread and thus the transaction will be committed twice (once per request processor call) resulting in an exception in the second attempt to commit. This can be resolved by use of some flag that marks the outermost call, so that we do the commit only there.
Another approach would be the use of an http filter that begins and commits the transaction thus moving the transaction boundaries at the http request.
All the above approaches do not make any reference to Hibernate classes so the implementation is persistence provider agnostic.
In this configuration with container-managed transactions, the transaction boundary is the ejb method call. Struts action classes make calls to the session ejb methods in order to retrieve data for display in various jsps. The problem is that after the ejb method returns, the transaction is over, the persistence context has ended and the pojos returned are detached. If the jsp that displays the data tries to access any lazily loaded associations an exception occurs. One solution might be to load every association eagerly but this could become very expensive in terms of performance and is definitely not scalable. Another approach might be to write different ejb methods that initialize the associations needed in different views but this will make the API between the web and middle tier very complicated.
What I finally did was borrowed by Hibernate. Hibernate suggests the use of the HibenateUtil class that manages transactions and is called usually in an HttpFilter. In this configuration the transaction boundary is the http request. In my case, I extended the Struts RequestProcessor and overridden the
process method.
public class MyRequestProcessor extends RequestProcessor {
private static Logger logger = Logger.getLogger(MyRequestProcessor.class);
private static final ThreadLocal<UserTransaction> threadTransaction = new ThreadLocal<UserTransaction>();
@Override
public void process(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
UserTransaction utx = null;
try {
utx = threadTransaction.get();
if (utx == null) {
Context ctx = new InitialContext();
UserTransaction utx = (UserTransaction) ctx.lookup("UserTransaction");
threadTransaction.set(utx);
utx.begin();
}
super.process(request, response);
utx.commit();
}
catch (Exception e){
try {
if (utx != null)
utx.rollback();
}
catch (Exception e1) {
logger.error("Cannot rollback transaction", e1);
}
throw new ServletException(e);
}
finally {
threadTransaction.remove();
}
}
}At the beginning of the processing the UserTransaction is initialized and after the processing it is committed. If an exception happens it is rolled back. By using this approach we make sure that the transaction and the persistence context are active after the ejb method returns and during the action and jsp execution thus enabling us to traverse association from inside the jsps. This approach has a problem though. If a forward is done from a struts action to another the request processor is called again in the same thread and thus the transaction will be committed twice (once per request processor call) resulting in an exception in the second attempt to commit. This can be resolved by use of some flag that marks the outermost call, so that we do the commit only there.
Another approach would be the use of an http filter that begins and commits the transaction thus moving the transaction boundaries at the http request.
All the above approaches do not make any reference to Hibernate classes so the implementation is persistence provider agnostic.
Thursday, April 19, 2007
Where is "delete-orphans" ?
A
What happens if one removes an
Ok, let's set the cascade type to all-delete-orphans (like in hibernate) so that orphans get automagically deleted. Not so easy, though. JPA (JSR-220) does not support the "delete-orphan" feature of hibernate and other persistence providers. What can one do? Either use a hibernate specific annotation (other persistence providers like TopLink have similar features) to declare the cascade as delete-orphan or delete the orphan entity programmaticaly (after removing it from the
Personally, I chose the second approach as the first ties the application with the specific persistence provider (hibernate in my case).
Customer has a shopping cart with OrderItems in it:
public class Customer {
...
@OneToMany(cascade=CascadeType.ALL)
private Set<OrderItem> cart;
...
}What happens if one removes an
OrderItem from the cart ? As I noticed today, the item no longer belongs to the customer 's cart but unfortunately still remains in the database as an orphan record.Ok, let's set the cascade type to all-delete-orphans (like in hibernate) so that orphans get automagically deleted. Not so easy, though. JPA (JSR-220) does not support the "delete-orphan" feature of hibernate and other persistence providers. What can one do? Either use a hibernate specific annotation (other persistence providers like TopLink have similar features) to declare the cascade as delete-orphan or delete the orphan entity programmaticaly (after removing it from the
Customer 's collection).Personally, I chose the second approach as the first ties the application with the specific persistence provider (hibernate in my case).
Friday, April 13, 2007
ORA-00907: missing right parenthesis
What follows is not new. It is very well known by jboss+hibernate users and a lot of info can be found at jboss and hibernate forums. Anyway, it took me almost four hours to clean up the mess so I think it is suitable for this blog (for those who have not realized yet, this blog is mostly about my troubles in the java world). So here it goes:
I was trying to configure a many-to-many relation between documents and document bodies. Each document has a collection of bodies, where each body represents a different translation, so each body corresponds to a different language. Each body on the other hand can belong to many documents, thus making the relation many-to-many. On top of this configuration, I wanted to access the bodies of a document by their language id so the map-based solution seemed ok:
The
Unfortunately, due to this bug, hibernate generates illegal sql for Oracle, when trying to initialize the
The "as" is optional but acceptable by many databases. However it is not acceptable by Oracle, as it is explained in the links mentioned above. As I found here the generation of "as" is due to a bug in annotations and the upgrade to hibernate-annotations 3.3.0.GA is suggested. However, the use of this version requires an upgrade of the hibernate-entity manager to version 3.3.x as the compatibility matrix suggests. My troubles didn't end at this point though, because I was using jboss-4.0.5.GA whose EJB3-JPA support is not compatible with the new hibernate-entitymanager. The upgrade to 4.2.0.CR1 seemed inevitable (this has a better EJB3 support but the hibernate-* jars still needed upgrading). Alas, a
I was trying to configure a many-to-many relation between documents and document bodies. Each document has a collection of bodies, where each body represents a different translation, so each body corresponds to a different language. Each body on the other hand can belong to many documents, thus making the relation many-to-many. On top of this configuration, I wanted to access the bodies of a document by their language id so the map-based solution seemed ok:
public class MyDocument {
...
@ManyToMany
@MapKey(name="langId")
private Map<Integer, MyDocumentBody> bodies;
...
}
The
bodies Map is keyed by the integer language id.Unfortunately, due to this bug, hibernate generates illegal sql for Oracle, when trying to initialize the
bodies Map. To be more specific, it uses a table alias in the FROM clause but it puts the "AS" keyword in front e.g.:
select * from TableA as a where blah, blah
The "as" is optional but acceptable by many databases. However it is not acceptable by Oracle, as it is explained in the links mentioned above. As I found here the generation of "as" is due to a bug in annotations and the upgrade to hibernate-annotations 3.3.0.GA is suggested. However, the use of this version requires an upgrade of the hibernate-entity manager to version 3.3.x as the compatibility matrix suggests. My troubles didn't end at this point though, because I was using jboss-4.0.5.GA whose EJB3-JPA support is not compatible with the new hibernate-entitymanager. The upgrade to 4.2.0.CR1 seemed inevitable (this has a better EJB3 support but the hibernate-* jars still needed upgrading). Alas, a
java.lang.NoClassDefFoundError: org/hibernate/annotations/common/reflection/ReflectionManager was waiting for me during deployment. Another google search and this finally solved my problem. hibernate-annotations-common.jar, which is not included in jboss by default, was needed in the lib folder. Four hours and a lot of googling later, I had my map-based many-to-many relation.
Thursday, April 12, 2007
Deploying an EJB twice ... :-)
OK. I know that what follows is a terrible mistake. Actually I knew it from the very beginning but I was curious to see what would happen. Here is how it goes: Two web applications were running on jboss for some years on two separate machines in the client 's data center. For ease of management, some time ago, the client requested that the two applications should be deployed on one machine with a single instance of jboss. No problem, I thought at first. After installing jboss 4.0.5 on the new machine and testing the two apps separately, it was about time to put them together. In the past we had some problems with such deployments if the two apps were using common libraries. Jboss documentation suggests that if you have two .ear files that include the same jars, a good practice is to remove the duplicate jars from the ear files and put them in the jboss 's
in the ear-deployer.xml file located in the
The problem in our case was that the two web apps were using a unique id generator implemented as a session EJB (let 's call it UniqueIDEJB). This EJB had been developed internally years ago, it was packaged in a jar along with all the necessary deployment descriptors and nobody wanted to mess with it. The first ear that contained the UniqueIDEJB was deployed without problems but when the second app was deployed an error occurred indicating that the UniqueIDEJB was already registered in the jndi under the same name.
No problem, one might think. Just deploy the second instance under a different jndi name. After all, that is what deployment descriptors are for. Remember though that nobody wanted to mess with the legacy EJB, so we chose to remove to jar containing the EJB from the two ear files and deploy it independently.
At first, all went well and the two apps along with the UniqueIDEJB were deployed successfully. However there still was a jar file containing the client stubs of the EJB that was included in both apps. This should not be a problem due to the class loader isolation that we used, but things turned out differently. It seems that when the EJB is deployed, jboss creates some proxies that implement the remote and home interfaces, but when the web app looks the EJB up in jndi and tries to cast the result to the home interface, this home interface is loaded by a different class loader (the one of the web app), therefore a ClassCastException occurres.
Conclusion: Class loader isolation does not help when an EJB is included in several web apps. What one should do is deploy the EJB outside of any ear file and put the client stubs jar in jboss 's
lib folder. Another approach is to set
<attribute name="Isolated">true</attribute>
in the ear-deployer.xml file located in the
deploy folder. This means that each ear has its own class loader isolated from other deployments and therefore each ear can have the same jars with the other without conflicts such as ClassCastException, LinkageError, etc.The problem in our case was that the two web apps were using a unique id generator implemented as a session EJB (let 's call it UniqueIDEJB). This EJB had been developed internally years ago, it was packaged in a jar along with all the necessary deployment descriptors and nobody wanted to mess with it. The first ear that contained the UniqueIDEJB was deployed without problems but when the second app was deployed an error occurred indicating that the UniqueIDEJB was already registered in the jndi under the same name.
No problem, one might think. Just deploy the second instance under a different jndi name. After all, that is what deployment descriptors are for. Remember though that nobody wanted to mess with the legacy EJB, so we chose to remove to jar containing the EJB from the two ear files and deploy it independently.
At first, all went well and the two apps along with the UniqueIDEJB were deployed successfully. However there still was a jar file containing the client stubs of the EJB that was included in both apps. This should not be a problem due to the class loader isolation that we used, but things turned out differently. It seems that when the EJB is deployed, jboss creates some proxies that implement the remote and home interfaces, but when the web app looks the EJB up in jndi and tries to cast the result to the home interface, this home interface is loaded by a different class loader (the one of the web app), therefore a ClassCastException occurres.
Conclusion: Class loader isolation does not help when an EJB is included in several web apps. What one should do is deploy the EJB outside of any ear file and put the client stubs jar in jboss 's
lib folder.
Subscribe to:
Posts (Atom)