Monday, September 18, 2017

Spring Application Listener

How to use the Spring Application Listener

To set the application to use Spring Application listener, you can do the following.
1. In the application context file for Spring, declare a bean as follows

  <bean id="applicationEventMulticaster"
  class="org.springframework.context.event.SimpleApplicationEventMulticaster"/>
Actually, this may not needed at all. The following method is from Spring. By default, it will create a SimpleApplicationEventMulticaster if none is given.
   package org.springframework.context.support;

   public abstract class AbstractApplicationContext extends DefaultResourceLoader
  implements ConfigurableApplicationContext, DisposableBean {
   
   /**
  * Initialize the ApplicationEventMulticaster.
  * Uses SimpleApplicationEventMulticaster if none defined in the context.
  * @see org.springframework.context.event.SimpleApplicationEventMulticaster
  */
 protected void initApplicationEventMulticaster() {
  ConfigurableListableBeanFactory beanFactory = getBeanFactory();
  if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
   this.applicationEventMulticaster =
     beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
   if (logger.isDebugEnabled()) {
    logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
   }
  }
  else {
   this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
   beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
   if (logger.isDebugEnabled()) {
    logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
      APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
      "': using default [" + this.applicationEventMulticaster + "]");
   }
  }
 }

...
}

2. Create Application listeners
import org.springframework.context.ApplicationListener;
@Component
public class MyEventListener implements ApplicationListener {
  ...
}

import org.springframework.context.ApplicationEvent;
public class MyEvent extends ApplicationEvent {
 ...
}


3. Just call the multicastEvent method of the bean applicationEventMulticaster when needed: applicationEventMulticaster.multicastEvent(event);

The method will invoke the application listeners to act on the event.

  public void multicastEvent(final ApplicationEvent event) {
  for (final ApplicationListener listener : getApplicationListeners(event)) {
   Executor executor = getTaskExecutor();
   if (executor != null) {
    executor.execute(new Runnable() {
     @SuppressWarnings("unchecked")
     public void run() {
      listener.onApplicationEvent(event);
     }
    });
   }
   else {
    listener.onApplicationEvent(event);
   }
  }
 }

How does the Application know what application listeners are listening?

At the application startup, the beans that implement the ApplicationListener interface will be automatically detected and registered.

ContextLoaderListener(ContextLoader).initWebApplicationContext(ServletContext)
->
XmlWebApplicationContext(AbstractApplicationContext).refresh();
->
DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory). applyBeanPostProcessorsAfterIniitalization
->
AbstractApplicationContext$ApplicationListenerDetector.postProcessAfterInitialization

public Object postProcessAfterInitialization(Object bean, String beanName) {
   if (bean instanceof ApplicationListener) {
    // potentially not detected as a listener by getBeanNamesForType retrieval
    Boolean flag = this.singletonNames.get(beanName);
    if (Boolean.TRUE.equals(flag)) {
     // singleton bean (top-level or inner): register on the fly
     addApplicationListener((ApplicationListener) bean);
    }
    else if (flag == null) {
     if (logger.isWarnEnabled() && !containsBean(beanName)) {
      // inner bean with other scope - can't reliably process events
      logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
        "but is not reachable for event multicasting by its containing ApplicationContext " +
        "because it does not have singleton scope. Only top-level listener beans are allowed " +
        "to be of non-singleton scope.");
     }
     this.singletonNames.put(beanName, Boolean.FALSE);
    }
   }
   return bean;
  }

public void addApplicationListener(ApplicationListener listener) {
  if (this.applicationEventMulticaster != null) {
   this.applicationEventMulticaster.addApplicationListener(listener);
  }
  else {
   this.applicationListeners.add(listener);
  }
 }

Sunday, February 19, 2017

How to do unit test on JPA

It will be very inconvenient to test JPA DAO classes if you need to build and deploy the application to an application server. You can actually do unit tests on JPA without using any application server. The following is one example.

1. The entity class.


@Entity
@Table(name = "T_SAMPLE")
public class SampleData implements Serializable {

 private SampleDataId id;
 private String xyz;
 
 @EmbeddedId
 public SampleDataId getId() {
  return this.id;
 }

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


 @Column(name = "XYZ")
 public String getXyz() {
  return this.xyz;
 }

 public void setXyz(final String xyz) {
  this.xyz = xyz;
 }

}
2. The DAO class to be tested.
packge com.example.dao;

@Repository
public class SampleDataDAO {
 protected static final Logger LOG = Logger.getLogger(SampleDataDAO.class);

  @PersistenceContext
  private EntityManager entityManager;

 /**
  * Returns List of SampleData type.
  */
 public List<SampleData> getSomeData() {
   List<SampleData> results = new ArrayList<SampleData>();
   EntityManager entityManager = getEntityManager();
   final CriteriaBuilder builder = entityManager.getCriteriaBuilder();
   final CriteriaQuery<SampleData> query = builder
     .createQuery(SampleData.class);
   final Root<SampleData> root = query.from(SampleData.class);
   List<Predicate> predicates = new ArrayList<Predicate>();
   query.select(root);
    ......
   query.where(predicates.toArray(new Predicate[] {}));

   results = entityManager.createQuery(query).getResultList();
   return results;
 }

public void saveSomeData(SampleData sampleData) {
   EntityManager entityManager = getEntityManager();
   entityManager.persist(sampleData); 
 }
}
3. The test class:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/testApplicationContext.xml" })
public class SampleDataDAOTest {

 @Autowired
 private SampleDataDAO sampleDataDAO;

 @Test
 public void testRead() {
  sampleDataDAO.getSomeData(...);
 }

 @Test
 @Transactional
 public SampleData testSave() {
  SampleData sampleData = new SampleData();
  sampleData.setXyz("bla");
  sampleDataDAO.saveSomeData(sampleData);
  SampleData savedData = sampleDataDAO.getSampleDataById(sampleData.getId());
  Assert.assertNotNull(savedData);
  return savedData;
 }
}

Notes:

  1. The method testSave() has the annotation @Transactional. Without this annotation, the test won't work. The savedData will be null. The @Transactional annotation has to appear somewhere. If the method saveSomeData of sampleDataDAO is annotated with @Transactional, then it is also fine.
  2. The good thing about using @Transactional on the method of a Junit test class is that Spring will automatically rollback the transaction after the test is done. So the above test method testSave() won't actually create a record in the database after the test. Below is from Spring documentation.

    In the TestContext framework, transactions are managed by the TransactionalTestExecutionListener. Note that TransactionalTestExecutionListener is configured by default, even if you do not explicitly declare @TestExecutionListeners on your test class. To enable support for transactions, however, you must provide a PlatformTransactionManager bean in the application context loaded by @ContextConfiguration semantics. In addition, you must declare @Transactional either at the class or method level for your tests.

4. The configuration file app/src/test/resources/testApplicationContext.xml.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
 
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        p:driverClassName="oracle.jdbc.driver.OracleDriver" p:url="jdbc:oracle:thin:@myurl"
        p:username="myUsername" p:password="myPassword" p:initialSize="5" p:maxActive="10">
    </bean>
 
    <bean
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
        id="entityManagerFactory">
        <property name="dataSource" ref="dataSource" />
    </bean>

 
    <context:component-scan base-package="com.example.dao">
    </context:component-scan>
 
    <bean class="org.springframework.orm.jpa.JpaTransactionManager"
        id="transactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
 
   
    <context:spring-configured />
    <context:annotation-config />
    <tx:annotation-driven transaction-manager="transactionManager" />
</beans>
5. The file app/src/main/java/META-INF/persistence.xml:
   <persistence xmlns="http://java.sun.com/xml/ns/persistence"
 version="1.0">

 <persistence-unit name="MY-UNIT" transaction-type="RESOURCE_LOCAL">
  <provider>org.hibernate.ejb.HibernatePersistence</provider>
  <non-jta-data-source>dataSource</non-jta-data-source>
  <properties>
   <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
   <!-- property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/ -->
   <property name="hibernate.show_sql" value="true" />
   <property name="hibernate.hbm2ddl.auto" value="none" />
   <prop key="hibernate.connection.autocommit">false</prop>
   <prop key="hibernate.connection.release_mode">after_transaction</prop>
  </properties>
 </persistence-unit>

</persistence> 

Note that the output log will show that this persistence unit is used.

Question. The test needs to use the Entity class SampleData.java. How is this class discovered in the test context?

Answer: The document http://docs.jboss.org/hibernate/stable/entitymanager/reference/en/html/configuration.html#setup-configuration-bootstrapping has good explaintion. It seems that by default, JPA will discover all the classes annotated with @Entity in the archive in the bootstrap process.

2.2.1. Packaging

The configuration for entity managers both inside an application server and in a standalone application reside in a persistence archive. 
A persistence archive is a JAR file which must define a persistence.xml file that resides in the META-INF folder. 
All properly annotated classes included in the archive (ie. having an @Entity annotation), all annotated packages and all 
Hibernate hbm.xml files included in the archive will be added to the persistence unit configuration, so by default, 
your persistence.xml will be quite minimalist:


<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
             version="2.0">
   <persistence-unit name="sample">
      <jta-data-source>java:/DefaultDS</jta-data-source>
      <properties>
         <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
         <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
      </properties>
   </persistence-unit>
</persistence>

The actual command line of the test run is something like below:

C:\tools\jre-7u79-windows-x64\jre1.7.0_79\bin\javaw.exe -ea 
-classpath C:\Users\me\workspace\app\target\test-classes;
C:\Users\me\workspace\app\target\classes;
......
 -testLoaderClass org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader 
-loaderpluginname org.eclipse.jdt.junit4.runtime 
-classNames com.sample.dao.SampleDataDAOTest
Debugging of the program shows the following details. 1. The file testApplicationContext.xml has the bean entityManagerFactory of the class org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean. 2. When this bean is created, its method afterPropertiesSet() calls HibernatePersistence.createContainerEntityManagerFactory(), which calls Ejb3Configuration.buildEntityManagerFactory(), and so on. Eventually it will create a map that contains all the classes with the annotation @Entity. The last few classes used in this chain of call are JPA or Hibernate classes which are not related to Spring. So these classes must have the builtin ability to discover the @Entity classes by following the JPA standards.

Note that if you just use Hibernate without using the generic JPA,then you use the configuration file hibernate.cfg.xml. And you can list the entity classes or packages in that file as the following example shows.

  <hibernate-configuration>
     <session-factory>
       <property name="hibernate.connection.driver_class>"com.mysql.mysql.Driver</property>
       ......
       <mapping class="com.sample.SampleData"/>
     </session-factory>
   </hibernate-configuration>

Thursday, February 9, 2017

CDI, Tomcat and JPA

Contexts and Dependency Injection (CDI) for the Java EE platform is one of several Java EE 6 features that help to knit together the web tier and the transactional tier of the Java EE platform. CDI is a set of services that, used together, make it easy for developers to use enterprise beans along with JavaServer Faces technology in web applications. Designed for use with stateful objects, CDI also has many broader uses, allowing developers a great deal of flexibility to integrate various kinds of components in a loosely coupled but typesafe way.

Tomcat (Tomcat 7 in this blog) is a web container. It is not a Java EE container. So it does not recognize @PersistenceContex, @EJB, etc.

Say we have the persistence.xml file for JPA(Java Persistence API) in the META-INF folder.

<?xml version="1.0" encoding="UTF-8"?> 
<persistence xmlns="http://java.sun.com/xml/ns/persistence" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" 
version="2.0"> 
   <persistence-unit name="my_unit"> 
     <provider>org.hibernate.ejb.HibernatePersistence</provider> 
     <properties> 
        <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" /> 
        <property name="hibernate.hbm2ddl.auto" value="update" /> 
        <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" /> 
        <property name="hibernate.connection.username" value="username" /> 
        <property name="hibernate.connection.password" value="pwd" /> 
        <property name="hibernate.connection.url" value="jdbc:mysql://localhost/somepath" /> 
     </properties> 
   </persistence-unit> 
</persistence> 

 

In a Java EE server, you can inject EntityManager as below:

public class MyApp {

    @PersistenceContext(unitName = "my-unit")
    private EntityManager entityManager;

    public void doSomething {
        entityManager.persist(...);
    }
}
 

But this won't work in Tomcat. In Tomcat, typically you need to do the following to get the EntityManager.

 EntityManagerFactory emf = Persistence.createEntityManagerFactory("my_unit"); 
 EntityManager em = emf.createEntityManager(); 
 em.getTransaction().begin(); 
   // do some thing here
 em.getTransaction().commit(); 
 

There is a way so that you can still use @PersistenceContext in Tomcat. The trick is to use the Spring class PersistenceAnnotationBeanPostProcessor. Below is the Spring documentation of this class.

This post-processor will inject sub-interfaces of EntityManagerFactory and EntityManager if the annotated fields or methods are declared as such. The actual type will be verified early, with the exception of a shared ("transactional") EntityManager reference, where type mismatches might be detected as late as on the first actual invocation.

Note: In the present implementation, PersistenceAnnotationBeanPostProcessor only supports @PersistenceUnit and @PersistenceContext with the "unitName" attribute, or no attribute at all (for the default unit). If those annotations are present with the "name" attribute at the class level, they will simply be ignored, since those only serve as deployment hint (as per the Java EE 5 specification).

This post-processor can either obtain EntityManagerFactory beans defined in the Spring application context (the default), or obtain EntityManagerFactory references from JNDI ("persistence unit references"). In the bean case, the persistence unit name will be matched against the actual deployed unit, with the bean name used as fallback unit name if no deployed name found. Typically, Spring's LocalContainerEntityManagerFactoryBean will be used for setting up such EntityManagerFactory beans. Alternatively, such beans may also be obtained from JNDI, e.g. using the jee:jndi-lookup XML configuration element (with the bean name matching the requested unit name). In both cases, the post-processor definition will look as simple as this:

   <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>

So in your Spring context.xml file, you can put something like the following:

 <bean id="entityManagerFactory"
  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="persistenceXmlLocation" value="classpath*:META-INF/persistence.xml" />
  <property name="persistenceUnitName" value="my_unit" />
  <property name="dataSource" ref="dataSource" />
  <property name="jpaVendorAdapter">
   <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    <property name="showSql" value="true" />
   </bean>
  </property>
  <property name="loadTimeWeaver">
   <bean
    class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
  </property>
   <property name="jpaDialect">
            <bean class="......"/>
        </property>
 </bean>
 <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
  

Wednesday, September 14, 2016

A generic method to get column-value map from Java JDBC ResultSet

The following method creates a column_name to value map from the Java JDBC ResultSet. It makes use of the meta data and Spring JdbcUtils class.

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.util.LinkedCaseInsensitiveMap;

public Map getColumnValueMapFromResultSet(ResultSet resultSet)
   throws SQLException {
  ResultSetMetaData metaData = resultSet.getMetaData();
  int columnCount = metaData.getColumnCount();
  Map columnValueMap = new LinkedCaseInsensitiveMap(columnCount );

  for (int i = 1; i <= columnCount; i++) {
   String columnName = JdbcUtils.lookupColumnName(metaData, i);
   Object value = JdbcUtils.getResultSetValue(resultSet, i);
   columnValueMap.put(columnName, value);
  }
  return columnValueMap;
 }

Monday, September 12, 2016

Java Annotation PostConstruct and Inheritance

It is quite confusing when the Java inheritance is mingled with the PostConstruct annotation. Based on my tests, I found the following. Suppose there are two classes.
  class A {
    @PostConStruct
    private void init(){
 
    }
  }

  class B extends A {

   }


Case 1

For the above case, the execution order is
  1. Constructor of A
  2. Constructor of B
  3. init method of A.
So the annotation @PostConstruct is inherited even when the annotated method is private in the parent class.

Case 2

Now if the class B has its own @PostConstruct method such as the following:
      @PostConstruct
      private void my_init(){
      }
   
Then the init() method of A will not be called. Instead, my_init() is called. So it seems that in the class hierarchy, only one PostConstruct annotated method is called.

Case 3

Now if the class B does not have its own @PostConstruct. But it overrides the @PostConstruct annotated method in its parent class.
  class A {
    @PostConStruct
    public void init(){
       System.out.println("A init()");
    }
  }

  class B extends A {
   @Override
   public void init(){
      System.out.println("B init()");
    }
   }
In this case the @PostConstruct method init() is called. But the init() method used is from class B. So it will print "B init()". Note that if the init() method in class A is private, then "A init()" will be printed out. In this case, the init() method of B is not an override method. Actually you have to remove its @Override annotation. Otherwise it won't compile.

Conclusion

In summary, if there is a method with the annotation @PostConstruct in a class C or its parent classes, then the annotated method will be called after the constructor of C is called. In case that @PostConstruct appears in multiple classes in the class hierarchy, the one closest to the class C will be called. Furthermore, if that annotated method is overridden by its subclasses, then the overriding method will be called. Of course, I think it is bad to declare the @PostConstruct annotated method as public or protected. It should be private so it won't be overridden.

Wednesday, July 27, 2016

A Simple Example to Use Spring BeanWrapper and PropertyAccessorFactory

The Spring classes BeanWrapper and PropertyAccessorFactory can be used to make it easier to set the nested property values of an object. You can also use the BeanWrapper to get the values of the properties.

First suppose there are the following two object classes. One class has a property that is the other class.

public class Animal {
 private String name;
 private Body body;
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public Body getBody() {
  return body;
 }
 public void setBody(Body body) {
  this.body = body;
 }
 @Override
 public String toString() {
  return "Animal [name=" + name + ", body=" + body + "]";
 }
}

public class Body {
 private double weight;
 private double height;
 public double getWeight() {
  return weight;
 }
 public void setWeight(double weight) {
  this.weight = weight;
 }
 public double getHeight() {
  return height;
 }
 public void setHeight(double height) {
  this.height = height;
 }
 @Override
 public String toString() {
  return "Body [weight=" + weight + ", height=" + height + "]";
 }
}

Below is the test class.

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.beans.PropertyValue;

public class PropertyAccessTest {
 public static void main(String[] args) {
  Animal animal = new Animal();
  animal.setBody(new Body());
  System.out.println("animal=" + animal);

  // use the wrapper to set the property values
  BeanWrapper wrapper = PropertyAccessorFactory
    .forBeanPropertyAccess(animal);
  PropertyValue p1 = new PropertyValue("body.weight", 123);
  wrapper.setPropertyValue(p1);
  PropertyValue p2 = new PropertyValue("name", "tiger");
  wrapper.setPropertyValue(p2);
  System.out.println("animal=" + animal);

  // use the wrapper to get the property values
  String[] properties = { "name", "body.weight" };
  for (String p : properties) {
  Object v = wrapper.getPropertyValue(p);
  System.out.println(p + ": " + v.getClass() + " " + v);
  }
 }
}
Running the test class generates the following result:
animal=Animal [name=null, body=Body [weight=0.0, height=0.0]]
animal=Animal [name=tiger, body=Body [weight=123.0, height=0.0]]
name: class java.lang.String tiger
body.weight: class java.lang.Double 123.0

Friday, January 29, 2016

Use WebLogic Maven Plugin

This is for WebLogic 12c. First follow the instructions in reference [1] to install the WebLogic Maven Plugin. Then in the pom.xml file, you can use something like the following:
           <plugin>
                <groupId>com.oracle.weblogic</groupId>
                <artifactId>wls-maven-plugin</artifactId>
                <version>12.1.2.0</version>
                <configuration>
                  <middlewareHome>C:/oracle/wl12.1.2.0</middlewareHome>
                  <weblogicHome>C:/oracle/wl12.1.2.0/wlserver</weblogicHome>
                  <domainHome>C:/oracle/wl12.1.2.0/user_projects/domains/mydomain</domainHome>
                  <source>path/to/myApp.war</source>
                  <user>weblogic</user>
                  <password>welcome1</password>
                  <name>myApp</name>
                </configuration>
            </plugin>
 

The property values in the configuration may have their default values. You can configure the values as needed.

The goal for deployment is com.oracle.weblogic:wls-maven-plugin:deploy.

Reference

  1. https://docs.oracle.com/middleware/1212/wls/WLPRG/maven.htm