Sunday, September 26, 2010

Spring's BeanWrapper

I was searching for an utily class to get dinamically the properties of a bean. The first one I analyzed is BeanUtils.getSimpleProperty from Apache BeanUtils. The usage is quite simple and intuitive:
String myProp = BeanUtils.getSimpleProperty(Object bean, String name);
After searching for a while I discovered another way to do it, which allow me to do the same without using another library. Since I'm already using Spring in my project, the easiest way is to use a class from the framework, the Spring's BeanWrapper:
BeanWrapper newWrapper = PropertyAccessorFactory.forBeanPropertyAccess(bean);
String myProp = (String) newWrapper.getPropertyValue(name);  
As the APIs say, this interface supports nested properties enabling the setting of properties on subproperties to an unlimited depth, that is exactly what I was searching for.

Friday, January 8, 2010

BeanComparator and null values

I was working on a project where we need to use the Commons Beanutils library in order to make comparisons on some Java beans. Our goal was to compare multiple properties on bean which can contains null value. In order to achieve this, we try to use the BeanComparator togheter with the ComparatorChain class:
Person o1 = new Person();
Person o2 = new Person();
o1.setId(1);
o1.setName("Name");
o2.setId(1);
o2.setName("Name");
ComparatorChain comparatorChain = new ComparatorChain();
comparatorChain.addComparator(new BeanComparator("id"));
comparatorChain.addComparator(new BeanComparator("name"));
int result = comparatorChain.compare(o1, o2);

The problem here is with the null values. If the Id or the Name of a person is nulle you will get the following exception:
java.lang.ClassCastException: java.lang.NullPointerException
at org.apache.commons.beanutils.BeanComparator.compare(BeanComparator.java:155)
at org.apache.commons.collections.comparators.ComparatorChain.compare(ComparatorChain.java:277)
How to solve this issue? The solution is to use the NullComparator class and wrap the BeanComparator for example with the following code:
Person o1 = new Person();
Person o2 = new Person();
o1.setId(1);
o1.setName("Name");
o2.setId(1);
o2.setName("Name");
ComparatorChain comparatorChain = new ComparatorChain();
comparatorChain.addComparator(new BeanComparator("id"), new NullComparator());
comparatorChain.addComparator(new BeanComparator("name"), new NullComparator());
int result = comparatorChain.compare(o1, o2);
In this way the null values are managed properly and you do not have the NullPointerException anymore!

Thursday, December 31, 2009

Hibernate: Group By and Count

One of the best features of Hibernate are the Criteria Queries, which allow you to define parametric and easy way to query your data. In this post, I would like to summarize the usage of the class Projections allow you to group your result set by applying a projection to your Criteria query. For example, if you like to "group by" and to "count" the number of instances for a parameter "par", you can use the following lines of code:
Criteria criteria = criteria();

ProjectionList projList = Projections.projectionList();
projList.add(Projections.groupProperty("par"), "parAlias");
projList.add(Projections.rowCount(), "countAlias");
criteria.setProjection(projList);

criteria.setResultTransformer(Transformers.aliasToBean(ObjDto.class));
Some remarks:
  • It is important to underline the usage of the "groupProperty" method to apply the grouping on the parameter "par" and the usage of the method "rowCount()" to count the number of instances (i.e. SQL count(*))
  • It is also fundametal to note the usage of the aliases in both methods: countAlias and parAlias. These aliases are used by the ResultTransformer
  • The Data Transfer Object (DTO) class ObjDto contains only two attributes: countAlias and parAlias
  • Finally, it is important to see the usage of the setResultTransformer to copy the result of the query on our DTO bean class called ObjDto
The Projection class allows you to aggregate and group your Criteria queries in an easy way. Morevoer, they can simplify and reduce your lines of code!

Monday, December 28, 2009

Log4j and DailyRollingFileAppender

Log4j is a cool Java library which helps inserting log entry in the code. One of the best features of this logging library is the usage of the DailyRollingFileAppender for archive purposes. This appender allows you to roll the files with the user choosen frequency.
The configuration is quite simple, according to the manual:
# Default Log - Catch all
log4j.rootLogger=DEBUG, stdout, logfile
# Console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c.%M:%L] - <%m>%n
# File
log4j.appender.logfile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.logfile.File=${log.dir}/${log.apptype}/log.log
log4j.appender.logfile.DatePattern=.yyyy-MM-dd

As you can see, the log files are rolled with the layout defined by the DatePattern property: .yyyy-MM-dd. This should follow a valid SimpleDateFormat convention. However, in this way the old log files are stored like: log.log.2009-01-01, log.log.2009-01-02 and so on, which means a different extension every day! In order to solve this issue, it is possible to escape the literal with the quotes in the DatePattern property, and insert the extension in the pattern. This means that the DatePattern property can be like this:
log4j.appender.logfile.DatePattern='.'yyyy-MM-dd'.log'

By following this approach, each log file will be archived like log.log.2009-01-01.log, log.log.2009-01-02.log.

Wednesday, December 23, 2009

Windows cannot load the locally stored profile

I was working on a server where there was the following error after each logon:
Windows cannot load the locally stored profile: Insufficient security rights
or a corrupted local file. Windows has logged you in with a temporary profile
any setting you make will not be saved.

Searching on Google, I found that the problem is related to the fact that the user has been deleted and recreated in the system. Therefore, in order to solve it, you need to follow this procedure:
  1. Run "WHOAMI /USER" to determine your SID
  2. Check the ProfileImagePath value in the following registry key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\Cu rrentVersion\ProfileList\
  3. Delete the other SID that is pointing to the same ProfileImagePath

This solved the problem!

Monday, October 12, 2009

Jasper and Spring

Overview
I'm working in a project where we have to integrate Jasper Reports with Spring 2.5.6. After looking into the Spring Reference, I found that in the section 14.7. JasperReports there are all the details needed for the configuration of Jasper Report with Spring. Moreover, I found in the CVS an example of Jasper and Spring integration. However I was not able to find out a configuration with annotations based controllers.
Therefore, I decided to code an annotation based version of the Jasper Demo Spring Example...

Controller
Here an example of configuration by using annotation based @Controller:

@Controller
public class ReportController extends MultiActionController {
// other code

@RequestMapping(value = "/exporterParameters.html")
public ModelAndView handleExporterParameters(HttpServletRequest request,
HttpServletResponse response) throws Exception {
return new ModelAndView("htmlReport", getModel());
}
}
web.xml
Here the configuration in the web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Jasper Reports</display-name>

<description>Jasper Reports Sample Application</description>

<servlet>
<servlet-name>jrtest</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>jrtest</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>jrtest</servlet-name>
<url-pattern>*.pdf</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>jrtest</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>jrtest</servlet-name>
<url-pattern>*.csv</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>jrtest</servlet-name>
<url-pattern>*.xls</url-pattern>
</servlet-mapping>

<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- log4j -->
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:log4j.properties</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
</web-app>
jrtest-servlet.xml
Here instead the jrtest-servlet.xml. It is important to note the bean called htmlReport which contains the details related to the Jasper report definition. Moreover, here you can also see how to set the JRHtmlExporterParameter export properties.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">

<context:component-scan base-package="org.springframework.samples.jasperdemo.web"/>
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
<context:annotation-config />

<!-- If a JasperReports view requires more complex configuration then use the BeanNameViewResolver to
map a given view name to a given view bean -->

<bean id="nameViewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver"/>

<bean id="htmlReport" class="org.springframework.web.servlet.view.jasperreports.JasperReportsHtmlView">
<property name="url">
<value>/WEB-INF/reports/simpleReport.jasper</value>
</property>
<property name="exporterParameters">
<map>
<entry key="net.sf.jasperreports.engine.export.JRHtmlExporterParameter.HTML_FOOTER">
<value>Footer by Spring!&lt;/td&gt;&lt;td width="50%"&gt;&amp;nbsp; &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/body&gt;&lt;/html&gt;</value>
</entry>
</map>
</property>
</bean>

</beans>


So, in this simple example you can see how to use Jasper with Spring with the controller based annotations.
I hope this help!