Java Ninja Chronicles By Norris Shelton

Things I learned in the pursuit of code

In a previous blog entry, I wrote about hot to Get the active Springframework profiles. In this one, I had the need to set the profile for a test. Keep in mind, I am not setting which profile the test should be included in, but which profile should be activated when the test runs.

We had the dataSources defined in a local profile and a default profile. In this case, I needed the test to use the local profile. It turned out to be pretty easy. All I had to do was annotate the test class with @ActiveProfiles. The value inside the annotation can contain multiple profiles, separated by commas.

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("local")
public class EventServiceTest {
   //...
}

August 23rd, 2017

Posted In: Spring

Leave a Comment

We had a need to know who was calling various web services. That is fairly easy to do when you have a standard URL. One solution is to simply grep your code repository for the URL (e.g. /my/service/). This becomes much more difficult when there is a path variable involved. An example URL with path variables is

@RequestMapping(value = "/mvc/customer/getState/{account}/more/url", method = RequestMethod.GET)

Lots of times, the URL is composed of multiple calls. A common way that this code will be found is below:

String url = String.format("/mvc/customer/getState/%s/more/url", accountNumber);
return restTemplate.getForObject(url, String.class);

This works, but makes it very difficult to determine who uses this web service call. You can grep for /mvc/customer/getState/ and that will work just fine if there aren’t multiple calls that use that same part of the URL in them. If there are other similar URLs, then effort will have to be expended to determine which are true hits and which are false hits.

There is another way to solve this problem if you are using the Spring’s RestTemplate. The RestTemplate can use the exact same URL pattern that is used by the web service URL pattern. This is accomplished by supplying a Map of data containing the path variable name and it’s corresponding value. An example is below:

Map<String, Object> params = new HashMap<>();
params.put("account", accountNumber);
return restTemplate.getForObject("/mvc/customer/getState/{account}/more/url", String.class, params);

August 5th, 2017

Posted In: Spring, Spring MVC, Spring RestTemplate

Leave a Comment

Spring Boot

Spring Boot is changing the world of Java development with Spring. It is taking away much of the pain that was involved with configuring applications. This is great when you are trying to create what they do by default. They create executable jars by default. What do you have to do if you need to create a WAR file to run on a Tomcat by someone else.

POM file

Let’s start with our project’s pom.xml file. Here we need to define the standard Spring Boot parent starter and also include include the Spring Boot Web starter. The Spring Boot Web starter also includes the Spring Boot Tomcat starter. In our case, we do not want it packaged inside our war because our war file will be deployed on a Tomcat server directly. We don’t have to roll our own. To change this behavior, we include the Spring Boot tomcat starter explicitly and set it’s scope to provided. We also must specify the packaging of our project to be a war.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.javaninja.springboot</groupId>
    <artifactId>springboot-web</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.4.RELEASE</version>
    </parent>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

Java Config

Normally the Java Configuration contains a main method because that is how the program will be launched. In this case, we do not need a main method and instead we need to provide a configure method to go along with the SpringBootServletInitializer that we extend.

package com.javaninja.springboot.web;


import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;


@SpringBootApplication
public class WebApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(WebApplication.class);
    }
}

Example Controller

That is all of the configuration that we need to make this work as a normal Spring MVC controller. To test our functionality, we need a very simple controller, such as the following,.

package com.javaninja.springboot.web;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class ExampleController {

    private Logger log = LoggerFactory.getLogger(getClass());

    @GetMapping("/example/boolean")
    public Boolean exampleBoolean() {
        log.info("Eureka!");
        return true;
    }
}

Test the controller

Let’s create a very simple test using the Spring Boot Test starter. This brings in Junit and MockMvc among other useful APIs.

package com.javaninja.springboot.web;


import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

import static org.assertj.core.api.Assertions.fail;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;


/**
 * @author norris.shelton
 */
@RunWith(SpringRunner.class)
@WebMvcTest(ExampleController.class)
public class TestExampleController {

    @Autowired
    private MockMvc mvc;

    @Test
    public void testExampleBoolean() {
        try {
            mvc.perform(get("/example/boolean")
                            .accept(MediaType.APPLICATION_JSON))
               .andExpect(status().isOk())
               .andExpect(content().string("true"));
        } catch (Exception e) {
            fail(e.toString());
        }
    }
}

The test run perfectly and produces the following logging and a nice pretty green bar.

2017-07-10 18:36:06.218  INFO 7499 --- [           main] c.j.springboot.web.ExampleController     : Eureka!

July 11th, 2017

Posted In: Maven, MockMVC, Spring, Spring Boot, Spring MVC, Test Driven Development, Unit Tests

Tags: , ,

Leave a Comment

Working with Spring Data JPA repositories is easy if you use them the way they are intended to be used. One way that they don’t like to be used is with two different databases with the objects in the same directories. In a previous blog titled Spring Data JPA with multiple entity managers, I showed how to have multiple EntityManagers work with Spring Data JPA. As part of that, we had to annotate each method that used the repository with @Transactional. I didn’t like this and I was searching for a way to make it better.

I tried to filter the jpa:repositories with a regex, but that wouldn’t work.

I next tried filtering by annotation and it worked like a charm. Here is how I did it.

Create annotations

The annotations are very simple and there isn’t Spring specific about them. I created @ReadOnly and @ReadWrite annotations.

package com.javaninja.adw.spring;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/**
 * Annotation used to indicate that this should be picked up as a ReadOnly database operation, specifically for
 * Spring Data JPA repositories.
 * @author norrisshelton
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ReadOnly {

} 
package com.javaninja.adw.spring;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/**
 * Annotation used to indicate that this should be picked up as a ReadWrite database operation, specifically for
 * Spring Data JPA repositories.
 * @author norrisshelton
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ReadWrite {

} 

Annotate the repositories

I annotated the Read-only repository with @ReadOnly and annotated my Read-Write repository with @ReadWrite.

package com.javaninja.adw.example;


import com.javaninja.adw.spring.ReadOnly;

import org.springframework.data.jpa.repository.JpaRepository;


/**
 * Read-only Spring Data JPA Repository for Example objects.
 * @author norrisshelton
 */
@ReadOnly
public interface RoExampleRepository extends JpaRepository<ExampleEntity, Integer> {

    ExampleEntity findByAffiliateId(int affiliateId);
}
package com.javaninja.adw.example;


import com.javaninja.adw.spring.ReadWrite;

import org.springframework.data.jpa.repository.JpaRepository;


/**
 * Read-write Spring Data JPA Repository for Example objects.
 * @author norrisshelton
 */
@ReadWrite
public interface RwExampleRepository extends JpaRepository<ExampleEntity, Long> {

}

Repository declaration

Once I have that, I can move onto the Spring context configuration. I could then modify my jpa:repositories declaration to look like:

<jpa:repositories base-package="com.javaninja.adw"
                  entity-manager-factory-ref="roEntityManagerFactory"
                  transaction-manager-ref="roTransactionManager">
    <repository:include-filter type="annotation" expression="com.javaninja.adw.spring.ReadOnly"/>
</jpa:repositories>
<jpa:repositories base-package="com.javaninja.adw"
                  entity-manager-factory-ref="rwEntityManagerFactory"
                  transaction-manager-ref="rwTransactionManager">
    <repository:include-filter type="annotation" expression="com.javaninja.adw.spring.ReadWrite"/>
</jpa:repositories>

What does it look like when used

Once those changes are done, using it is as easy as any other usage. No more @Transactional annotations.

package com.javaninja.adw.example;


import com.javaninja.adw.ExampleModel;

import org.springframework.stereotype.Service;


/**
 * @author norris.shelton
 */
@Service
public class ExampleService {

    private final RoExampleRepository roExampleRepository;

    public ExampleService(RoExampleRepository roExampleRepository) {
        this.roExampleRepository = roExampleRepository;
    }

    /**
     * Gets an example model object.
     * @return populated example model
     */
    public ExampleModel getExampleModel(int affiliateId) {
        ExampleEntity exampleEntity = roExampleRepository.findByAffiliateId(affiliateId);
        ExampleModel exampleModel = new ExampleModel();
        exampleModel.setExampleProperty(exampleEntity.getName());
        return exampleModel;
    }
}

The rest of the Spring Context

The rest of the Spring Context configuration looks the same. There is two of anything. To prevent confusion, I pre-pended ro or rw to all of my objects.

<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
<util:properties id="jpaProperties">
    <!--<prop key="hibernate.show_sql">false</prop>-->
    <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
</util:properties>
<bean id="rwEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
      p:dataSource-ref="rwAdwDataSource"
      p:packagesToScan="com.javaninja.adw"
      p:persistenceUnitName="rwPersistenceUnit"
      p:jpaVendorAdapter-ref="jpaVendorAdapter"
      p:jpaProperties-ref="jpaProperties"/>
<bean id="roEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
      p:dataSource-ref="roAdwDataSource"
      p:packagesToScan="com.javaninja.adw"
      p:persistenceUnitName="roPersistenceUnit"
      p:jpaVendorAdapter-ref="jpaVendorAdapter"
      p:jpaProperties-ref="jpaProperties"/>
<!--
    Transaction-related configuration
-->
<tx:annotation-driven/>
<bean id="rwTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="rwEntityManagerFactory"/>
    <qualifier value="rw"/>
</bean>
<bean id="roTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="roEntityManagerFactory"/>
    <qualifier value="ro"/>
</bean>

May 3rd, 2017

Posted In: Java, java ninja, Javaninja, Spring, Spring Data, Spring Data JPA

Leave a Comment

We are using -D system parameters to define our connection pool values. They were defined in a Tomcat setenv file in the bin directory.

export CATALINA_OPTS="$CATALINA_OPTS -DPROXY-RO-JDBC=jdbc:mysql://192.168.0.1/javaninja?zeroDateTimeBehavior=convertToNull"
export CATALINA_OPTS="$CATALINA_OPTS -DPROXY-RO--- USER=javaninja"
export CATALINA_OPTS="$CATALINA_OPTS -DPROXY-RO-PASS=javaninja"
export CATALINA_OPTS="$CATALINA_OPTS -DPROXY-RO-INITIAL-SIZE=1"
export CATALINA_OPTS="$CATALINA_OPTS -DPROXY-RO-MIN-IDLE=1"
export CATALINA_OPTS="$CATALINA_OPTS -DPROXY-RO-MAX-IDLE=1"
export CATALINA_OPTS="$CATALINA_OPTS -DPROXY-RO-MAX-TOTAL=15"

The parameters appeared to be read correctly, as evidenced by the Tomcat log.

14-Dec-2016 09:23:41.499 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -DPROXY-RO-JDBC=jdbc:mysql://192.168.0.1/javaninja?zeroDateTimeBehavior=convertToNull
14-Dec-2016 09:23:41.499 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -DPROXY-RO--- USER=javaninja
14-Dec-2016 09:23:41.499 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -DPROXY-RO-PASS=javaninja
14-Dec-2016 09:23:41.499 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -DPROXY-RO-INITIAL-SIZE=1
14-Dec-2016 09:23:41.499 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -DPROXY-RO-MIN-IDLE=1
14-Dec-2016 09:23:41.499 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -DPROXY-RO-MAX-IDLE=1
14-Dec-2016 09:23:41.499 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -DPROXY-RO-MAX-TOTAL=15

This did not work. We would get weird messages about the value not being in range. This was due to one of the values having noAccessToProcedureBodies=true. The JDBC driver expected yes, no, true or false Unfortunately, what it was receiving was true\n. I have no idea where the newline was coming from. I deleted the end of the line and typed the characters myself, but they were still there.

The solution was to trim all of the values of control characters. Apache StringUtils is my preferred tool for that; however, it is a static class and Spring doesn’t like that. To get over that, I instantiated a copy of it.

<bean id="stringUtils" class="org.apache.commons.lang3.StringUtils"/>

Once I had a StringUtils bean, I used it to trim the values by

<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close"
      p:driverClassName="com.mysql.jdbc.Driver"
      p:url="#{stringUtils.trim(systemProperties['PROXY-RO-JDBC'])}"
      p:username="#{stringUtils.trim(systemProperties['PROXY-RO--- USER'])}"
      p:password="#{stringUtils.trim(systemProperties['PROXY-RO-PASS'])}"
      p:initialSize="#{stringUtils.trim(systemProperties['PROXY-RO-INITIAL-SIZE'])}"
      p:maxTotal="#{stringUtils.trim(systemProperties['PROXY-RO-MAX-TOTAL'])}"
      p:maxIdle="#{stringUtils.trim(systemProperties['PROXY-RO-MAX-IDLE'])}"
      p:minIdle="#{stringUtils.trim(systemProperties['PROXY-RO-MIN-IDLE'])}"
      p:testOnBorrow="false"
      p:timeBetweenEvictionRunsMillis="60000"
      p:testWhileIdle="true"/>

December 14th, 2016

Posted In: Java, java ninja, Javaninja, Spring

Leave a Comment

In the previous blog entry titled Turning Spring MVC exceptions into status codes with messages, I mapped exceptions into HTTP status codes.

Test Controller

In this blog we will test those and verify that everything is working correctly. I started with a test controller that I would use to generate the exceptions and the message. I created controller methods that would generate consistent results:

  • ResourceException with an HTTP 400 and a message
  • ResourceException with an HTTP 404 and a message
  • RuntimeException without any developer customization
  • Exception with a message

I wanted to ensure that I had consistent behavior and I was able to pull information from the exception that would be relevant to the client/consumer, but I also wanted to ensure that I never returned a stacktrace to the outside world.

package com.javaninja.cam.spring;


import com.javaninja.cam.dto.Prospect;
import com.javaninja.cam.exception.ResourceException;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class TestController {

    @RequestMapping(value = "/test/resourceException400")
    public Prospect getResourceException400() {
        throw new ResourceException(HttpStatus.BAD_REQUEST, "Test Bad Request Exception message");
    }

    @RequestMapping(value = "/test/resourceException404")
    public Prospect getResourceException404() {
        throw new ResourceException(HttpStatus.NOT_FOUND, "Test Not Found Exception message");
    }

    @RequestMapping(value = "/test/runtimeException")
    public int getRuntimeException() {
        return Integer.parseInt("x");
    }

    @RequestMapping(value = "/test/exception")
    public int getException() throws Exception {
        throw new Exception("Test Exception message");
    }
}

Junit Test Class

Once that was written, it was fairly easy to test the results. I used MockMVC with Spring Test to implement my test class. As part of this test, I wanted to ensure that the custom ResourceException that I created was handled correctly. I also wanted to ensure that I could handle RuntimeExceptions that happened during regular program execution could be handled. The last thing I wanted to verify was that developer created and thrown exceptions could be handled and that the message that they were created with was outputted correctly. I checked the HTTP status and the content for each type of exception.

package com.javaninja.cam.spring;


import com.javaninja.cam.JunitTestUtility;

import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import static org.junit.Assert.fail;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;


/**
 * @author norris.shelton
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-test.xml")
@WebAppConfiguration
public class TestCamControllerAdvice {

    @Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

    /**
     * Needed because we have some legacy code that intereactes directly with the context.  This is NOT normal and 
     * will be removed as the project is modernized. 
     * @throws Exception
     */
    @BeforeClass
    public static void createMockContext() throws Exception {
        JunitTestUtility.setup();
    }

    @Before
    public void setup() {
        mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
    }

    /**
     * Tests the custom ResourceException and verifies that it returns a HTTP 400 with the expected message.
     */
    @Test
    public void testResourceException400() {
        try {
            mockMvc.perform(get("/test/resourceException400"))
                   .andExpect(status().isBadRequest())
                   .andExpect(content().string("Test Bad Request Exception message"))
                   .andDo(print());
        } catch (Exception e) {
            fail(e.toString());
        }
    }

    /**
     * Tests the custom ResourceException and verifies that it returns a HTTP 404 with the expected message.
     */
    @Test
    public void testResourceException404() {
        try {
            mockMvc.perform(get("/test/resourceException404"))
                   .andExpect(status().isNotFound())
                   .andExpect(content().string("Test Not Found Exception message"))
                   .andDo(print());
        } catch (Exception e) {
            fail(e.toString());
        }
    }

    /**
     * Tests that a RuntimeException is received and that it returns the expected message.
     */
    @Test
    public void testRuntimeException() {
        try {
            mockMvc.perform(get("/test/runtimeException"))
                   .andExpect(status().isInternalServerError())
                   .andExpect(content().string("java.lang.NumberFormatException: For input string: \"x\""))
                   .andDo(print());
        } catch (Exception e) {
            fail(e.toString());
        }
    }

    /**
     * Tests that an Exception is received and that it returns the expected message.
     */
    @Test
    public void testException() {
        try {
            mockMvc.perform(get("/test/exception"))
                   .andExpect(status().isInternalServerError())
                   .andExpect(content().string("Test Exception message"))
                   .andDo(print());
        } catch (Exception e) {
            fail(e.toString());
        }
    }
}

MockMVC Print Output

For readability, I also displayed the full MockMVC print output. The output makes it very clear that I received the anticipated information and nothing else. The example output is below:

com.javaninja.cam.spring.TestCamControllerAdvice

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /test/exception
       Parameters = {}
          Headers = {}

Handler:
             Type = com.javaninja.cam.spring.TestController
           Method = public int com.twinspires.cam.spring.TestController.getException() throws java.lang.Exception

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = java.lang.Exception

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 500
    Error message = null
          Headers = {Content-Type=, Content-Length=[22]}
     Content type = text/plain;charset=ISO-8859-1
             Body = Test Exception message
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /test/resourceException400
       Parameters = {}
          Headers = {}

Handler:
             Type = com.javaninja.cam.spring.TestController
           Method = public com.javaninja.cam.dto.Prospect com.javaninja.cam.spring.TestController.getResourceException400()

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = com.javaninja.cam.exception.ResourceException

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 400
    Error message = null
          Headers = {Content-Type=, Content-Length=[34]}
     Content type = text/plain;charset=ISO-8859-1
             Body = Test Bad Request Exception message
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /test/resourceException404
       Parameters = {}
          Headers = {}

Handler:
             Type = com.javaninja.cam.spring.TestController
           Method = public com.javaninja.cam.dto.Prospect com.javaninja.cam.spring.TestController.getResourceException404()

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = com.javaninja.cam.exception.ResourceException

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 404
    Error message = null
          Headers = {Content-Type=, Content-Length=[32]}
     Content type = text/plain;charset=ISO-8859-1
             Body = Test Not Found Exception message
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /test/runtimeException
       Parameters = {}
          Headers = {}

Handler:
             Type = com.javaninja.cam.spring.TestController
           Method = public int com.javaninja.cam.spring.TestController.getRuntimeException()

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = java.lang.NumberFormatException

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 500
    Error message = null
          Headers = {Content-Type=, Content-Length=[54]}
     Content type = text/plain;charset=ISO-8859-1
             Body = java.lang.NumberFormatException: For input string: "x"
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

Process finished with exit code 0

There you have it. A full Junit/MockMVC test harness that can be used to determine if a SpringMVC controller is returning the correct information when you are trying to map Exceptions into HTTP status codes, along with messages that can be returned with the client consumer.

November 16th, 2016

Posted In: Java, java ninja, Javaninja, JUnit, MockMVC, Spring, Spring MVC, Test Driven Development

Leave a Comment

In the original blog entry, Throwing exceptions with messages from a SpringMVC controller I set up a system to allow exceptions that would be thrown to cause an HTTP status code to be sent to the consumer with a message.

I needed to expand upon that to handle all of the exceptions that my Spring MVC controllers could encounter. To accomplish that, I created a class and annotated it with @ControllerAdvice. This allowed me to create a ExceptionHandlers for all of my controllers in one place.

I created three mappings because I wanted to handle the three types of exceptions a little differently than the others.

  • ResourceException – allows me to set a HTTP status and a message
  • RuntimeException – these are not typically created by developers I need to grab all of the information that I can. That is why I used the toString. That contains the name of the exception and the system specified message.
  • Exception – these are checked exceptions and are created by developers within their code. The expectation is that they put a meaningful message in the message property.

This was fairly easy to accomplish by having three different exception mappings. Within each exception mapping, I set the values in the ResponseEntity to display the appropriate HTTP status with a message in the content.

package com.javaninja.cam.spring;


import com.javaninja.cam.exception.ResourceException;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;


/**
 * Exception handler advice class for all SpringMVC controllers.
 * @author norrisshelton
 * @see ControllerAdvice
 */
@ControllerAdvice
public class CamControllerAdvice {

    /**
     * Returns whatever HTTP status was set within the ResourceException.  Uses the message that was set when
     * the ResourceException was created.
     * @param e SpringMVC controller exception.
     * @return http response entity
     * @see ExceptionHandler
     */
    @ExceptionHandler(ResourceException.class)
    public ResponseEntity handleResourceException(ResourceException e) {
        return ResponseEntity.status(e.getHttpStatus()).body(e.getMessage());
    }

    /**
     * Sets the HTTP status as INTERNAL_SERVER_ERROR (500).  Uses the toString of the exception because
     * RuntimeExceptions don't always have enough usable information in the message property.
     * @param e SpringMVC controller exception.
     * @return http response entity
     * @see ExceptionHandler
     */
    @ExceptionHandler(RuntimeException.class)
    public ResponseEntity handleRuntimeException(RuntimeException e) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.toString());
    }

    /**
     * Sets the HTTP status as INTERNAL_SERVER_ERROR (500).  Uses the message property under the assumption that the
     * developer that created the exception set a meaningful explanation in the message property.
     * @param e SpringMVC controller exception.
     * @return http response entity
     * @see ExceptionHandler
     */
    @ExceptionHandler(Exception.class)
    public ResponseEntity handleException(Exception e) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
    }
}

November 16th, 2016

Posted In: Java, java ninja, Javaninja, Spring, Spring MVC

One Comment

The SpringFramework has a RestTemplate object that can be used to HTTP-based network calls. It doesn’t timeout by default, but there is functionality that can be configured. A RequestFactory must be created, then it needs to be wired into the RestTemplate.

The readTimeout and the connectionTimeout are both expressed in milliseconds.

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd>
 
    <bean id="requestFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory"
          p:readTimeout="250"
          p:connectTimeout="250"/>
 
    <bean id="restTemplate" class="org.springframework.web.client.RestTemplate"
          c:requestFactory-ref="requestFactory"/>
</beans>

Once you have the RequestFactory configured, then the RestTemplate will begin to throw SocketTimeoutException and ConnectTimeoutException, depending on the problem. This is normally handled by catching RestClientException. This RuntimeException wraps all exceptions that are throws by the RestTemplate.

String response = null;
try {
    response = restTemplate.getForObject(url, String.class);
} catch (RestClientException e) {
    createOrderResponse.setStatus("failure");
    logger.error("Unable to get the PayNearMe barcode URL", e);
    //FIXME do something with the exception
    //throw e;
}

Catching the RestClientException is usually enough, because you only want to know that there is a problem. However, if you need to know the specific problem, you can test the RootCause for the specific type of exception.

String response = null;
try {
    response = restTemplate.getForObject(url, String.class);
} catch (RestClientException e) {
    createOrderResponse.setStatus("failure");
    if (e.getRootCause() instanceof SocketTimeoutException) {
        logger.error("SocketTimeoutException", e);
    } else if (e.getRootCause() instanceof ConnectTimeoutException) {
        logger.error("ConnectTimeoutException", e);
    } else {
        logger.error("Some other exception", e);
    }
    //FIXME do something with the exception
    //throw e;
}

September 13th, 2016

Posted In: Java, java ninja, Javaninja, Spring

Leave a Comment

I like to use SpringMVC for my JSON controllers. I do not prefer to return HTTP status codes other than 200, but sometimes you don’t have a choice. I was working on a project where the service would return the requested resource when it is available. If the resource is not found, then it is supposed to return an HTTP status of 404 with a messages. I thought this would be included right out of the box, but it wasn’t.

What Spring MVC offers and why it didn’t work

With Spring MVC, you have the ability to define an exception and have that exception return a specified HTTP status code when it reaches the controllers. Here is what an exception class would look like:

package com.twinspires.brisdataapi.bdsserver.exceptions;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

/**
 * @author norris.shelton
 */
@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class NotFoundException  extends RuntimeException {
    /**
     * Constructs a new runtime exception with the specified detail message.
     * The cause is not initialized, and may subsequently be initialized by a
     * call to {@link #initCause}.
     * @param message the detail message. The detail message is saved for later retrieval by the {@link #getMessage()}
     *                method.
     */
    public NotFoundException(String message) {
        super(message);
    }
}

This does provide a way to specify a message, but it doesn’t get displayed when a message is returned by the controllers. Ugh.

This would provide a good start, but I would need an exception handler to get the message. Unfortunately, all of the examples of the exception handlers show a method per exception.

Doing the least to make it work

This details the changes that I needed to make to allow the service to function correctly. I wanted to create as few classes as possible.

Define an exception

I created an exception that extends RuntimeException. I didn’t add a @ResponseStatus because I didn’t want to have to make an exception for each status code. I created a constructor that takes an HTTP status code and a message. This allows me to have one exception that I can reuse in all of my controllers and always return the correct status and message.

package com.twinspires.brisdataapi.bdsserver.exceptions;

import org.springframework.http.HttpStatus;

/**
 * @author norris.shelton
 */
@SuppressWarnings("ClassWithoutNoArgConstructor")
public class BdsServiceException extends RuntimeException {

    private HttpStatus httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;

    public HttpStatus getHttpStatus() {
        return httpStatus;
    }

    /**
     * Constructs a new runtime exception with the specified detail message.
     * The cause is not initialized, and may subsequently be initialized by a
     * call to {@link #initCause}.
     * @param message the detail message. The detail message is saved for later retrieval by the {@link #getMessage()}
     *                method.
     */
    public BdsServiceException(HttpStatus httpStatus, String message) {
        super(message);
        this.httpStatus = httpStatus;
    }
}

Define SpringMVC exception handler

Now that I have an exception that has all of the information that I want returned to the caller of my service, I need to define an exception handler. It is the same type of exception handler that you normally see, except it returns a ResponseEntity. With the ResponseEntity, I can return the retrieve the correct status code and message from the exception and return them to the caller.

package com.twinspires.brisdataapi.bdsserver.spring;

import com.twinspires.brisdataapi.bdsserver.exceptions.BdsServiceException;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class ExceptionHandlerAdvice { 
 
    @ExceptionHandler(BdsServiceException.class)
    public ResponseEntity handleException(BdsServiceException e) {
        // log exception 
        return ResponseEntity.status(e.getHttpStatus()).body(e.getMessage());
    }         
} 

Putting it to use

All that is left is throwing the exception. I threw the exception with the desired HTTP status code and the message.

            throw new ResourceException(HttpStatus.NOT_FOUND, "We were unable to find the specified resource.");

June 22nd, 2016

Posted In: Java, java ninja, Javaninja, Spring, Spring MVC

Leave a Comment

Accessing properties via Spring is very easy. To read a properties file is very easy. This reads the given properties file from the file system and places the values in a map named rabbitConfiguration. It takes advantage of SpEl to get a system property and use that to resolve the file name.

<util:properties id="rabbitConfiguration" location="file:#{systemProperties.APP_CONFIG}/funding.properties"/>

My problems started when I tried to use the values from the properties file that contained periods. I tried to use them like:

    <bean id="rabbitConnectionFactory" class="org.springframework.amqp.rabbit.connection.CachingConnectionFactory"
          c:hostname="#{rabbitConfiguration.vipre.host}"
          c:port="#{rabbitConfiguration.vipre.port}"
          p:username="#{rabbitConfiguration.vipre.user}"
          p:password="#{rabbitConfiguration.vipre.password}"/>

Spring did not like it. It thought that vipre was my property and host was something to be accessed off of it like an object. This is the exception that was thrown.

Caused by: org.springframework.beans.factory.BeanExpressionException: Expression parsing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 20): Property or field 'vipre' cannot be found on object of type 'java.util.Properties' - maybe not public?
	at org.springframework.context.expression.StandardBeanExpressionResolver.evaluate(StandardBeanExpressionResolver.java:164)
	at org.springframework.beans.factory.support.AbstractBeanFactory.evaluateBeanDefinitionString(AbstractBeanFactory.java:1365)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.doEvaluate(BeanDefinitionValueResolver.java:255)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.evaluate(BeanDefinitionValueResolver.java:228)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:204)
	at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:648)
	at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:140)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1137)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1040)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351)
	... 109 common frames omitted
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 20): Property or field 'vipre' cannot be found on object of type 'java.util.Properties' - maybe not public?
	at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:224)
	at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:94)
	at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:81)
	at org.springframework.expression.spel.ast.CompoundExpression.getValueRef(CompoundExpression.java:57)
	at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:87)
	at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:120)
	at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:242)
	at org.springframework.context.expression.StandardBeanExpressionResolver.evaluate(StandardBeanExpressionResolver.java:161)
	... 124 common frames omitted

I searched and searched around the internet trying to find a way to work around. I tried single-quotes, back-slashes, double-quotes, double-quotes and single-quotes together. Nothing seemed to work, then it hit me. To get around this, I approached the properties access via the array/bracket syntax (#{rabbitConfiguration[‘vipre.port’]}

    <bean id="rabbitConnectionFactory" class="org.springframework.amqp.rabbit.connection.CachingConnectionFactory"
          c:hostname="#{rabbitConfiguration['vipre.host']}"
          c:port="#{rabbitConfiguration['vipre.port']}"
          p:username="#{rabbitConfiguration['vipre.user']}"
          p:password="#{rabbitConfiguration['vipre.password']}"/>

May 31st, 2016

Posted In: Java, java ninja, Javaninja, SpEl, Spring

Leave a Comment

Next Page »
LinkedIn Auto Publish Powered By : XYZScripts.com