Java Ninja Chronicles By Norris Shelton

Things I learned in the pursuit of code

Spring RestTemplate has been the mainstay of most Java back-end projects. Some of the background material for using RestTemplate can be found here Using UriBuilder and Using Spring RestTemplate with path parameters. Spring RestTemplate isn’t gone, but the writing is on the wall. It’s time to get up to speed on WebClient, even if you aren’t being Reactive.

Spring RestTemplate has been the mainstay of most Java back-end projects. http://javaninja.net/2019/02/using-uribuilder/Spring RestTemplate isn’t gone, but the writing is on the wall. It’s time to get up to speed on WebClient, even if you aren’t being Reactive.

Maven Dependencies

Add the following Maven dependencies to your project.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
    <groupId>org.projectreactor</groupId>
    <artifactId>reactor-spring</artifactId>
    <version>1.0.1.RELEASE</version>
</dependency>

GET with static URL

Your RestTemplate call would have looked something like the following:

ConfigurationListModel configurationListModel = 
    restTemplate.getForObject(configurationServiceUrl + "/app/some/url", 
                              ConfigurationListModel.class);

The pertinent parts of that code are the static URL and the object that the response will be parsed into.

The WebcClient code is going to be a little more verbose, but it is simple enough.

ConfigurationListModel configurationListModel =
    WebClient.create(configurationServiceUrl)
             .get()
             .uri("/app/some/url")
             .retrieve()
             .bodyToMono(ConfigurationListModel.class)
             .block();
  • create – creates a WebClient with the specified base (host) URL. Scheme + host in this case.
  • get – prepares this request to be a GET request.
  • uri – the desired url. A static path in this case.
  • retrieve – performs the specified HTTP request against the specified resource.
  • bodyToMono – extracts the response body to a mono. A mono of my custom response object in this case.
  • block – wait till the requested HTTP resource responds (e.g. perform a synchronous call).

Get with Query Parameters

A typical RestTemplate get with request parameters is below. I use UriComponentsBuilder to build the URI.

URI uri = UriComponentsBuilder.fromUriString(configurationServiceUrl)
                              .path("/app/configuration/list")
                              .queryParam("param", param)
                              .build(true)
                              .toUri();
ConfigurationListModel configurationListModel = 
    restTemplate.getForObject(uri, ConfigurationListModel.class);

There are two different way that query parameters can be handled. The first way is to use parameter substitution.

ConfigurationListModel configurationListModel =
    WebClient.create(configurationServiceUrl)
             .get()
             .uri("/app/some/url?param={param}", paramValue)
             .retrieve()
             .bodyToMono(ConfigurationListModel.class)
             .block();

The second implementation takes advantage of the builder to create the URI.

ConfigurationListModel configurationListModel =
    WebClient.create(configurationServiceUrl)
             .get()
             .uri(builder -> builder.path("/app/some/url")
                                    .queryParam("param", param)
                                    .build())
             .retrieve()
             .bodyToMono(ConfigurationListModel.class)
             .block();

GET with a PATH variable

Let’s consider an example where the URL contains data. That data is commonly referred to as a PATH variable. I generally used the UriComponentsBuilder when it came to composing a URL. This moves the extra bit of complexity out of the RestTemplate call.

URI uri = UriComponentsBuilder.fromUriString(configurationServiceUrl)
                              .path("/app/configuration/{stackId}/list")
                              .buildAndExpand(stackId)
                              .encode()
                              .toUri();
ConfigurationListModel configurationListModel = 
    restTemplate.getForObject(uri, ConfigurationListModel.class);

The conversion to WebClient is very similar to the static URL call. The only difference is in the uri method call.

ConfigurationListModel configurationListModel =
    WebClient.create(configurationServiceUrl)
             .get()
             .uri("/app/configuration/{stackId}/list", stackId)
             .retrieve()
             .bodyToMono(ConfigurationListModel.class)
             .block();

The uri method now takes an additional value. It is substituted in the specified path parameter. The path parameter value is specified by {}, like it is for UriComponentsBuilder.

POST with a body

Building on top of the examples that we have already is the need to perform a POST. Here is what a typical RestTemplate POST will look like.

ConfigurationValueModel request = new ConfigurationValueModel();
request.setAffiliateId(affiliateId);
request.setStackId(stackId);
request.setKey(key);

ConfigurationValueModel configurationValueModel = 
    restTemplate.postForObject(configurationServiceUrl + "/app/some/url", 
                               request, 
                               ConfigurationValueModel.class);

I built the contents of the body in an object that has all of the properties that I need. That part of the solution will stay the same.

ConfigurationValueModel request = new ConfigurationValueModel();
request.setAffiliateId(affiliateId);
request.setStackId(stackId);
request.setKey(key);

ConfigurationValueModel configurationValueModel = WebClient.create(configurationServiceUrl)
         .post()
         .uri("/app/configuration/value/get")
         .body(BodyInserters.fromObject(request))
         .retrieve()
         .bodyToMono(ConfigurationValueModel.class)
         .block();

The post method is specified instead of the get method. The next big change is the inclusion of the body method. The body method needs a body inserter. In this case, I use an inserter that inserts the body from a specified object. I specify my previously used object.

With this foundation, it should be very easy to build out the replacements for the rest of your Spring RestTemplate calls as you migrate to the new WebClient.

April 27th, 2019

Posted In: Javaninja

Leave a Comment

We had several different ways to specify URLs that were used to call other services. This caused confusion when you were searching for what consumers existed for a particular service endpoint. One of our developers introduced us to UriBuilder and it was adopted. A simple example of UriBuilder usage is

URI myServiceUri = UriBuilder.fromPath(myServiceUrl)
                             .path("/path")
                             .build()
                             .toUri();

This will create a URI object which is directly usable by Spring’s RestTemplate.

  • .build(), .build(false) – builds the UriComponents object, but does not encode the values.
  • .build(true) – builds the UriComponents object and encodes the values.

UriBuilder also supports path variables and uses the same notation that Spring MVC uses for it’s controller mappings. In this example, we have a path variable that is specified with a placeholder and it’s encoded value is used to replace the placeholder.

URI myServiceUri = UriBuilder.fromPath(myServiceUrl)
                             .path("/path/{pathVariable}")
                             .buildAndExpand(pathVariable)
                             .encode()
                             .toUri();

Things just got interesting. If you have a value that you need substituted, then you need to call several methods.

  • .buildAndExpand() will allow you to expand data in the order that they were specified.
  • .encode() is needed to encode the data because .buildAndExpand() calls .build(false). .encode() optionally accepts encoding rulesl
  • toUri() to converts the return of encode() to an URI object.

If you specify multiple path variables and their values, they will be substituted in the order provided, as you would expect.

You can even specify query parameters with the following notation.

URI myServiceUri = UriBuilder.fromPath(myServiceUrl)
                             .path("/path/")
                             .queryParam("param1", param1)
                             .queryParam("param2", param2)
                             .build(true)
                             .toUri();

While, multiple values for the same request parameter isn’t common, it is supported by UriBuilder by simply specifying multiple values like so

URI myServiceUri = UriBuilder.fromPath(myServiceUrl)
                             .path("/path/")
                             .queryParam("param1", param1value1, param1value2)
                             .queryParam("param2", param2)
                             .build(true)
                             .toUri();

This will cause multiple parameters to be specified on the URL, each with it’s own value, like

param1=abc&amp;param1=xyz

There are several UrlBuilder classes available in Java. We settled on javax.ws.rs.core because it is generally available no whatever what APIs you happen to be using in your project.

Along the way, we also came up with some standards for usage that go above and beyond what UriBuilder requires.

fromPath – We standardized on using the name of the application and Url as a suffix for the name of the variable containing the server that we are calling. This made it easy to find all calls to a particular system.

path – We standardized on using the same path value that we use in our Spring MVC controller. This made it easy for us to find the calls for any particular controller endpoint. As part of this, we also did away with using multiple Spring MVC mappings to create one mapping (e.g. annotating the top of a class and having that appended onto each method’s mapping). This created a bit of redundancy, but paid off dividends whenever we needed to find the clients of a service.

February 5th, 2019

Posted In: Javaninja

Tags: , , , , ,

Leave a Comment

We like to use Apache Commons Lang to convert our Objects to a String for easy logging of our application state. Our usual way of doing this is to specify the Objects toString method as.

public String toString() {
    return ReflectionToStringBuilder.toString(this);
}

This works great for us. It isn’t a hard-coded String conversion and will pick up new properties as the bean is maintained.

However, this method is not aware of any fields that may have sensitive content, such as passwords. To prevent sensitive fields from being included in the toString conversion, there are 2 different ways that this can be prevented.

The first way to prevent sensitive information from being included in the toString output is to annotate the individual property, such as

@ToStringExclude
private String password;

Another method for preventing sensitive Object fields from being included in the toString is to specify exclude fields by

public String toString() {
    return ReflectionToStringBuilder.toStringExclude(this, password);
}

Both of these work equally as well to prevent the sensitive information from being included in the toString output.

February 5th, 2019

Posted In: Javaninja

Tags: , , , ,

Leave a Comment

Tomcat access logs are not enabled in Spring Boot by default. The access logs can be a very useful troubleshooting tool. The logs can be enabled by adding a property to the application.properties in the src/main/resources directory.

# Enable access log.
server.tomcat.accesslog.enabled=true

This will enable Tomcat Access Logging. The logs will go to the current temporary directory where the existing Tomcat work directory is located. The logs will appear under a directory named logs in a file that follows the normal Tomcat Access logs, such as access_log.2019-02-04.log.

It is a good idea to specify the directory that you want to contain the Tomcat logs, etc instead of relying on them being sent to a temporary directory. You can specify the Tomcat Basedir by adding the following to the application.properties.

# Tomcat base directory, which will be at the same level as the 
# Spring Boot jar. If not specified, a temporary directory
# is used.
server.tomcat.basedir=tomcat

The directory with the specified name will be created at the same directory level as the .jar that contains the Spring Boot application. If you are running the application as part of your IDE, then the specified directory will appear in the root of your source code.

An alternative way to specify the properties is to specify them as JVM parameters. An example of both of these would be

-Dserver.tomcat.basedir=tomcat -Dserver.tomcat.accesslog.enabled=true

Tomcat Access Logs can be easily enabled in a Spring Boot application by setting the appropriate property. This allows easy troubleshooting and if you set the Tomcat basedir, you can also access Tomcat’s work directory.

Additional information about configuring Spring Boot Tomcat can be found at https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-configure-accesslogs

February 5th, 2019

Posted In: Javaninja

Tags: , , , ,

Leave a Comment

We were troubleshooting some troubling problems when we needed to see what was going on inside the MySql driver. This isn’t a standard thing, so what to do.

We were using SLF4J for our existing logging so we chose that path.

First we included the SLF4J Log4J bridge by adding the following to our pom.xml.

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>log4j-over-slf4j</artifactId>
    <version>${slf4j.version}</version>
</dependency>

Then we had to modify the URL property for our datasource by adding

&logger=com.mysql.jdbc.log.Slf4JLogger&profileSQL=true

to the end of our URL property. There is one caveat. The ampersand needs to be escaped since it is part of XML. Also, we already had some MySql driver settings, so we needed the ampersand instead of the question mark.

<bean id="settingsDataSource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close"
      p:driverClassName="com.mysql.jdbc.Driver"
      p:url="jdbc:mysql://my.server.com:3306/mycontext?zeroDateTimeBehavior=convertToNull&amp;logger=com.mysql.jdbc.log.Slf4JLogger&amp;profileSQL=true"
      p:username="nunnya"
      p:password="bidness"
      p:defaultAutoCommit="false"
      p:maxWait="3000"
      p:testOnBorrow="true"
      p:testWhileIdle="true"
      p:minEvictableIdleTimeMillis="30000"
      p:timeBetweenEvictionRunsMillis="60000"
      p:removeAbandoned="true"
      p:suspectTimeout="3"
      p:removeAbandonedTimeout="5"
      p:logAbandoned="true"
      p:validationQuery="select now()"
      p:logValidationErrors="true"
      p:initialSize="2"
      p:maxActive="2"
      p:minIdle="2"
      p:maxIdle="2"/>

February 2nd, 2018

Posted In: Java, java ninja, Javaninja, log4j-over-slf4j, Logging, Logging configuration, MySql

Leave a Comment

In a previous blog, I showed how to use JPA to read and write to a database with JPA. Spring Batch – reading and writing JPA. We prefer to use Spring Data Repositories instead of using the JPA directly. Thankfully, there is a way to use a Spring Data Repository directly with Spring Batch.

RepositoryItemWriter

This is how a RepositoryItemWriter is declared. It follows the normal ItemWriter pattern. It needs a Spring Data Repository and to know what method should be called on the repository, save in this case.

@Bean
public RepositoryItemWriter<WagerActivity> writer() {
    RepositoryItemWriter<WagerActivity> writer = new RepositoryItemWriter<>();
    writer.setRepository(wagerActivityRepository);
    writer.setMethodName("save");
    return writer;
}

Spring Batch 4 has the concept of Builders. This is an example of what the Builder for this repository should look like:

return new RepositoryItemWriterBuilder<WagerActivity>()
                .methodName("save").repository(wagerActivityRepository).build();

Repository Declaration

A repository is an interface that surrounds an Entity. My interface is as follows:

public interface WagerActivityRepository extends JpaRepository<WagerActivity, Integer> {
}

Save Method

I don’t like hard-coded Strings, so I figured out how to get the save method name from Spring Data. The first thing I had to do was get the RepositoryMetadata. I created a DefaultRepositoryMetadata with my repository to instantiate the object. I then instantiated a DefaultCrudMethods with the repository metadata. Once I had that, I could get the save method and the name that should be used to access it. I removed the need for a hard-coded String, but I don’t think it is worth the effort. Too bad there isn’t a Enum.

@Bean
public RepositoryMetadata repositoryMetadata() {
    return new DefaultRepositoryMetadata(WagerActivityRepository.class);
}
@Bean
public RepositoryItemWriter<WagerActivity> writer() {
    DefaultCrudMethods defaultCrudMethods = new DefaultCrudMethods(repositoryMetadata());
    RepositoryItemWriter<WagerActivity> writer = new RepositoryItemWriter<>();
    writer.setRepository(wagerActivityRepository);
    writer.setMethodName(defaultCrudMethods.getSaveMethod().getName());
    return writer;
}

December 7th, 2017

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

Leave a Comment

How do you set the private member in another class? I was working on a Junit test for a class that isn’t usually wired into my Spring context. Since the class wasn’t being constructed by Spring for the test, I didn’t have the advantage of autowiring.

@Autowired
private CoreServiceBean coreServiceBean;

@Autowired
private EzMoneyServiceBean ezMoneyServiceBean;

Apache Commons BeanUtils didn’t work

I tried using Apache Commons BeanUtils to set the private property, but there is a silent return statement if it is truly private member.

try {
    descriptor =
        getPropertyUtils().getPropertyDescriptor(target, name);
    if (descriptor == null) {
        return; // Skip this property setter
    }
} catch (NoSuchMethodException e) {
    return; // Skip this property setter
}

Java Reflection

I next tried the Java Reflection API. It seems a little clunky, but it did the job without too much work. I performed the following steps:

  • I looked up the private field by name.
  • I set the field as accessible.
  • I set the new value of the field.

Here is what it looks like for one of the fields:

Field coreServiceBeanField = EzMoneyResourceBean.class.getDeclaredField("coreServiceBean");
coreServiceBeanField.setAccessible(true);
coreServiceBeanField.set(ezMoneyResourceBean, coreServiceBean);

November 14th, 2017

Posted In: Java, java ninja, Javaninja

Tags:

Leave a Comment

Generating Java classes from an XSD is a common use case. I am partial to the Highsource (e.g. jvnet) maven-jaxb2-plugin. This plugin is very easy to use. Add the following to your pom.xml.

<build>
    <plugins>
        <plugin>
            <groupId>org.jvnet.jaxb2.maven2</groupId>
            <artifactId>maven-jaxb2-plugin</artifactId>
            <version>0.13.2</version>
            <executions>
                <execution>
                    <id>generate</id>
                    <goals>
                        <goal>generate</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

By default, the plugin will compile any xsd files located in src/main/resources. They will be generated in target/generated-sources/xjc/generated.

Generated Classes

By default, the generated classes will be in the generated package. To customize this value, include an XJB file in the same directory as the target XSD. I prefer to do one XJB for each XSD like the following.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxb:bindings
        version="2.1"
        xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
        xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <jaxb:bindings schemaLocation="a.xsd" node="//xs:schema">
        <jaxb:schemaBindings>
            <jaxb:package name="org.ab.a"/>
        </jaxb:schemaBindings>
    </jaxb:bindings>
</jaxb:bindings>

September 12th, 2017

Posted In: Javaninja

Leave a Comment

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

In a previous blog, I talked about Testing Springframework MVC Rest controllers with MockMVC. What I didn’t know is that you can use the MockMVC framework to also interrogate the Request object.

In this case, we have an Interceptor that is modifying the request by modifying an object’s property and adding that object to the request as a request attribute. To test this, we had to be able to see the value of the request attribute object after the request is done. Luckily MockMVC provides us the ability to do just that.

To accomplish this, I had to utilize the RequestResultMatchers via MockMvcResultMatchers.request() method to get a reference to the request object. Once I had the request object, I was able to get the object being stored as a request attribute by calling the attribute() method . Once I had the object, I was able to access it’s properties by calling hasProperty on it. From there on, I was able to use matchers that I was used to using.

    @Test
    public void testExtractStateFromCookie() {

        try {
            mockMvc.perform(get("/legacy/tote/currentrace")
                                .param("param1", "value1")
                                .param("param2", "value2")
                                .param("param3", "value3")
                                .cookie(new Cookie("STATE", "kY")))
                   .andExpect(request().attribute("USER_INFO", hasProperty("state", equalToIgnoringCase("ky"))));
        } catch (Exception e) {
            fail(e.toString());
        }
    }

Along the way, I did use some new Matchers. They are:

  • org.hamcrest.text.IsEqualIgnoringCase.equalToIgnoringCase() – This provides functionality similar to is(), but ignores the case of the text.
  • org.hamcrest.core.IsNull.nullValue – This allows for easy comparison to null
  • IsEqualIgnoringWhiteSpace.equalToIgnoringWhiteSpace() – All leading and trailing whitespace is ignored. Any duplicate white spaces within the string are considered single spaces.
  • IsEmptyString.isEmptyOrNullString() – compares against empty string or null (e.g. StringUtils.isBlank()).

August 15th, 2017

Posted In: hamcrest, MockMVC

Leave a Comment

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