jpa

Dangers of a Domain Model as the Messaging Model

When designing a services layer, we can relate this to an n-tier architecture where the presentation layer exists on a separate server (possibly developed under a different technology). So the services layer will essentially be like the Session Facade down to the integration layer for interactions between databases, file systems, etc. In this design, there is usually a decision as to whether or not the domain models will be exposed out of the business layer, or whether those domain models will be mediated into a different object representation like a DTO (Data Transfer Object). In this discussion, Domain Models represent our persistence representations while the Messaging Model represents our models exposed via a Service Contract.

In the design of the models themselves, the drive is towards creating a Canonical Model as described in XML Standards for Service Modeling. In this specific implementation, the decision was to utilize the Domain Model as the Canonical Model and expose those models via the Service Contract. As different parts of the application architecture evolved, this began to expose itself as being the cause of some issues.

First off, the technology being used in this case is CXF/JAX-WS/Spring/Hibernate/JPA/AOP. The CXF/JAX-WS frameworks/APIs are used for exposing SEIs as web services for invocation. JPA/Hibernate are being used to provide the persistence framework through JPA ORM files and Hibernate as the Provider. Spring is being used to wire together the CXF/JAX-WS endpoints with the business logic and persistence layer, as well as using AOP with JTA to provide transactionality.

One of the first issues to be hit related to the fact that models representing persistence may be over complex for the needs of a UI Framework (which would potentially be more successful with a flattened model). The persistence model however has complex relationships like bidirectional relationships that allow us access to Parent/Child interactions without having to loop through an object model and keep track of them ourselves. The issue this brings to light though is that a bidirectional relationship will many times consist of a Parent with a Collection of Children, where each instance of the Child in the Collection has a reference back to the Parent, which internally has a Collection of Children and on and on and on. So when it comes time for JAXB to marshal the objects into XML to produce the SOAP Response being sent out of the CXF/JAX-WS framework, the process consumes all memory and begins to run out of Memory and the server crashes. This occurs because the recursive nature of a bidirectional relationship and as JAXB walks the object model to persist it, it will start into a recursive loop of serialization as it walks that bidirectional relationship and the callbacks from the Child to the Parent and so on. This issue is discussed in some detail in the following two posts:

JPA Entities to XML – Bidirectional Relationships
JAXB Mapping cyclic references to XML

The Child object will most likely need to have an @XmlTransient annotation on the relationship it has back to the Parent. Therefore when JAXB is marshalling the object model into XML, it will convert the Parent and then Collection of Children, but not the Child’s relationship back to the Parent. The client of the calling service needs to be aware then that the Child does have a Parent (the containing Parent) even though over the wire (with relation to the SOAP message) it appears that the Child does not have a reference back to a Parent. There maybe a need to think through the same sort of concept for the equals/hashCode/compareTo/toString, as to which fields are being used and how much of the object graph is being walked in order to utilize that field.

Another issue is related to what happens within an application with regards to how Hibernate handles relationships. Hibernate helps the initial load and overall performance of an Entity by providing lazy loading features. Hibernate Without a ton of background experience, it was easy to incorrectly configure Hibernate ORM files by trying to make all the Collections eagerly fetched. But when the WAR is deployed and Spring begins to bootstrap the loading of the persistence.xml and orm.xml files, we receive an error related to (Caused by: org.hibernate.HibernateException: cannot simultaneously fetch multiple bags).

Hibernate and Multiple Bags
Hibernate Exception – Simultaneously Fetch Multiple Bags

So we have to correctly label Collections as LAZY, by default they are supposed to be. This seems to fix our issue with the Multiple Bag Exception. The problem is that now our Collections that are not EAGER hold a reference to Hibernate’s PersistentBag (used as a proxy for the lazy loading of the relationship) and the One-to-one Objects that are not EAGER hold a Hibernate Proxy (used as a proxy for the lazy loading of the relationship). This becomes an issue in web applications related to whether or not the session is open so that when those proxies get touched, they can retrieve the subsequent relationship. Otherwise we will receive the Hibernate LazyInitializationException. There are quite a few articles on how to resolve this issue:

Hibernate – Lazy Load exception – no session or session was closed
How to solve lazy initialization exception using JPA and Hibernate as provider (with newer ways to solve it).

Even though we are not running in a complete MVC web application, we have the same situation occurring because the models we are exposing through the web service are Domain Models tied to a Hibernate Sessions (because of the EntityManager and ORM files). So like a typical SessionFacade, the service that is exposed as a web service has AOP Pointcuts to add JTA Transactionality. What occurs is that when that WAR receives a web service request, JAX-WS/JAXB/CXF do their work and then hand off the Object to the appropriate SIB (Service Implementation Bean) which has an AOP Pointcut tied to it, so a JTA transaction has been started. All data access that is done within that transaction ties the Hibernate Session (EntityManager) to that transaction, because of:

1
<entry key="hibernate.current_session_context_class" value="jta"/>

Therefore when all the logic is complete and the service method returns the Object to the calling framework (essentially the business logic is done and now the JAX-WS/JAXB/CXF will take over), the AOP Pointcut is complete and closes the Transaction (and therefore the Hibernate Session). So when the JAXB part of the process marshals the Object into XML and walks the object graph, it will run into the Hibernate Proxies and PersistentBag instances, with no Hibernate Session from which to retrieve the relationship. Therefore the LazyInitializationException occurs.

In some of these examples they talk about the OpenEntityManagerInViewFilter or called the Open Session in View pattern. This is one of the typical ways to solve this issue from within a web application.

This can be done by making the following modifications (as an example)

1
<entry key="hibernate.current_session_context_class" value="jta"/>

is changed to

1
<entry key="hibernate.current_session_context_class" value="org.springframework.orm.hibernate3.SpringSessionContext" />

And add the following to the web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<filter>
        <filter-name>OpenEntityManagerInViewFilter</filter-name>
        <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
        <init-param>
            <param-name>entityManagerFactoryBeanName</param-name>
            <param-value>sampleEntityManagerFactory</param-value>
        </init-param>
        <init-param>
            <param-name>singleSession</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>flushMode</param-name>
            <param-value>AUTO</param-value>
        </init-param>
    </filter>

This actually can work for us. Another way to do it is to create a CXF Interceptor to start the transaction at a certain point in the Phases of unmarshalling data when the request is received, or closing the transaction when the marshalling process has completed. Since we hadn’t tried the Open Session in View pattern, the resolution that occurred was creating a touch method that would utilize a ReflectionUtils.doWithFields functionality to walk the whole object graph and touch any Hibernate Proxies that were not EAGERLY loaded. This would essentially force selects to occur immediately when the object was retrieved from the database (by adding a step in the framework to perform a touch of an object before it was returned to the calling method).

Another approach was to use the concept in service design where we could use a single fine grained method to produce multiple types of responses based on the data the user wanted. So for instance, if we had a method that was getPerson and retrieved a Person, their family, their addresses, etc, we could change the amount of data returned from that one getPerson method by supply a list of Filters/Scopes for limiting data. This would allow a user to call getPerson with a List of Filter fields like address and family, so that when the getPerson retrieved a Person object, it did not also retrieve the Person’s Address and Family (would be additional select statements to other tables). Therefore, the we could take the fact that Hibernate will not allow more than one Collection to be EAGER as an advantage because time was not wasted pulling in additional resources the user might not want. The Person object would be retrieved and have its Hibernate Proxies (for doing lazy loading of the Collections) and if the List of Filters was populated, the code could determine if one of the Filtered fields was a Hibernate Proxy, then that reference could be set to null (dereferencing that Hibernate Proxy). Therefore when the object was marshaled via JAXB, it would not throw a LazyInitializationException on that field because the reference was null and we did not need that data returned to the user.

This approach actually seemed to produce less selects than by using the Open Session in View pattern. This simplified the architecture by leaving the AOP and JTA Pointcuts as they were originally developed.

Share and Enjoy

Hibernate and JPA 2.0 with WebLogic Server

I talked a little about utilizing Hibernate/JPA 2 with WebLogic Server in my blog about (Multiple persistence.xml files and JPA). First off, the idea was to utilize JPA 2 and use Hibernate as the provider so that all the persistence logic could be written against JPA. Long-term, this was a mistake, since Hibernate has such advanced features such as their Filters and Interceptors that Hibernate’s API began to slowly creep into the core persistence classes we developed. So even though the initial concept seemed ideal to have this separation where the persistence provider would be hidden from application logic, that quickly changed and it became apparent that much time and effort would have been saved in just using Hibernate as opposed to coupling it with JPA 2.

That being said, in order to get Hibernate to work in WebLogic Server, one of the simplest things to do is create a preclasspath directory that we can place in front of WebLogic libraries in the WebLogic Server startup script. Then additional libraries can be added to this folder that are necessary to implement features where library collisions occur with WebLogic Server weblogic.jar and other default jars (such as saaj-impl.jar). Since the weblogic.jar contains many 3rd party libraries, and older versions than we like to use, we have to place the antlr jar in this preclasspath directory (along with other ones such as commons-lang.jar and saaj-impl.jar). Once we start our WebLogic Server, we start getting errors related to this Oracle Forum post (Thread: Hibernate 3.6 Final (JPA 2.0) + WL 10.3.x :Unable to deploy sample appn) and Can not deploy 3.5 to Weblogic 10.3 server. The error is basically:

1
java.lang.Throwable: java.lang.NoSuchMethodError: javax.persistence.spi.PersistenceUnitInfo.getValidationMode()Ljavax/persistence/ValidationMode;

The way to simply resolve this is by putting the “hibernate-jpa-2.0-api-1.0.1.Final.jar” into the preclasspath folder in WebLogic Server and restart the server. This appeared to fix the issue, until we actually started doing testing later on in other environments related to the Validation Framework. The following error began to appear (ignore the jar names, I use Apache Shade to combine the multiple hibernate jars into a single jar):

1
2
3
4
5
6
7
8
9
10
11
java.lang.AbstractMethodError: null        
at javax.persistence.Persistence$1.isLoaded(Persistence.java:93) ~[hibernate-jpa-2.0-api-1.0.1.Final.jar:1.0.1.Final]        
at org.hibernate.validator.engine.resolver.JPATraversableResolver.isReachable(JPATraversableResolver.java:61) ~[hibernate-full.jar:3.6.9]        
at org.hibernate.validator.engine.resolver.DefaultTraversableResolver.isReachable(DefaultTraversableResolver.java:131) ~[hibernate-full.jar:3.6.9]        
at org.hibernate.validator.engine.resolver.SingleThreadCachedTraversableResolver.isReachable(SingleThreadCachedTraversableResolver.java:46) ~[hibernate-full.jar:3.6.9]
at org.hibernate.validator.engine.ValidatorImpl.isValidationRequired(ValidatorImpl.java:1242) ~[hibernate-full.jar:3.6.9]        
at org.hibernate.validator.engine.ValidatorImpl.validateConstraint(ValidatorImpl.java:448) ~[hibernate-full.jar:3.6.9]        
at org.hibernate.validator.engine.ValidatorImpl.validateConstraintsForDefaultGroup(ValidatorImpl.java:397) ~[hibernate-full.jar:3.6.9]        
at org.hibernate.validator.engine.ValidatorImpl.validateConstraintsForCurrentGroup(ValidatorImpl.java:361) ~[hibernate-full.jar:3.6.9]        
at org.hibernate.validator.engine.ValidatorImpl.validateInContext(ValidatorImpl.java:313) ~[hibernate-full.jar:3.6.9]        
at org.hibernate.validator.engine.ValidatorImpl.validate(ValidatorImpl.java:139) ~[hibernate-full.jar:3.6.9]

The next step was to upgrade the Hibernate Validator framework jars and also attempt to upgrade the Hibernate jars, but this did not seem to alleviate our issues. Plus, the phase of the project did not allow the upgrade from a Hibernate 3.6.0 to the newer Hibernate 4.* without some serious regression. So with some additional research, the issue seemed to really resolve around what implementation classes were being forced down the WebLogic Server classpath, as opposed to the libraries that were being supplied within the WAR. The following two links were discussions that related to this issue:

@Valid annotation gives java.lang.AbstractMethodError
AbstractMethodError in WebLogic 10.3.4
Validator fails when a non-Hibernate persistence layer is in the classpath

So through these discussions as well as a few other threads that I cannot seem to find now, the resolution was to get rid of the preclasspath library of hibernate-jpa-2.0-api-1.0.1.Final.jar and replace that jar with another spec reference from Geronimo called geronimo-jpa_2.0_spec-1.1.jar. With this replacement, the JPA 2.0 functionality continued to work because of the provided interfaces within the Geronimo API, and the AbstractMethodError disappeared when utilizing the Validator Framework functionality.

Share and Enjoy

JPA (Hibernate) Field Name Issues

I am using Hibernate 3.6, JPA 2.0, and Spring 3.0.6. Hibernate configuration files are being used instead of annotations on the model classes because we like the separation of the configuration files so that the models don’t carry Hibernate library dependencies. These classes utilize standard POJO/Bean definitions with field names and getters/setters for each field, utilizing Hibernate’s Field Access. Here is a sample of the class and orm file:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/**
 * This is a generated class. Do not modify.
 */

@XmlRootElement(namespace = "http://foo.com/model", name = "ElectronicAddress")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(namespace = "http://foo.com/model", name = "ElectronicAddress", propOrder = { "eAddress", "id" })
public class ElectronicAddress extends ContactPoint {

    /**
     * The serialize value.
     */

    private static final long serialVersionUID = -1L;
    /**
     * The eAddress field.
     */

    @XmlElement(name = "EAddress", namespace = "##default")
    private String eAddress;
    /**
     * The id field.
     */

    @XmlElement(name = "Id", namespace = "##default")
    private Long id; //NOPMD

    /**
     * Gets the value of the eAddress property.
     * This field is Required.
     *
     * @return eAddress object is {@link String }
     */

    public String getEAddress() {
        return eAddress;
    }

    /**
     * Sets the value of the eAddress property.
     * This field is Required
     *
     * @param eAddress object is {@link String }
     */

    public void setEAddress(String eAddress) {
        this.eAddress = eAddress;
    }

    /**
     * Gets the value of the id property.
     * This field is Optional.
     *
     * @return id object is {@link Long }
     */

    public Long getId() {
        return id;
    }

    /**
     * Sets the value of the id property.
     * This field is Optional
     * genericInheritGetterSetter
     * @param id object is {@link Long }
     */

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

}

The following is the orm file:

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
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm
  http://java.sun.com/xml/ns/persistence/orm_2_0.xsd"

    version="2.0">
    <description>com.foo.model.ElectronicAddress Entity Mapping</description>
    <package>com.foo.model</package>
    <schema>COMMON</schema>
    <access>FIELD</access>
    <entity class="com.foo.model.ElectronicAddress"
        access="FIELD" metadata-complete="true">
        <table name="ELECTRONIC_ADDRESSES" />
        <attributes>
            <id name="id">
                <column name="ELECTRONIC_ADDRESS_ID" />
                <generated-value strategy="SEQUENCE" generator="ADDR_SEQ" />
                <sequence-generator name="ADDR_SEQ"
                    sequence-name="COMMON.ADDR_SEQ" allocation-size="1" />
            </id>
            <basic name="eAddress">
                <column name="ELECTRONIC_ADDRESS" />
            </basic>
        </attributes>
    </entity>
</entity-mappings>

When the application is deployed to the WebLogic Server, there are quite a few WARN statements that appear related to some of the properties that are defined within the orm files. The interesting thing is that the WARN messages only appear with relation to field names that have a single lowercase character, and these WARN messages don’t appear to change/effect any of the running application.

1
2
3
4
5
2011-02-22 15:38:10,785 [[STANDBY] ExecuteThread: '3' for queue: 'weblogic.kernel.Default (self-tuning)'] WARN org.hibernate.cfg.annotations.reflection.JPAOverridenAnnotationReader - Property com.foo.model.contactpoint.ElectronicAddress.eAddress not found in class but described in  (possible typo error)
2011-02-22 15:38:10,801 [[STANDBY] ExecuteThread: '3' for queue: 'weblogic.kernel.Default (self-tuning)'] WARN org.hibernate.cfg.annotations.reflection.JPAOverridenAnnotationReader - Property com.foo.model.person.PersonContact.eAddressCpId not found in class but described in  (possible typo error)
2011-02-22 15:38:10,801 [[STANDBY] ExecuteThread: '3' for queue: 'weblogic.kernel.Default (self-tuning)'] WARN org.hibernate.cfg.annotations.reflection.JPAOverridenAnnotationReader - Property com.foo.model.person.PersonContact.eAddress not found in class but described in  (possible typo error)
2011-02-22 15:38:10,817 [[STANDBY] ExecuteThread: '3' for queue: 'weblogic.kernel.Default (self-tuning)'] WARN org.hibernate.cfg.annotations.reflection.JPAOverridenAnnotationReader - Property com.foo.model.person.PartyContact.eAddressCpId not found in class but described in  (possible typo error)
2011-02-22 15:38:10,817 [[STANDBY] ExecuteThread: '3' for queue: 'weblogic.kernel.Default (self-tuning)'] WARN org.hibernate.cfg.annotations.reflection.JPAOverridenAnnotationReader - Property com.foo.model.person.PartyContact.eAddress not found in class but described in  (possible typo error)

After posting this to Stackoverflow.com under (In Hibernate/JPA can field names no begin with a single letter camel case?), I was pointed to the JPAOverridenAnnotationReader class.

When we take a look at the class JPAOverridenAnnotationReader, we find a method called checkForOrphanProperties

1
2
3
4
5
6
7
8
9
for (Method method : clazz.getMethods()) {
    String name = method.getName();
    if ( name.startsWith( "get" ) ) {
        properties.add( Introspector.decapitalize( name.substring( "get".length() ) ) );
    }
    else if ( name.startsWith( "is" ) ) {
        properties.add( Introspector.decapitalize( name.substring( "is".length() ) ) );
    }
}

The problem is that the method looks for all public fields and then starts adding field names based on “get” and “is” methods it finds. The Introspector.decapitalize method utilizes specific rules to determine what to decapitalize.

From the Introspector class:

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
/**
 * Utility method to take a string and convert it to normal Java variable
 * name capitalization.  This normally means converting the first
 * character from upper case to lower case, but in the (unusual) special
 * case when there is more than one character and both the first and
 * second characters are upper case, we leave it alone.
 * <p>
 * Thus "FooBah" becomes "fooBah" and "X" becomes "x", but "URL" stays
 * as "URL".
 *
 * @param  name The string to be decapitalized.
 * @return  The decapitalized version of the string.
 */

public static String decapitalize(String name) {
if (name == null || name.length() == 0) {
    return name;
}
if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
        Character.isUpperCase(name.charAt(0))){
    return name;
}
char chars[] = name.toCharArray();
chars[0] = Character.toLowerCase(chars[0]);
return new String(chars);
}

The result is that the decapitalize method doesn’t work the way we expect based on how our field name/setter/getter methods are cased.

1
private String eAddress;

And our getter is:

1
2
3
public String getEAddress() {
        return eAddress;
}

So based on the Introspector.decapitalize functionality, the result of the decapitalize would be “EAddress”, not “eAddress”. Because it sees two capital letters in the “EAddress” when the code substrings off the “get”…it won’t decapitalize those. Therefore it complains that the eAddress field in the orm.xml doesn’t exist. The persistence of the field works totally fine, these warnings just show up when the war starts and the files are bootstrapped.

Share and Enjoy