Tuesday, July 2, 2013

Deproxy a lazily loaded JPA reference (using standard Java and JPA API)

When tried to tune our near-production application, we came to problem when a single entity reference (not a collection) is loaded lazily. We used inheritance with this entity and hibernate JPA provider (as probably any other provider) inserts a proxy object into referencing entity instead of reference to real object loaded from database (as it is not yet loaded).

We came to a problem because we were casting super class to subclasses using instanceof. The problem is that proxy class is already a subclass and cannot be cast to a sibling class. It is a proxy only to super class instance, but it's not possible to access methods of superclasses directly. The proxy never gets converted to real subclass. The problem is specified herehere and here. All described solutions depend on hibernate non-standard API to retrieve deproxied instance.

However, after lots of thinking...

... I found a solution to deproxy a class using standard Java and JPA API. Tested with hibernate, but does not require hibernate as a dependency and should work with all JPA providers.

Only one requirement - its necessary to modify parent class (Address) and add a simple helper method.

General idea: add helper method to parent class which returns itself. when method called on proxy, it will forward the call to real instance and return this real instance.

Implementation is a little bit more complex, as hibernate recognizes that proxied class returns itself and still returns proxy instead of real instance. Workaround is to wrap returned instance into a simple wrapper class, which has different class type than the real instance.

In code:

class Address {
   public AddressWrapper getWrappedSelf() {
       return new EntityWrapper(this);
   }
...
}

class AddressWrapped {
    private Address wrappedAddress;
...
}

To cast Address proxy to real subclass, use following:

Address address = dao.getSomeAddress(...);
Address deproxiedAddress = address.getWrappedSelf().getWrappedAddress();
if (deproxiedAddress instanceof WorkAddress) {
WorkAddress workAddress = (WorkAddress)deproxiedAddress;
}

Tuesday, March 12, 2013

Properties and config in persistence.xml

List of elements in persistence.xml

<!-- turn off 2nd level caching (optional), values: NONE, ALL, DISABLE_SELECTIVE, ENABLE_SELECTIVE,  -->
        <shared-cache-mode>NONE</shared-cache-mode>
<!-- desired provider (optional), if not present, default provider will be used -->
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<!-- optional declaration of used datasource, if not specified, connection properties must be specified, otherwise will use specified datasrouce in container -->
<jta-data-source>jdbc/cbn</jta-data-source>

List of standard properties

Driver: <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver"/>
URL: <property name="javax.persistence.jdbc.url" 
       value="jdbc:derby://localhost:1527/chapter02DB;create=true"/>
User: <property name="javax.persistence.jdbc.user" value="APP"/>
Password: <property name="javax.persistence.jdbc.password" value="APP"/>

Hibernate properties

Debug SQL:  <property name="hibernate.show_sql" value="true"/>
Schema generation (optional):
            <!-- create the database schema automatically, values: create-drop, update -->
            <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
Dialect:   <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />

EclipseLink properties

Schema generation (optional):
      <!-- create the database schema automatically, values: create-tables, drop-and-create-tables -->
      <property name="eclipselink.ddl-generation" value="create-tables"/>

Resources

  • http://antoniogoncalves.org/2009/07/05/jpa-2-0-standard-properties-in-persistence-xml/
  • Netbeans persistence.xml editor