Category Archives: Java

Using Gmail as SMTP server from Java, Spring Boot apps

Gmail users can use Gmail’s SMTP server smtp.gmail.com to send emails from their Spring Boot apps. For this let us do some setup in the app:

  1. Provide SMTP connection properties in the application.properties file:
    spring.mail.host=smtp.gmail.com
    spring.mail.username=<your gmail/google app email>
    spring.mail.password=*****
    spring.mail.port=587
    spring.mail.properties.mail.smtp.starttls.enable=true
    spring.mail.properties.mail.smtp.auth=true
    spring.mail.properties.mail.smtp.starttls.required=true
  2. Use Spring Boot Email tools library – which is a wrapper over Spring Boot Email starter library.  Add the following in your pom.xml:
    <dependency>
        <groupId>it.ozimov</groupId>
        <artifactId>spring-boot-email-core</artifactId>
        <version>0.6.3</version>
    </dependency>
  3. Annotation your application’s main class (i.e class annotated with @SpringBootApplication) with @EnableEmailTools:
    @SpringBootApplication
    @EnableEmailTools
    public class EmailApplication {
        public static void main(String[] args){
            SpringApplication.run(EmailApplication.class, args);
        }
    }
  4. Let’s write a test which uses it.ozimov.springboot.mail.service.EmailService bean to send an email:
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class EmailServiceTest {
        @Autowired 
        it.ozimov.springboot.mail.service.EmailService emailService; 
    
        @Value("${spring.mail.username}") String fromEmail; 
        @Test 
        public void testSendEmail() throws UnsupportedEncodingException { 
            User user = new User(); 
            user.setEmail("sanaulla123@gmail.com"); 
            user.setDisplayName("Mohamed Sanaulla"); 
            final Email email = DefaultEmail.builder() 
                .from(new InternetAddress(fromEmail, "From Name"))
                .to(Lists.newArrayList(new InternetAddress(
                    user.getEmail(), user.getDisplayName()))) 
                .subject("Testing email")
                .body("Testing body ...")
                .encoding("UTF-8").build();
            emailService.send(email); 
        }
    }

Continue reading

Advertisements

Getting to know about java.nio.file.Path – 2

In Part 1 of this, we looked at most of the APIs in the java.nio.file.Path class. In this article, we will look at the remaining APIs.

Using register()

This API allows us to register an implementation of java.nio.file.WatchService interface which will listen for events like directory creation, modification, and deletion. And it intimates the listeners by means of a java.nio.file.WatchKey. I would like to dedicate a different article for this API because it involves another new feature which was introduced in Java 7.

Using resolve()

This method deals with two Path instances. One instance on this the resolve() method is called and the other instance which is passed as an argument. The argument can be either a Path instance or a String representing the path.

This method resolves the other path against this path. The resolution is done as follows:

  1. If the other path is an absolute path, then it returns the other path. Because the other path can be reached by using the absolute path.
  2. If the other path is a relative path then the other path is appended to this path. For example:
    Path path = Paths.get("src", "main", "resources");
    Path other = Paths.get("blogsamples");
    
    assertThat(path.resolve(other)).isEqualTo(
            Paths.get("src", "main", "resources", "blogsamples"));

The different scenarios in which this method can be invoked is given in the test below:

@Test
public void testResolved() throws IOException {
    Path path = Paths.get("src", "main", "resources");
    Path other = Paths.get("blogsamples");

    assertThat(path.resolve(other)).isEqualTo(
            Paths.get("src", "main", "resources", "blogsamples"));

    other = Paths.get("/Users");
    assertThat(path.resolve(other)).isEqualTo(Paths.get("/Users"));

    path = Paths.get("/src", "main", "resource");
    assertThat(path.resolve("/Users")).isEqualTo(Paths.get("/Users"));
}

Using resolveSibling()

This method is similar to resolve() except that it considers this path’s parent to resolve the other path. Again there are different possibilities which I have captured in the test below:

@Test
public void testResolveSibling(){
    Path path = Paths.get("src", "main", "resources", "test1");
    Path other = Paths.get("test2");

    //both paths are not absolute
    assertThat(path.resolveSibling(other)).isEqualTo(
            Paths.get("src", "main", "resources", "test2"));

    //other path is absolute
    assertThat(path.resolveSibling("/test2")).isEqualTo(
        Paths.get("/test2"));

    //this path has no parent
    path = Paths.get("/");
    assertThat(path.resolveSibling("/test2")).isEqualTo(
        Paths.get("/test2"));

    //the other path is empty and this path has no parent
    assertThat(path.resolveSibling("")).isEqualTo(Paths.get(""));

    //the other path is empty and this path has parent
    path = Paths.get("src", "main", "resources", "test1");
    assertThat(path.resolveSibling("")).isEqualTo(
            Paths.get("src", "main", "resources"));
}

Using relativize()

This method returns a relative path that when resolved against this path returns the other path (i.e the path which is passed as a parameter).

I have tried to illustrate in the tests below the different possibilities while trying to create a relative path between two paths.

Path path = Paths.get("src", "main", "resources", "test1");
Path other = Paths.get("test2");

assertThat(path.relativize(other).toString())
    .isEqualTo("..\\..\\..\\..\\test2");

In the above case, both the paths are relative. It requires 4 hops backward from the src/main/resources/test1 to reach /test2. The same is obtained by applying the relativize method.

If one of the paths is absolute and the other is relative, then invoking relativize results in an IllegalArgumentException as shown below:

@Test(expected = IllegalArgumentException.class)
public void testRelativize_WithRelativeAndAbsolutePath(){
    Path path = Paths.get("/src", "main", "resources", "test1");
    Path other = Paths.get("src", "main", "resources");
    path.relativize(other);
}

If both the paths are absolute, then the output of relativize() is implementation dependent. The below test is written against JDK 8 on Windows platform:

@Test
public void testRelativize_WithAbsolutePaths(){
    Path path = Paths.get("/src", "main", "resources", "test1");
    Path other = Paths.get("/src", "main", "resources", "test1", "test2");
    assertThat(path.relativize(other).toString())
        .isEqualTo("test2");
}

Using startsWith()

This method checks if the path on which the startsWith() method has the same name elements in the beginning as that of the path passed as the argument. And the path passed as the argument has no extra name elements that are not present in this path.

For example: /a/b/c starts with /a/b , a/b/c/d starts with a/b/c

Let us look at the different possible cases while invoking the method:

@Test
public void testStartsWith(){
    //both paths are absolute
    Path path = Paths.get("/src", "main", "resources", "test1");
    Path other = Paths.get("/src", "main", "resources");
    assertThat(path.startsWith(other)).isTrue();

    /*
    both paths are absolute, where as the other 
    path has more name elements 
    */
    path = Paths.get("/src", "main", "resources", "test1");
    other = Paths.get("/src", "main", "resources", 
        "test1", "test2");
    assertThat(path.startsWith(other)).isFalse();

    //both paths are same
    path = Paths.get("/src", "main", "resources", "test1");
    other = Paths.get("/src", "main", "resources", "test1");
    assertThat(path.startsWith(other)).isTrue();

    //either of them is relative
    path = Paths.get("src", "main", "resources", "test1");
    other = Paths.get("/src", "main", "resources", "test1");
    assertThat(path.startsWith(other)).isFalse();

    //both of them are relative
    path = Paths.get("src", "main", "resources", "test1");
    other = Paths.get("src", "main", "resources");
    assertThat(path.startsWith(other)).isTrue();

}

Getting to know about java.nio.file.Path – 1

Introduction

The last few released of Java namely Java 7, Java 8 and the upcoming Java 9 have quite a lot of features which makes the life of Java developers easier. (I know Java 9 will make it tougher, but only while you adopt the new paradigm. After that it’s going to be much better).

One of the features or API was the enhancements of the File API introduced in Java 7. One of the new classes of that feature set is java.nio.file.Path and its factory java.nio.file.Paths.

Maven Dependencies

We will be using JUnit and AssertJ to write our tests to demonstrate the API.

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>
<dependency>
    <groupId>org.assertj</groupId>
    <artifactId>assertj-core</artifactId>
    <!-- use 2.8.0 for Java 7 projects -->
    <version>3.8.0</version>
    <scope>test</scope>
</dependency>

Creating an instance of java.nio.file.Path

As I mentioned before java.nio.file.Paths is the creator for java.nio.file.Path that is it provides two factory methods:

  • static Path get(String first, String … more)
  • static Path get(URI uri)

that can be used to get an instance of java.nio.file.Path. Let us look at the two ways to obtain the instance:

@Test
public void testPathCreation(){
    Path path = Paths.get("src", "main", "resources");
    assertThat(path.isAbsolute()).isFalse();
    assertThat(path.toString()).isEqualTo("src\\main\\resources");

    Path uriPath = Paths.get(URI.create("file:///Users/Mohamed/git"));
    assertThat(uriPath.isAbsolute()).isFalse();
    assertThat(uriPath.toAbsolutePath().toString())
            .isEqualTo("C:\\Users\\Mohamed\\git");
}

Exploring the APIs

Using endsWith()

This method is used to check if a given Path object ends with another Path object or a path represented as a String object.

@Test
public void testEndsWith(){
    Path path = Paths.get("src", "main", "resources");
    assertThat(path.endsWith(Paths.get("main","resources"))).isTrue();
    assertThat(path.endsWith("resources")).isTrue();
}

Using getFileName()

This method returns the name of the directory or the file present at the terminal or end of the path.

@Test
public void testGetFileName(){
    Path path = Paths.get("src", "main", "resources");
    assertThat(path.getFileName().toString()).isEqualTo("resources");
    path = Paths.get("src", "test", "java", "info", 
        "sanaulla","PathDemoTest.java");
    assertThat(path.getFileName().toString())
        .isEqualTo("PathDemoTest.java");
}

Using getFileSystem()

This method returns an instance of java.nio.file.FileSystem representing the underlying file system. We will look at this in detail in a future post.

@Test
public void testGetFileSystem(){
    Path path = Paths.get("src", "main", "resources");
    assertThat(path.getFileSystem()).isNotNull();
    assertThat(path.getFileSystem().getSeparator()).isEqualTo("\\");
    path.getFileSystem().getRootDirectories().forEach(System.out::println);
}

Using getName() and getNameCount()

The getNameCount() returns number of name components present in the path where each name component is seperated by a file seperator. And the method getName() takes an index and returns the name component at the index.

For example  a given path: /var/log/myapp/spring.log has 4 name components and the component position is 0 based. So the name component at index 1 is log.

@Test
public void testGetName(){
    Path path = Paths.get("src", "main", "resources");
    assertThat(path.getName(0)).isEqualTo(Paths.get("src"));

    assertThat(path.getName(path.getNameCount() - 1))
            .isEqualTo(Paths.get("resources"));
}

Using getParent()

This API returns the path from the root of a path until the terminal directory or file (i.e excluding it). For example: invoking getParent() on a Path instance representing /var/log/myapp/spring.log returns a Path instance representing /var/log/myapp

It returns null if the given path has no parent or if it is the root directory.

@Test
public void testGetParent(){
    Path path = Paths.get("src", "main", "resources");
    assertThat(path.getParent()).isEqualTo(Paths.get("src", "main"));
    assertThat(Paths.get("/").getParent()).isNull();
}

Using getRoot()

This API returns a Path instance of the root if it exists or null for a given instance of Path.

@Test
public void testGetRoot(){
    Path path = Paths.get("src", "main", "resources");
    assertThat(path.getRoot()).isNull();

    path = Paths.get("/users", "Mohamed", "git", "blogsamples");
    assertThat(path.getRoot()).isEqualTo(Paths.get("/"));
}

Using normalize()

This API is a bit tricky. It removes redundant elements in your path. Redundant elements are those whose removal will eventually result in a similar Path. For example: if we have a path src\..\src\main\java is equivalent to src\main\java. The normalize() API helps in achieving the latter from the former.

@Test
public void testNormalize(){
    Path path = Paths.get("src","..", "src", "main", "resources", ".");
    assertThat(path.toString())
            .isEqualTo("src\\..\\src\\main\\resources\\.");
    assertThat(path.normalize().toString())
            .isEqualTo("src\\main\\resources");
}

Using subpath()

This method returns a sub path identified by the lower bound and upper bound which are passed as parameters to the method. The upper bound is excluded while computing the sub path.

@Test
public void testSubpath(){
    Path path = Paths.get("Mohamed", "git", 
            "blogsamples", "src", "main", "resources");
    assertThat(path.subpath(2, 3).toString()).isEqualTo("blogsamples");
    assertThat(path.subpath(0, path.getNameCount()).toString())
            .isEqualTo("Mohamed\\git\\blogsamples\\src\\main\\resources");
}

Using toAbsolutePath()

This method returns the absolute path for the given path. An absolute path originates from the root of the file system.

@Test
public void testToAbsolutePath(){
    Path path = Paths.get("src", "main", "resources");
    assertThat(path.toAbsolutePath().toString())
       .isEqualTo("C:\\Users\\Mohamed\\git\\blogsamples\\src\\main\\resources");
}

Using toFile()

This is a very handy way to create an instance of java.io.File. We can leverage the use of creating a Path object with multiple folder levels and then use toFile() to get an instance of File.

@Test
public void testToFile(){
    Path path = Paths.get("src", "main", "resources");
    File file = path.toFile();
    assertThat(file).isNotNull();
    assertThat(file.isDirectory()).isTrue();
    assertThat(file.exists()).isTrue();
}

Using toRealPath()

This method can be used to resolve a symbolic link to its real location. To test this API we create a symbolic link:

On windows you would use:

mklink /D "C:\blogsample" "C:\Users\Mohamed\git\blogsamples"

On Linux, you would use

ln -s /var/log/sample.log sample

The method takes an option of type LinkOption. As of now, this enum has one element i.e NOFOLLOW_LINKS. If this option is passed then the symbolic link is not resolved to its real path.

@Test
public void testToRealPath() throws IOException {
    Path path = Paths.get( "/blogsample");
    assertThat(path.toRealPath().toString())
            .isEqualTo("C:\\Users\\Mohamed\\git\\blogsamples");
    assertThat(path.toRealPath(LinkOption.NOFOLLOW_LINKS).toString())
            .isEqualTo("C:\\blogsample");
}

Using toUri()

This method returns a URI representation of a given path. Generally, on Windows, you would see something of the form: file:///C:/. But this is system dependent

@Test
public void testToUri(){
    Path path = Paths.get("src", "main", "resources");
    assertThat(path.toUri()).isEqualTo(
      URI.create("file:///C:/Users/Mohamed/git/blogsamples/src/main/resources/"));
}

Note: It’s important to note that the return type of most of the APIs is an instance of java.nio.file.Path. This helps us in chaining multiple methods and invoke them on a single java.nio.file.Path instance.

In the next article, we will look at the remaining few APIs in java.nio.file.Path.

Behavior Driven Development (BDD) of Postfix calculator

What is a postfix expression?

An expression where in the operator is placed after the operands is called a postfix expression. For example an expression (also called infix expression) 2 + 3 in postfix is 2 3 +, expression 2 + 3 * 4 in postfix is 2 3 4 * +

In this article we will look at how to develop an postfix expression evaluator using BDD approach. Our evaluator would handle Addition, Subtraction, Multiplication and Division of floating and integer numbers.

BDD in action

Let us create a maven application for our BDD experiment. I am using Eclipse as my IDE. Once you have your project created, add the following dependencies in the pom.xml

<dependency>
  <groupId>info.cukes</groupId>
  <artifactId>cucumber-java</artifactId>
  <version>1.2.5</version>
  <scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/info.cukes/cucumber-junit -->
<dependency>
  <groupId>info.cukes</groupId>
  <artifactId>cucumber-junit</artifactId>
  <version>1.2.5</version>
</dependency>

In BDD we first write acceptance tests. These acceptance tests are tests which would test the complete module/application there by declaring it to satisfy the user requirements. And these can be captured at the time of creating the acceptance criteria for a user story (concept widely used in scrum based agile software development methodology). These tests tend to be more user requirement focused and are often written in collaboration with the customer or customer representative or the product owner.

At the stakeholders end

As the people involved in the development of acceptance tests tend to non-technical, there is a Domain Specific Languge (DSL) available which helps in capturing the acceptance tests. This DSL is called Gherkin. And a tool called Cucumber helps in generating tests and then executing them. This generation and execution of tests is all behind the scenes and is carried out by the developer.

Let us see how a sample Gherkin file (ends with a .feature extension) looks like:

#comment
# there can be only 1 feature in a .feature file
Feature: Feature name
    feature description

# there can be multiple scenarios, which means multiple possibilities the feature can be used 
Scenario: Scenario 1
Given some input "abc"
And another input "xyz"
When user performs some action
Then the result should be "pqr"

# similarly we can have multiple scenarios

The above feature file is pretty clear and is mostly english language based. (This is the beauty of DSLs). There are few key words in the above file like Feature, Scenario, Given, And, When, Then and few more. And there are some restrictions like there can be only 1 Feature, And at the beginning of new line should be And and not and, then and can occur with in the sentence as normal and and so on. (I know too many ands). But such restrictions are what is imposed by the DSL.

Generating such feature files is quite simple and we can easily collaborate with stakeholders to capture their requirements and specifications by using examples and these examples can be written in form of Scenarios.

Developers End

The developer can take this feature file and generate java code. This java code is nothing but collection of methods backing each Given, When, Then clauses written in the feature file. There are different ways to generate it and I will show you one such way in this article.

Dive into code

Let us now dive into the code.

Create a feature file postfix-evaluator.feature in the location src/test/resources

Feature: Testing Post Fix evaluator
	We would use this to test our post fix evaluator
	
Scenario: Testing the evaluator with sum only
Given User enters "2 3 5 + +"
When User asks for result
Then result should be "10"

Scenario Outline: Testing the evaluator with complex expressions
Given User enters <expression>
When User asks for result
Then result should be <result>

Examples:
    | expression | result |
    | "3 4 5 + -" | "-6" |
    | "5 1 2 + 4 * + 3 -" | "14"  |
    | "5 2 3 ^ + 5 8 + " | "13"  |
    | "2 1 12 3 / - +" | "-1" |
    | "6 3 - 2 ^ 11 - " | "-2" | 

You know Scenario, but what is this Scenario Outline? It is a parameterized version of Scenario which means that the Given, When, Then specified for the Scenario Outline are executed for each of the test input provided in the Example section.

But how do we link the Examples and Given, When, Then?

The first row of the Example section indicate the name of the variables to which the value is assigned. And the same variable name can be used in the parameterized clauses of Given, When, Then. And you parameterize the clauses using .

Now to generate the Java code for this feature file, let us create a JUnit test runner TestPostFixEvaluator.java in src/test/java/bdd

package bdd;

import org.junit.runner.RunWith;

import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;

@RunWith(Cucumber.class)
@CucumberOptions(features = "src/test/resources/")
public class TestPostFixEvaluator {

}

Run the above test and you will see a message like:

6 Scenarios ([33m6 undefined[0m)
18 Steps ([33m18 undefined[0m)
0m0.000s


You can implement missing steps with the snippets below:

@Given("^User enters \"([^\"]*)\"$")
public void user_enters(String arg1) throws Throwable {
    // Write code here that turns the phrase above into concrete actions
    throw new PendingException();
}

@When("^User asks for result$")
public void user_asks_for_result() throws Throwable {
    // Write code here that turns the phrase above into concrete actions
    throw new PendingException();
}

@Then("^result should be \"([^\"]*)\"$")
public void result_should_be(String arg1) throws Throwable {
    // Write code here that turns the phrase above into concrete actions
    throw new PendingException();
}

The above message contains the missing steps. So let us copy the above missing steps into class PostFixEvaluatorSteps in the package bdd under src/test/java and also add the code to test our post fix evaluator as shown below

package bdd;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import evaluator.PostFixEvaluator;

public class PostFixEvaluatorSteps {
  PostFixEvaluator evaluator;
  Double computedResult;
  
  @Given("^User enters \"([^\"]*)\"$")
  public void user_enters(String expression) throws Throwable {
    evaluator = new PostFixEvaluator(expression);
  }

  @When("^User asks for result$")
  public void user_asks_for_result() throws Throwable {
    computedResult = evaluator.evaluate();
  }

  @Then("^result should be (\\d+)$")
  public void result_should_be(Double result) throws Throwable {
    assertEquals(result, computedResult);
  }
  
  @Then("^result should be \"([^\"]*)\"$")
  public void result_should_be(String result) throws Throwable {
    assertTrue(Double.parseDouble(result) == computedResult);
  }
 
}

Running the above will give up all sorts of abuses from the java compiler. So let us create a PostFixEvaluator class in the package evaluator under src/main/java with the class definition as shown below:

package evaluator;

import java.util.Stack;

public class PostFixEvaluator {
  
  public final String expression;
  
  public PostFixEvaluator(String expression) {
    this.expression = expression;
  }
    
  public Double evaluate(){ return 0d; }
}

And if you run the test TestPostFixEvaluator, you will see that all the tests as failing as shown below:
bdd1

To implement a Post fix evaluator we make use of Stack. The way it works is:
1. If you encounter an operand, push it to stack
2. If you encounter a binary operator pop two elements and push the result to stack
3. If you encounter a unary operator pop 1 element and push the result to stack
4. If you have come to the end of expression then pop the stack to get the result.

There are various error conditions which we can handle:
1. If at the end of expression stack is empty, then we dont have any result
2. If at the end of expression stack has more than 1 element then we dont have enough operators, so expression is invalid
3. If on encountering an operator, we dont have enough operands in the stack, then the expression is invalid.
and so on.

We can update the PostFixEvaluator class with the code below (I havent considered error scenarios. We can easily add some negative tests and then write code to pass those negative tests, refactoring becomes easy as we already have tests for our feature).

package evaluator;

import java.util.Stack;

public class PostFixEvaluator {
  
  public final String expression;
  
  public PostFixEvaluator(String expression) {
    this.expression = expression;
  }
  
  Stack<Double> pfStack = new Stack<Double>();
  
  public Double evaluate(){
    String [] exprArray = expression.split("\\s+");
    for ( String elem : exprArray){
      if ( isOperator(elem)){
          Double operand2 = pfStack.pop();
          Double operand1 = pfStack.pop();
          switch (elem) {
          case "*":
            pfStack.push(operand1 * operand2);
            break;
          case "+":
            pfStack.push(operand1 + operand2);
            break;
          case "-":
            pfStack.push(operand1 - operand2);
            break;
          case "/":
            pfStack.push(operand1 / operand2);
            break;
          case "^":
            pfStack.push(Math.pow(operand1, operand2));
            break;
          default:
            throw new RuntimeException("Unsupported operator");
        }
      }else{
        pfStack.push(Double.parseDouble(elem));
      }
    }
    
    if ( pfStack.isEmpty()){
      throw new RuntimeException("Stack is empty, no result found");
    }
    return pfStack.pop();
  }
  
  private boolean isOperator(String element){
    switch (element) {
    case "+":
    case "-":
    case "/":
    case "*":
    case "^":
      return true;
    default:
      return false;
    }
  }
  
}

It is a pretty naive design, one can refactor and also refactor to use Strategy design pattern. This is all possible because we have acceptance tests, if we make some error during the refactoring, then the acceptance tests will flag them.

Let us run the test TestPostFixEvaluator now and see that all the scenarios are getting executed successfully:
bdd2

This was a simple introduction to BDD. In the next article I will show how we can apply TDD exclusively and then an article with a mix of BDD and TDD.

The source for this is available on Github: https://github.com/sanaulla123/bdd-tdd-demo

Looking forward to hear your feedback!

Gotcha: Migrating from Spring Security 3.2.x to Spring Security 4.x

Here is a simple gotcha to keep in mind while migrating to newer Spring Security version 4.x from Spring Security 3.2.x

What’s the problem?

The Spring security configuration expressions hasRole('role_name') and hasAuthority('role_name') are no longer the same.

The catch is: hasAuthority checks for any role name passed to the expression without prepending ‘ROLE_’ (which is the default role prefix), where as hasRole checks for any role name passed to the expression by prepending ‘ROLE_’ to the role name.

Below is the snapshot of the class definition for SecurityExpressionRoot for both the versions of Spring Security which defines the methods hasRole and hasAuthority.

springsec-gotcha

In Spring Security 3.2.x hasAuthority and hasRole are checking for the presence of given role name in getAuthoritySet() [The getAuthoritySet() retrieves the GrantedAuthority list for the user]

In Spring Security 4.x hasAuthority is invoking the API hasAnyAuthorityName passing the prefix as null whereas hasRole is invoking the API hasAnyAuthorityName passing the default prefix which is ‘ROLE_’ (the same has been highlighted in the image above)

There is another interesting API in Spring Security 4.x (again highlighted in the image above) called getRoleWithDefaultPrefix() as shown in image below:

springsec4-2.png

Interesting to see above how the role name is being prefixed with the role prefix.

What is the fix?

  1. Either you append all your roles with ‘ROLE_’ prefix. OR
  2. Use hasAuthority as the replacement for hasRole expression without the need for changing the role names OR
  3. Override the defaultRolePrefix with null or empty string so that the same expression hasRole works with the same role names. [I need to figure out how to do this. It should be possible because the setter for the property is public]

New @RequestParam annotations in Spring Boot 1.4 (Spring Framework 4.3)

Earlier in Spring/Spring Boot to Map a GET or POST or DELETE or any HTTP method request handler we would write something like below:

@RestController
@RequestMapping("/api/books")
public class BookAPIController {
  @RequestMapping
  public ResponseEntity<?> getBooks(){
  
  }
  
  @RequestMapping("/{book_id}")
  public ResponseEntity<?> getBook(@PathVariable("book_id") String bookId){
  
  }
  
  @RequestMapping(method = RequestMethod.POST)
  public ResponseEntity<?> addNewBook(@RequestBody Map<String, Object> requestBody){
	
  }
  
  @RequestMapping(method = RequestMethod.POST, value="/{book_id}")
  public ResponseEntity<?> editBook(@PathVariable("book_id") String bookId){
	
  }
  
  @RequestMapping(method = RequestMethod.DELETE, value="/{book_id}")
  public ResponseEntity<?> deleteBook(@PathVariable("book_id") String bookId){
	
  }
}

But with Springframework 4.3 and Spring Boot 1.4 (which now uses Springframework 4.3) we have some new annotations to map the HTTP methods to request handlers for the following HTTP methods: GET, POST, PUT, PATCH, DELETE. These new annotations are namely: @GetMapping, @PostMapping, @PutMapping, @PatchMapping, @DeleteMapping. So the above code now looks like:

@RestController
@RequestMapping("/api/books")
public class BookAPIController {
  @GetMapping
  public ResponseEntity<?> getBooks(){}
  
  @GetMapping("/{book_id}")
  public ResponseEntity<?> getBook(
    @PathVariable("book_id") String bookId
  ){}
  
  @PostMapping
  public ResponseEntity<?> addNewBook(
    @RequestBody Map<String, Object> requestBody
  ){}
  
  @PostMapping("/{book_id}")
  public ResponseEntity<?> editBook(
    @PathVariable("book_id") String bookId
  ){}
  
  @DeleteMapping("/{book_id}")
  public ResponseEntity<?> deleteBook(
   @PathVariable("book_id") String bookId
  ){}
}

These new annotations aid in improving the code readability and also reducing the annotation text to some extent

Java Gotcha: Parse string using SimpleDateFormat with months greater than 12

I was the other day trying to parse a date string into a date object using SimpleDateFormat to check for the validity of the date string. I had the SimpleDateFormat defined as: SimpleDateFormat expiryDateFormat = new SimpleDateFormat("dd/MM/yyyy");. The date string I was trying to parse was: 10/26/2016 which is clearly invalid with respect to the pattern defined in the SimpleDateFormat. I found that the parsing went through and then it failed while trying to insert into DB due to invalid date. I was utterly confused. Then I wrote a small program to isolate the issue with SimpleDateFormat:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Solution {

  public static void main(String[] args) {

    SimpleDateFormat expiryDateFormat = 
        new SimpleDateFormat("dd/MM/yyyy");
    try {
      Date date =expiryDateFormat.parse("10/26/2016");
      System.out.println(date);
    } catch (ParseException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }

  }
}

The above code gave an output: Sat Feb 10 00:00:00 AST 2018. I was surprised at this behavior. Then I uncovered a secret method setLenient() using which we can put the SimpleDateFormat parsing to be strict and report errors on slightest of mismatch and not try to interpret the input by adjusting the value. So an updated code looks like:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Solution {

  public static void main(String[] args) {

    SimpleDateFormat expiryDateFormat = 
        new SimpleDateFormat("dd/MM/yyyy");
    expiryDateFormat.setLenient(false);
    try {
      Date date =expiryDateFormat.parse("10/26/2016");
      System.out.println(date);
    } catch (ParseException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }

  }
}

which indeed throws an exception as expected:

java.text.ParseException: Unparseable date:"10/26/2016"
	at java.text.DateFormat.parse(DateFormat.java:366)
	at Solution.main(Solution.java:12)