Showing posts with label Spring Framework. Show all posts
Showing posts with label Spring Framework. Show all posts

Tuesday, October 15, 2019

Spring MVC - HTTP message converter

Quite often you need to provide users with the same data, but in different forms, like JSON, PDF, XLS, etc. If your application is Spring Framework based, this task can be achieved using HTTP message converters.

HTTP message converters are applied when HTTP request (or its parts) needs to be converted into type required for handler method argument (see: Handler methods - method arguments), or when value returned by handler method needs to be converted somehow to create HTTP response (see: Handler methods - Return values).

Spring Framework provides you with a set of predefined HTTP message converters, for ex. for byte arrays, JSON, etc. - This set can be modified or extended to your needs.
 
In this post we will focus on converting value returned from handler method into desired form, using example provided by me (see below for the link to the source code repository).

 Suppose that we have a controller returning some Team data, like this (yes, I know, I've ignored team Id)
@RestController
public class TeamDetailsController {

    @GetMapping("/teams/{teamId}/")
    public Team read() {
        final Set<TeamMember> members = new LinkedHashSet<>();
        members.add(new TeamMember("Albert Einstein", LocalDate.of(1879, 3, 14)));
        members.add(new TeamMember("Benjamin Franklin", LocalDate.of(1706, 1, 17)));
        members.add(new TeamMember("Isaac Newton", LocalDate.of(1643, 1, 4)));
        return new Team(members);
    }

}
In our example, handler method response will be, by default, converted into JSON:
{
  "members": [
    {
      "dateOfBirth": "1879-03-14",
      "name": "Albert Einstein"    },
    {
      "dateOfBirth": "1706-01-17",
      "name": "Benjamin Franklin"    },
    {
      "dateOfBirth": "1643-01-04",
      "name": "Isaac Newton"    }
  ]
}
If we would like to convert the data returned by the handler into XLS file, we can simply define a bean being HTTP message converter implementation, which will be activated by the HTTP Accept header:
@Service
public class TeamToXlsConverter extends AbstractHttpMessageConverter<Team> {

    private static final MediaType EXCEL_TYPE = MediaType.valueOf("application/vnd.ms-excel");

    TeamToXlsConverter() {
        super(EXCEL_TYPE);
    }

    @Override
    protected Team readInternal(final Class<? extends Team> clazz, final HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        return null;
    }

    @Override
    protected boolean supports(final Class<?> clazz) {
        return (Team.class == clazz);
    }

    @Override
    protected void writeInternal(final Team team, final HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        try (final Workbook workbook = new HSSFWorkbook()) {
            final Sheet sheet = workbook.createSheet();
            int rowNo = 0;
            for (final TeamMember member : team.getMembers()) {
                final Row row = sheet.createRow(rowNo++);
                row.createCell(0)
                   .setCellValue(member.getName());
            }
            workbook.write(outputMessage.getBody());
        }
    }

}
You have to keep in mind that in our example, defined HTTP message converter will be applied always when the handler method returns value of type Team (see supports method), and HTTP Accept header matches "application/vnd.ms-excel". In this case, XLS file generated by the HTTP message converter is returned instead of JSON representation of Team.

Few links for the dessert:

Follow-ups:


This article has been republished on DZone's Java Zone (10/19/2019) and on Java Code Geeks (10/21/2019).

Sunday, December 2, 2012

Spring's Web MVC - Redirect to the Memory Leak

They say that one rock can cause an avalanche. Lately, one of my Colleagues, Marcin Radoszewski, gave me such a rock. You'll probably never guess what it is, but there is a chance, that you use it in many of your Web Applications. Allow me to introduce this rock to you :)

You probably well know redirect after post pattern. Using Spring Framework you have few ways to implement it, let's focus on one of them, returning the target URL as the String with redirect: prefix.

Suppose that we have controller using this method of redirecting, and we have to pass some parameters during the redirect, let it be some entity ID for example:

@RequestMapping(method = RequestMethod.POST)
public String onPost(...) {
    ...
    return "redirect:form.html?entityId=" + entityId;
}

As you see, our rock doesn't look dangerous, it even doesn't look suspicious :) - What the heck is wrong with that?! - you may ask. Well, to explain that, we have to take a look at the way how Spring Framework handles the value returned by you.

You may start from reading Resolving views in Spring Framework documentation, and then take a closer look at the source code of AbstractCachingViewResolver, which is base class for many different View Resolvers in Spring, including: JSP, FreeMarker, Velocity, Jasper Reports, Tiles and XSLT view resolvers.

When resolveViewName method is called on AbstractCachingViewResolver it uses HashMap based view cache to speed up view resolving in the future calls, and cache key is by default created using view name and current locale.

Now to the clue :) - when you use the above method of redirecting, Spring Framework uses the whole String returned from your controller's method as the view name, including all parameters included in the target URL. Each time you perform the redirect, the parameters may vary, thus such a redirect will leave one additional entry in view cache of  AbstractCachingViewResolver, causing memory leak.

How soon that will kill my application? - you may ask. That depends on the amount of memory assigned to JVM, and the number of performed redirects :) - I've made some tests using: -Xmx64M option, with simple application build from only one controller - see this example. After about 76400 redirects the application died with OutOfMemoryError: Java heap space.
 


Follow-ups:


This article has been republished on Java Code Geeks (12/07/2012), and on Dzone's Javalobby (12/10/2012).

Sunday, February 19, 2012

Spring MVC - Flash Attributes

Latest Spring Framework incarnation (3.1) brought interesting feature called Flash Attributes. It is remedy for the problem mentioned a long time ago, in one of my posts: Spring MVC - Session Attributes handling. This problem can be described in few words: if we want to pass the attributes via redirect between two controllers, we cannot use request attributes (they will not survive the redirect), and we cannot use Spring's @SessionAttributes (because of the way Spring handles it), only ordinary HttpSession can be used, which is not very convenient.

Below you will find an example of Flash Attributes usage, before you start reviewing it, read Using flash attributes section of Spring documentation.

Suppose that we have two controllers: AController and BController, first one will prepare some data and pass to the second using Flash Attributes after the form submission. On the AController we will have something like this:
@RequestMapping(method = RequestMethod.POST)
public String handleFormSubmission(..., final RedirectAttributes redirectAttrs) {
    ...
    redirectAttrs.addFlashAttribute("AttributeName", value);
    return "redirect:to_some_url_handled_by_BController";
}
When the form will be submitted, attribute value will be stored as Flash Attribute named "AttributeName", and thanks to the Spring, will be passed to BController, where it can be used for example in following way:
@Controller
...
@SessionAttributes("AttributeName")
public class SearchCriteriaHandler {
    ...
    @RequestMapping(method = RequestMethod.GET)
    public void handleGetRequest(@ModelAttribute("AttributeName") final SomeType value) {
        ...
    }
    ...
}

Before your handler method will be called, Spring Framework will populate the Model with the available Flash Attributes - at this point value passed from AController will become a model attribute for the BController. Note, that because we also defined this attribute as the Session Attribute, it will be automatically stored for future usage within this controller, after the GET request handling.

Let me say that I was waiting for this feature for the long time, ;)

Related Posts: Spring MVC - Session Attributes handling

Saturday, March 5, 2011

Spring @Autowired, JUnit and Mockito

Few days ago I've encountered interesting problem with autowiring Mockito based Spring Framework beans, let me share it with you :)

Everything started when I've made JUnit test for some business logic code.
...
import static junit.framework.Assert.assertNotNull;
...
@ContextConfiguration({ "classpath:.../business-logic.xml", "classpath:.../orm-jpa.xml",
"classpath:.../test/mockito.xml", ... })
public class MockitoTest extends AbstractJUnit4SpringContextTests {

    @Autowired
    private EmployeeManager employeeManager;

    @Test
    public void test01() {
        assertNotNull(employeeManager.get(Long.valueOf(1L)));
    }
}
Default EmployeeManager implementation used by me delegates the entity fetching to EmployeeDAO:
@Component("business-logic.EmployeeManager")
public class DefaultEmployeeManager implements EmployeeManager {

    @Autowired
    private EmployeeDAO employeeDAO;

    public Employee get(Long identifier) {
        return employeeDAO.get(identifier);
    }
}
EmployeeDAO in this example is a mock created using Mockito:
<bean id="persistence.EmployeeDAO" class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg value="....dao.EmployeeDAO" />
</bean>
When I tried to run the test, it responded with beautiful exception:
java.lang.IllegalStateException: Failed to load ApplicationContext
...
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'business-logic.EmployeeManager': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private ... .dao.EmployeeDAO ... .logic.impl.DefaultEmployeeManager.employeeDAO; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [... .dao.EmployeeDAO] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
...
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private ... .dao.EmployeeDAO ... .logic.impl.DefaultEmployeeManager.employeeDAO; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [... .dao.EmployeeDAO] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. 
My first thoughts were - Why the heck it doesn't work?! There is a bean which can be used for autowiring! - but after few seconds I realized that I'm wrong :) - Here is the explanation why ;)

When Spring Framework creates the beans, and tries to autowire the EmployeeManager properties it seeks for the bean having class EmployeeDAO, but at this point our Mockito based bean is still a Factory, not concrete instance, therefore Spring Framework checks the mock method of our Factory, to determine the type of returned objects. As you may see below it has signature:
public static <T> T mock(Class<T> classToMock)
and thus the determined type is Object, which of course doesn't match the desired one (EmployeeDAO).

Let me read your mind at this point ;) - You think: What can we do with it? - Well, we have to assure that EmployeeDAO bean will be turned into real instance before it will be requested for autowiring.
In other words EmployeeDAO bean should be defined BEFORE the beans using it for autowiring.

We can do it in following ways:
  1. Change the @ContextConfiguration annotation to move the file defining this bean (mockito.xml) in front of all others (very naive solution, but sometimes sufficient ;) )
  2. Define for all beans referring EmployeeDAO that they depend on it
The last one can be achieved in following way:
@Component("business-logic.EmployeeManager")
@DependsOn("persistence.EmployeeDAO")
public class DefaultEmployeeManager implements EmployeeManager ...
when you define your beans using context scanning, or if you simple define them in XML, using depends-on attribute of the bean.

PS: Libraries/Frameworks used in the above example: Spring Framework - 3.0.4, Mockito - 1.8.5 and JUnit 4.8.1

Sunday, January 30, 2011

STS - @RequestMappings View

Sometimes I wonder if I really know the tools lurking beneath the surface of my Eclipse IDE ;) - today I've discovered @RequestMappings View - part of SpringSource Tool Suite (STS). I know, you probably use it for centuries already ;) - but for me it was really nice surprise :) - The rest of this post is for all the developers having feeling that there should be something like that, but still looking for it ;)

Let's start from the beginning, and open this View:


At the bottom of the Eclipse window you should see something like this:


Let's populate it with some data now ;) - this is the hardest part, because your project should have a Spring Project Nature, my own didn't have it, therefore I had to correct its configuration - adding missing Nature first:


and defining which files contain Spring Beans:


Finally we can find the file defining our application's request handlers, and populate the View with defined mappings:


Which will look somehow like this now:


When you click twice on any of the lines in this view you'll be transfered to the appropriate handler method, like in this example:


I'm still learning this View, and hope that next STS versions (I'm using 2.5.2 currently) will bring more functionality in it.

Saturday, January 15, 2011

Spring - Using Beans in HTTP Servlet

So you want to use your beautiful and shining Spring Beans in ugly and ordinary HTTP Servlet? Don't be ashamed ;) Sometimes we all have to do it, and we do it in many different ways ;) Below you may find few examples.

Old-fashioned way :) - used by me till some beautiful Thursday morning ...
public class BeanTest extends HttpServlet {

    private EmployerManager employerManager;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // Do something amazing with the Spring Bean ...
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        WebApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(config.getServletContext());
        employerManager = applicationContext.getBean("business-logic.EmployerManager", EmployerManager.class);
        super.init(config);
    }

}
As you see, you can access Spring WebApplicationContext and then the desired bean by its identifier. Main disadvantage of this method is the bean identifier hardcoded into Servlet code. Especially if you are performing automatic component scan in Spring (ex. <context:component-scan base-package="[...].logic.impl" />). In this case you have two choices:
  1. Define the identifier of the bean using annotations:
    
    @Service("business-logic.EmployerManager")
    public class DefaultEmployerManager implements EmployerManager {
       ...
    }
    
  2. Use default bean identifier created by Spring in your Servlet - see: Naming autodetected components
Now relax, close your eyes, think about the refactoring the code, and all those hardcoded names which you should change by hand. It's time to forget this method my Friend, as I did. :)

Thankfully there are many young people, with open mind, who don't use the old-fashioned ways of doing things, and invent their own, as did my colleague - Bartek. Below you may find method doing the same as the above one, but based on @Autowired annotation usage.
public class BeanTest extends HttpServlet {

    @Autowired
    private EmployerManager employerManager;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // Do something amazing with the Spring Bean ...
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, config.getServletContext());
        super.init(config);
    }

}

SpringBeanAutowiringSupport will inject the appropriate Spring Beans into all your Servlet's properties marked with @Autowired annotation. That's all :) No hardcoding of bean names, no worries about future refactorings. Now relax, close your eyes, ...

Sunday, January 9, 2011

Spring MVC - Session Attributes handling

Spring Framework 2.5 has introduced annotation based programming model for MVC Controllers. Spring Framework 3 has made next step, and deprecated widely used SimpleFormController. Now we are all doomed to use annotations ;) but do we really understand what is going on behind the scenes?

Let's take a look at the @SessionAttributes and SessionStatus today :) If you are not familiar with them, you should start with Specifying attributes to store in a session with @SessionAttributes and Supported handler method arguments and return types before you will continue reading this post.

@SessionAttributes annotation is used on the Controller class level to declare used session attributes. All Model attributes having names or types defined in this annotation will be automatically persisted and restored between the subsequent requests. Sounds easy and beautiful, isn't it? Small declaration instead of boring HttpSession's getAttribute / setAttribute calls. Tempting :), try it and you'll find it can be dangerous too ...

"Automatically persisted" should alarm you :) - where? how? when? and for how long? - you should ask immediately :) - Well, let's take a deeper look at it :)

Strategy used for persisting Model attributes is defined by SessionAttributeStore implementation, Spring Framework by default uses DefaultSessionAttributeStore which in turn relies on HttpSession as the storage (for Servlet environment). You can provide custom implementation of the SessionAttributeStore interface, which you then enable by supplying a custom bean configuration for an AnnotationMethodHandlerAdapter (see Spring MVC pitfall - overriding default beans).

Model attributes are persisted at the end of request handling by AnnotationMethodHandlerAdapter, after calling your handler method responsible for request handling and after determining the ModelAndView for the response. Their names in Model are used as their names in the persistent storage, ex. @SessionAttributes("form") will trigger persisting Model attribute named "form" as HttpSession attribute named "form".

Persisted Model attributes will be removed only if you'll call SessionStatus.setComplete() method in some of your handler methods.

If at this point you still don't have any doubts, let me share my own with you:
  1. Cleaning not needed session attributes is a little tricky, because in a little more complicated applications users usually have possibilities to use Breadcrumb Navigation, some Menus, etc., each of them can cause switching the flow from one to another without calling SessionStatus.setComplete() method (and thus without cleaning the attributes used by the flow). 
  2. Using default SessionAttributeStore implementation and same names for Model attributes for different types of data will sooner or later lead to beautiful ClassCastException. Why? Because when some part of your application will persist attribute of class A under name "form", and user will then switch without cleaning it to other functionality, using also "form" attribute, but expecting it to be of class B, that will not end with the exception only if A extends B.
We all struggle with the HttpSession attributes cleaning, even not using Spring Framework, in fact. Both the problems mentioned by me above can be found outside the Spring Framework based application too. Using this beautiful and shining @SessionAttributes annotation you have to know how does it work, otherwise it will make you mad, instead of helping you.

For the dessert :) - few pitfalls you may encounter while using @SessionAttributes:
  1. When you refer to non-existing session attribute using @ModelAttribute annotation, HttpSessionRequiredException will be raised, like in following example:
    @SessionAttributes("abc")
    public class MyController {
    
        @RequestMapping(method = RequestMethod.GET)
        public void onGet(@ModelAttribute("abc") String something) {
            ...
        }
    }
    
    This exception, like the any other, can be then handled by you, using @ExceptionHandler annotation for example.
  2. SessionStatus.setComplete() method will trigger cleaning of Session Attributes, but only those which Spring will find "actual session attribute". Suppose that you declare 3 session attributes, but use only 1 of them in your handler method parameters, like in following example:
    @SessionAttributes({ "abc", "def", "ghi" })
    public class BindingTestController {
    
        @ModelAttribute("abc")
        public String createABC() {
            return "abc";
        }
    
        @RequestMapping(method = RequestMethod.GET)
        public void onGet(@ModelAttribute("abc") String something) {
            // do nothing :)
        }
    
        @RequestMapping(method = RequestMethod.POST)
        public void onPost(@ModelAttribute("abc") String something, BindingResult bindingResult, SessionStatus sessionStatus) {
            sessionStatus.setComplete();
        }
    
    }
    
    Only the "abc" attribute will be considered as "actual session attribute", and removed on POST request.
  3. Attribute will be flagged as "actual session attribute" while resolving @ModelAttribute annotated method parameters and AFTER request processing - in this case all Model attributes are checked if they should be persisted (according to @SessionAttributes annotation). 
  4. Assuming that you pass the parameter to some flow, using @SessionAttributes mechanism may lead to surprises, sometimes unpleasant :( Suppose that you want to start new flow programmatically, from Controller A, you put the flow parameter on session, under name "parameter", and mark the Controller B (handling the entry point to the flow) with the @SessionAttribute("parameter"). That will not work my Friend, "parameter" will not be restored into B Controller's Model on entry, because it is not an "actual session attribute" (see above), at least before the first request handling. (Spring 3.1 brings remedy for this problem, named Flash Attributes - see my post Spring MVC - Flash Attributes)

Sunday, December 5, 2010

JPA - Lazy Loading and View rendering

JPA would be unusable without Lazy Loading, which is a feature allowing fetching of correlated entities from the database when they are referenced for the first time, rather than immediately when you perform the database query. Imagine that you cannot use Lazy Loading ... One query for the single result can return the whole database in this case, if you are lucky enough ;)

Each time when you use @OneToMany or @ManyToMany annotations, Lazy Loading is active by default, without any effort. For all other types of associations you may control it, using fetch attribute of annotation defining the association.

Sounds wonderful, isn't it? Everything is done automagically without my intervention, required entities are fetched from the database when they are needed, the world is beautiful and free of violence ... Well, not quite, my dear Watson ...

You have to be aware, that some entities may be referenced for the first time at the View rendering level. For Spring Framework based application with JSP used for View layer (but not only in this setup) this can lead to miscellaneous problems, which depends on used JPA provider.

Let's take a deeper look at the potential problems, using usual Employer - Employee - Benefit example from my previous JPA related posts. Suppose that we want to fetch the Employer information from the database, but the Employees and Benefits only when they are referenced. Associations between Employer, Employees and Benefits look like this:
@Entity
@Table(name = "EMPLOYERS")
public class Employer implements Serializable {
    ...
    private List<Employee> employees;
    ...
    @OneToMany(mappedBy = "employer")
    public List<Employee> getEmployees() {
        return employees;
    }
    ...
}

@Entity
@Table(name = "EMPLOYEES")
public class Employee implements Serializable {
    ...
    private List<Benefit> benefits;
    private Employer employer;
    ...
    @OneToMany(mappedBy = "employee")
    public List<Benefit> getBenefits() {
        return benefits;
    }

    @ManyToOne
    @JoinColumn(name = "EMPLOYER_ID")
    public Employer getEmployer() {
        return employer;
    }
    ...
}

@Entity
@Table(name = "BENEFITS")
public class Benefit implements Serializable {
    ...
    private Employee employee;

    @ManyToOne
    @JoinColumn(name = "EMPLOYEE_ID")
    public Employee getEmployee() {
        return employee;
    }
    ...
}
DAO fetching the Employer data for Model:
@Repository
public class DefaultEmployerDAO implements EmployerDAO {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public Employer get(Long identifier) {
        return entityManager.find(Employer.class, identifier);
    }
    ...
}
And the JSP view displaying the Employer information, along with the Employees, and their Benefits:
<h1><c:out value="${employer.businessName}" /></h1>
...
<c:forEach items="${employer.employees}" var="e">
    <tr>
        <td><c:out value="${e.firstName}" /></td>
        <td>
            <ul>
               <c:forEach items="${e.benefits}" var="b">
                   <li><c:out value="${b.name}" /></li>
               </c:forEach>
            </ul>
        </td>
    </tr>     
</c:forEach>
Let's examine how it will behave for different JPA providers, starting from EclipseLink 2.1.1. When we try to open desired view in browser, we will see something like this:


Application activity while preparing the Model (seen from the Spring Insight):


and while rendering the view itself:


All the SQL queries visible at the view rendering level are caused by Lazy Loading.
As you see the EclipseLink and Lazy Loading works without any special effort :)

Now it's time to check Hibernate 3.4.0.GA. For this provider, when we try to open the desired view in browser, we will see beautiful
LazyInitializationException: failed to lazily initialize a collection of role: [...].entities.domain.Employer.employees, no session or session was closed
Sweet, isn't it? :) - old hibernate session closed problem strikes again, this time in JPA ;) - but believe me, this is not the worst problem you may encounter using JPA ;), because with a little help from OpenEntityManagerInViewFilter it can be quickly corrected (if you are using hibernate for a little longer, you are probably well aware of very useful OpenSessionInViewFilter used in similar situations with "pure" hibernate). Let's add this filter to the web.xml:
<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>persistence.EntityManagerFactory</param-value>
    </init-param>
</filter>
...
<filter-mapping>
    <filter-name>OpenEntityManagerInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
The entityManagerFactoryBeanName parameter should match the name of your Entity Manager factory bean in Spring Framework configuration.

With this filter we can get finally the desired results. This time Application activity while preparing the Model looks like this:

and while the view rendering:

Finally OpenJPA 2.0.1 - first try without the OpenEntityManagerInViewFilter, and we will see in browser:

Good Lord! No data loaded at all ... no exceptions reported ... the worst situation, because you don't know if there are no data to view in the database, or there is something wrong with the application! :(

Let's add the OpenEntityManagerInViewFilter, and try again:

Now it looks as expected!
Application activity while preparing the Model:


and the view rendering:


As you see above, Lazy Loading requires for both Hibernate and OpenJPA OpenEntityManagerInViewFilter to be used, while EclipseLink work without any special effort.

Sunday, November 28, 2010

Spring MVC pitfall - overriding default beans

We all learn the whole life :) My last lesson was related to overriding default beans registered by mvc namespace parsers. It all started when I read Customizing WebDataBinder initialization section of Spring Framework 3.0 documentation. You can read there something like this:
To externalize data binding initialization, you can provide a custom implementation of the WebBindingInitializer interface, which you then enable by supplying a custom bean configuration for an AnnotationMethodHandlerAdapter, thus overriding the default configuration.
Encouraged by this citation I registered my own bean along the usual <mvc:annotation-driven />
<mvc:annotation-driven />

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="webBindingInitializer" ref="MyWebBindingInitializer" />
</bean>
    
<bean class="[...].DefultWebBindingInitializer" id="MyWebBindingInitializer" />
At this point I've encountered first problem - the order of beans registration matters in the above case - first registered handler will be used. This is reasonable, one AnnotationMethodHandlerAdapter is registered by Spring while processing <mvc:annotation-driven /> and one by me. First registered wins :)

I've moved my bean before <mvc:annotation-driven /> and started enjoying its work. After few days I was preparing some functionality returning one value from the handler method, which should be converted automagically to JSON response (see my posts: JSON - Jackson to the rescue and JSON - Jackson Serialization Narrowed). To my surprise, usual configuration didn't worked, I started digging through my own and Spring Framework code, and found the reason (which in fact can be also deduced from mvc:annotation-driven documentation) - my own bean didn't registered the same message converters as parser responsible for processing mvc:annotation-driven (AnnotationDrivenBeanDefinitionParser) and especially one needed by me: MappingJacksonHttpMessageConverter.

At this point I had few possibilities to solve this problem, I could for example register appropriate message converter myself, but I decided to go a different way, because solving the problems generated ourselves, is worse than avoiding those problems :)

I've prepared BeanPostProcessor implementation correcting the one property required by me:
public class MVCConfigurationPostProcessor implements BeanPostProcessor {

    private WebBindingInitializer webBindingInitializer;

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof AnnotationMethodHandlerAdapter) {
            ((AnnotationMethodHandlerAdapter) bean).setWebBindingInitializer(webBindingInitializer);
        }
        return bean;
    }

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }   

    public void setWebBindingInitializer(WebBindingInitializer webBindingInitializer) {
        this.webBindingInitializer = webBindingInitializer;
    }

}
Then I've corrected my Spring configuration to:
<bean class="[...].MVCConfigurationPostProcessor">
    <property name="webBindingInitializer" ref="MyWebBindingInitializer" />
</bean>
    
<bean id="MyWebBindingInitializer" class="[...].DefultWebBindingInitializer" />
    
<mvc:annotation-driven />
Finally I was able to enjoy both AnnotationMethodHandlerAdapter using my own WebBindingInitializer and JSON conversion working correctly :).

Saturday, November 13, 2010

JMX - Counting Users

Have you ever asked yourself how many users are using your favorite service at the moment? Watching the leaves falling down outside your window you ask yourself - am I alone? Is there anyone logged in except me? Hey! Stop watching the leaves, they will only make you more melancholic ;) - use the JMX :)

Read this article, and you'll discover the idea of controlling number of users logged in for web application based on Spring FrameworkSpring Security and Java Management Extensions (JMX).

First of all, we'll define the Managed Bean:
@ManagedResource(objectName = "Test:name=BigBrother")
public class BigBrother implements NotificationPublisherAware {

    private NotificationPublisher notificationPublisher;

    private final AtomicInteger userCounter = new AtomicInteger(0);

    @ManagedAttribute
    public int getUserCounter() {
        return userCounter.intValue();
    }

    @Override
    public void setNotificationPublisher(NotificationPublisher notificationPublisher) {
        this.notificationPublisher = notificationPublisher;
    }

    public void userLoggedIn(Principal principal) {
        userCounter.incrementAndGet();
        notificationPublisher.sendNotification(new Notification("User '" + principal.getName() + "' logged in.", this, 0));
    }

    public void userLoggedOut(Principal principal) {
        userCounter.decrementAndGet();
        notificationPublisher.sendNotification(new Notification("User '" + principal.getName() + "' logged out.", this, 0));
    }

}
Now we have to call the appropriate methods of this bean each time user will log in or log out.

First case is definitely the easiest one :) We may use the default behavior of Spring Security. Each time user is successfully authenticated, the Spring Security tries to publish an application event related to it. Happily for us when you use Security Namespace Configuration the default event publisher used (DefaultAuthenticationEventPublisher) sends the AuthenticationSuccessEvent. 
This type of events can be observed by the bean similar to:
public class LoginListener implements ApplicationListener<AuthenticationSuccessEvent> {

    @Autowired
    private BigBrother bigBrother;

    @Override
    public void onApplicationEvent(AuthenticationSuccessEvent event) {
        bigBrother.userLoggedIn(event.getAuthentication());
    }
}
All you have to do is register the above bean in Spring context :)

Now it's time to face the handling of user's log out. We could use nice feature of Spring Security LogoutFilter - each time user log out is handled by it, and the log out finishes successfully, the defined LogoutSuccessHandler is called. You may think - It can't be so easy - Exactly, my dear Watson, it can't be :)

You have to remember that users usually do what they want, and not what you expect them to do :) They don't have to log out from your application, then can just close the browser window, or shutdown the computer, or just leave the browser alone for so long that HTTP session will expire.

The expiration is the clue :) We can use HttpSessionBindingListener interface - if we add object implementing this interface to the HTTP session, it will be notified when it will be removed from session, which can be triggered when: a) session will be invalidated on user's log out (default behavior of  Spring Security configured using Security Namespace Configuration), b) session expires after some time of user inactivity, c) session attribute is removed on developer's demand

Let's start with the following XML configuration:
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:security="http://www.springframework.org/schema/security"
       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/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
    ...
    <security:http auto-config='true'>
        ...
        <security:custom-filter ref="security.BigBrotherHelpingFilter" after="SECURITY_CONTEXT_FILTER" />
        ...                
    </security:http>
    ...                            
    <bean id="security.BigBrotherHelpingFilter" class="....BigBrotherHelpingFilter" />
</beans>
The above XML will add our own authentication processing filter into Spring Security filters chain, right after the SecurityContextPersistenceFilter (see: Adding in Your Own Filters). It will be something like this:
public class BigBrotherHelpingFilter extends GenericFilterBean {

    private String attributeName = "__BIG_BROTHER_HELPER";

    @Autowired
    private BigBrother bigBrother;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
                    ServletException {
        chain.doFilter(request, response);
        if (((HttpServletResponse) response).isCommitted()) {
            return;
        }
        HttpSession httpSession = ((HttpServletRequest) request).getSession(false);
        if (null == httpSession) {
            return;
        }
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        if (null != authentication) {
            httpSession.setAttribute(attributeName, new AuthenticationHolder(authentication, bigBrother));
        } else {
            httpSession.setAttribute(attributeName, null);
        }
    }
    ...
}
And the last part of code for this post:
public class AuthenticationHolder implements HttpSessionBindingListener {

    private final Authentication authentication;

    private final BigBrother bigBrother;

    public AuthenticationHolder(Authentication authentication, BigBrother bigBrother) {
        this.authentication = authentication;
        this.bigBrother = bigBrother;
    }

    public Authentication getAuthentication() {
        return authentication;
    }

    @Override
    public void valueBound(HttpSessionBindingEvent event) {
        // Ignore ...
    }

    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {
        bigBrother.userLoggedOut(authentication);
    }

}

Let's test the whole setup using VisualVM - when you run it, select your servlet container, and then available managed beans, under Test/BigBrother you should see the bean used by us:


Let's subscribe to the notifications in Notifications tab, and try to log in to our web application, you should see new notification:


When you select the Operations tab, and run getUserCounter operation you'll receive:

Now let's try to log out, then check the notifications:


and the user counter:
You can observe similar effect to log out when you leave your browser untouched until your HTTP session will expire (by default 30 minutes). 

Monday, November 1, 2010

JMX - Notification Publishing

In my previous post: JMX - Life Savior or Backdoor - I've prepared an example of JMX usage within the Spring Framework, let's modify it a little, to show the method of publishing notifications.

@ManagedResource(objectName = "Test:name=Cerberus")
public class Cerberus extends HandlerInterceptorAdapter implements NotificationPublisherAware {

    private NotificationPublisher notificationPublisher;

    private boolean opened = true;

    @ManagedOperation
    public void close() {
        this.opened = false;
        notificationPublisher.sendNotification(new Notification("Hades closed", this, 0));
    }

    @ManagedAttribute
    public boolean isOpened() {
        return opened;
    }

    @ManagedOperation
    public void open() {
        this.opened = true;
        notificationPublisher.sendNotification(new Notification("Hades opened", this, 0));
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (!opened) {
            notificationPublisher.sendNotification(new Notification("Hades out of order", this, 0));
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
        }
        return opened;
    }

    public void setNotificationPublisher(NotificationPublisher notificationPublisher) {
        this.notificationPublisher = notificationPublisher;
    }

}

Again we will use the VisualVM for watching our managed bean. Run it, select tomcat on the left pane, switch to the MBeans tab, select Test and then Cerberus, and finally switch to the Notifications. You will see:
To watch the notifications coming from the managed bean you have to subscribe to them first, click on the "Subscribe" and switch to the Operations - run the close operation - and check what is visible in Notifications now:


Try to reach the URL to which the Cerberus is bound - you'll get 404 error in return (as expected), and another notification:


Running the open method will give you another one:


Now you may make yourself a cup of tea, and become a Big Brother for a while, watching the internals of your application ;)

Sunday, October 31, 2010

JMX - Life Savior or Backdoor

The Java Management Extensions (JMX) API is a standard for managing and monitoring applications and services. Its usage in application build using Spring Framework is very simple and easy. I hope you'll agree with me after lecture of this post.

We will use one of the possible solutions for JMX and Spring usage, based on Java 5 annotations. On the Spring configuration level we need only one new line:

<beans xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" 
xsi:schemalocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/context 
           http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    ...
    <context:mbean-export />
    ...
</beans>

The rest of this magic is done at the Java source :). Let's build a handler interceptor, which will be also exported as the managed bean:

@ManagedResource(objectName = "Test:name=Cerberus")
public class Cerberus extends HandlerInterceptorAdapter {

    private boolean opened = true;

    @ManagedOperation
    public void close() {
        this.opened = false;
    }

    @ManagedAttribute
    public boolean isOpened() {
        return opened;
    }

    @ManagedOperation
    public void open() {
        this.opened = true;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (!opened) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
        }
        return opened;
    }

}

Suppose that we map this interceptor to some URL within our web application, check if the target URL will return some response ...

Wonderful! But wait, where can we see this managed bean? - you may say :) - sometimes you need the glasses to read the newspaper ;) - We will use the VisualVM as the glasses, which will help us to see the managed beans. When we run it, we will see something like this:
Now select the Tomcat on the left pane, and when the right one will display the tomcat information, choose MBeans (Managed Beans)
From the list of Managed Beans choose Test and then Cerberus - why? We named our bean this way :) - using: @ManagedResource(objectName = "Test:name=Cerberus"), now you should see:
We used the @ManagedAttribute only on isOpened method, therefore the opened attribute will be read only. Let's switch to the Operations tab, which contains:
As you see we can run from this tab 3 methods marked with @ManagedOperation or @ManagedAttribute annotations. Let's run the close method - click on the close button and following dialog will appear:
Let's check the opened attribute using isOpened method call:
Wonderful, but what does it mean to our handler interceptor? Let's try to reach the URL protected by our Cerberus again:
It looks like the Cerberus stopped the request, sending 404 error - as we asked him to do :)

Amazing and terrifying - you can control your application behavior from outside - use it with care ...

Thursday, October 21, 2010

JSON - Jackson Serialization Narrowed

In my last post - JSON - Jackson to the rescue - I've described quick example of JSON response creating. Let's back to this example and take a deeper look at the created response.

[{"id":1, "benefits":[{"name":"Healthy Employees", "id":1, "type":"HEALTH_COVERAGE", "startDate":1104534000000, "endDate":null}, {"name":"Gold Autumn","id":2,"type":"RETIREMENT_PLAN","startDate":1104534000000,"endDate":null},{"name":"Always Secured","id":3,"type":"GROUP_TERM_LIFE","startDate":1104534000000,"endDate":null}],"firstName":"John"},{"id":2,"benefits":[],"firstName":"Mary"},{"id":3,"benefits":[],"firstName":"Eugene"}]

There are situations, where parts of the data represented by domain entities should remain invisible for the public, and therefore shouldn't be serialized and exposed via JSON. We will try to narrow our response down to make it a little more secure from our point of view - by hiding the Employee's benefits.

First method to achieve this goal is usage of @JsonIgnore annotation.

@Entity
@Table(name = "EMPLOYEES")
public class Employee implements Serializable {
   ...
    @JsonManagedReference("employee-benefit")
    @OneToMany(mappedBy = "employee", cascade = CascadeType.PERSIST)    
    @JsonIgnore
    public List getBenefits() {
        return benefits;
    }
    ...
}

The above modification will change the response to:

{"employees":[{"id":1,"firstName":"John"},{"id":2,"firstName":"Mary"},{"id":3,"firstName":"Eugene"}]}

which is exactly what we need - but don't smile too wide yet ;) - consider situation when you want the same entity to be serialized in different ways depending on the request "context". It is very probable that you would like give to customer only the properties necessary in the response, while the admin should see much more in his part of application. @JsonIgnore is unusable in this case :( - but wait, don't panic yet - here we come to the second solution - @JsonView annotation

Let's modify the controller preparing the JSON response in the following manner:

@Controller
@RequestMapping("/employee-list.json")
public class EmployeeListController {

    private static final String MODEL_KEY_EMPLOYEES = "employees";

    @Autowired
    private EmployerDAO employerDAO;

    private final ObjectMapper objectMapper = new ObjectMapper();

    private final MappingJacksonJsonView view = new MappingJacksonJsonView();

    public EmployeeListController() {
        objectMapper.getSerializationConfig().setSerializationView(Employer.PublicView.class);
        view.setObjectMapper(objectMapper);
        view.setRenderedAttributes(new HashSet(Arrays.asList(MODEL_KEY_EMPLOYEES)));
    }

    @RequestMapping(method = RequestMethod.GET)
    public View handleGet(@RequestParam("employerId") Long employerId, Model model) {
        model.addAttribute(MODEL_KEY_EMPLOYEES, employerDAO.getEmployees(employerId));
        return view;
    }
}

As you see we will use the Spring Framework's MappingJacksonJsonView, with our own ObjectMapper instance. In controller's constructor we define which model attributes should be serialized (using setRenderedAttributes method), and switch serialization view to the Employer.PublicView. This will force Jackson to serialize only those properties which don't have @JsonView annotation at all, or have @JsonView annotations matching specified view. If we will modify our entities to look like this:

@Entity
@Table(name = "EMPLOYERS")
public class Employer implements Serializable {

    public interface PrivateView { }

    public interface PublicView { }
    ...
    @Column(name = "BUSINESS_NAME")
    @JsonView(PublicView.class)
    public String getBusinessName() {
        return businessName;
    }

    @JsonManagedReference("employer-employee")
    @OneToMany(mappedBy = "employer", cascade = CascadeType.PERSIST)
    @JsonView(PublicView.class)
    public List getEmployees() {
        return employees;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long getId() {
        return id;
    }
    ...
}

@Entity
@Table(name = "EMPLOYEES")
public class Employee implements Serializable {
    ...
    @JsonManagedReference("employee-benefit")
    @OneToMany(mappedBy = "employee", cascade = CascadeType.PERSIST)
    @JsonView(PrivateView.class)
    public List getBenefits() {
        return benefits;
    }

    @JsonBackReference("employer-employee")
    @ManyToOne(optional = false)
    @JoinColumn(name = "EMPLOYER_ID")
    public Employer getEmployer() {
        return employer;
    }

    @Column(name = "FIRST_NAME")
    public String getFirstName() {
        return firstName;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long getId() {
        return id;
    }
    ...
}

we will get exactly the same response as for @JsonIgnore usage, but in a little more flexible way :)

{"employees":[{"id":1,"firstName":"John"},{"id":2,"firstName":"Mary"},{"id":3,"firstName":"Eugene"}]}

The last possibility worth mentioning here is usage of mix-in annotations, let's change our controller once again to show the idea standing behind it.

@Controller
@RequestMapping("/employee-list.json")
public class EmployeeListController {

    @JsonIgnoreProperties("benefits")
    private static class EmployeePublicView extends Employee {
        // Empty by design ...
    }

    private static final String MODEL_KEY_EMPLOYEES = "employees";

    @Autowired
    private EmployerDAO employerDAO;

    private final ObjectMapper objectMapper = new ObjectMapper();

    private final MappingJacksonJsonView view = new MappingJacksonJsonView();

    public EmployeeListController() {
        objectMapper.getSerializationConfig().addMixInAnnotations(Employee.class, EmployeePublicView.class);
        view.setObjectMapper(objectMapper);
        view.setRenderedAttributes(new HashSet(Arrays.asList(MODEL_KEY_EMPLOYEES)));
    }

    @RequestMapping(method = RequestMethod.GET)
    public View handleGet(@RequestParam("employerId") Long employerId, Model model) {
        model.addAttribute(MODEL_KEY_EMPLOYEES, employerDAO.getEmployees(employerId));
        return view;
    }

}

As you see it is very similar to the controller above, the difference is new class EmployeePublicView extending Employee, and defining that benefits property will be ignored while serialization (using @JsonIgnoreProperties annotation). OK, but how this will help us with desired serialization of Employee instances? - the key factor is addMixInAnnotations usage - this method allows us to override the annotations defined on Employee class with those from the EmployeePublicView! Amazing and effective idea which doesn't need any domain entities modifications (you may safely remove the @JsonView annotations from the preview example)

Monday, October 18, 2010

JSON - Jackson to the rescue

Sometimes you have to fetch some data from the server in JavaScript, JSON is pretty good choice for this task.

Let's play with the Employer - Employee - Benefit example from the post JPA Demystified (episode 1) - @OneToMany and @ManyToOne mappings. We will use it inside the web application based on Spring Framework. Our first controller will return the employees list as the response body, in our case MappingJacksonHttpMessageConverter will be used automagically for converting the value returned by handleGet method to the response send to client.

@Controller
@RequestMapping("/employee-list.json")
public class EmployeeListController {
    @Autowired
    private EmployerDAO employerDAO;

    @RequestMapping(method = RequestMethod.GET)
    @ResponseBody
    public List<Employee> handleGet(@RequestParam("employerId") Long employerId) {
        return employerDAO.getEmployees(employerId);
    }
}

When we try to fetch the data for the first time, we encounter beautiful exception: JsonMappingException: Infinite recursion (StackOverflowError) - caused by bi-directional references between the Employer - Employee - Benefit.

Looking for the possible solution, I've found a note Handle bi-directional references using declarative method(s), and after reading it, I've corrected the domain entities in following way:

@Entity
@Table(name = "EMPLOYERS")
public class Employer implements Serializable {
...
    @JsonManagedReference("employer-employee")
    @OneToMany(mappedBy = "employer", cascade = CascadeType.PERSIST)
    public List getEmployees() {
        return employees;
    }
...
}

@Entity
@Table(name = "EMPLOYEES")
public class Employee implements Serializable {
...
    @JsonManagedReference("employee-benefit")
    @OneToMany(mappedBy = "employee", cascade = CascadeType.PERSIST)
    public List getBenefits() {
        return benefits;
    }

    @JsonBackReference("employer-employee")
    @ManyToOne(optional = false)
    @JoinColumn(name = "EMPLOYER_ID")
    public Employer getEmployer() {
        return employer;
    }
...
}

@Entity
@Table(name = "BENEFITS")
public class Benefit implements Serializable {
...
    @JsonBackReference("employee-benefit")
    @ManyToOne(optional = false)
    @JoinColumn(name = "EMPLOYEE_ID")
    public Employee getEmployee() {
        return employee;
    }
...
}

After performing the above changes, I could finally enjoy the JSON response returned by my code:

[{"id":1, "benefits":[{"name":"Healthy Employees", "id":1, "type":"HEALTH_COVERAGE", "startDate":1104534000000, "endDate":null}, {"name":"Gold Autumn","id":2,"type":"RETIREMENT_PLAN","startDate":1104534000000,"endDate":null},{"name":"Always Secured","id":3,"type":"GROUP_TERM_LIFE","startDate":1104534000000,"endDate":null}],"firstName":"John"},{"id":2,"benefits":[],"firstName":"Mary"},{"id":3,"benefits":[],"firstName":"Eugene"}]

And as usual some links for the dessert: