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