Java Ninja Chronicles By Norris Shelton

Things I learned in the pursuit of code

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&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

WP to LinkedIn Auto Publish Powered By : XYZScripts.com