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

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

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

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