Category Archives: Java

Vert.x event bus communicating between Verticles

In my previous post on Vert.x, I demonstrated how to create multiple Verticle’s but also how a Verticle needn’t actually be a “service” but in some cases is just a worker process or in the case of the previous post a “main” or startup process.

This leads us to better see how Vert.x is actor-like with regards to Verticles.

In situations where we have multiple Verticles and possible some of those Verticles are simply workers for the other Verticles, we would need some way of communicating across those different parts of the application. Hence Vert.x also comes with an event bus for communicating across Verticles. This is a global event bus across all our Verticles.

Let’s, for sake of simplicity change our previous example so that whenever a service is successfully routed to, an event is sent out of the EventBus to say which services was called.

So, taken the example from my previous post, add the following to the MainVerticle start method

EventBus eventBus = vertx.eventBus();

eventBus.consumer("/svc", m -> {
   System.out.println(m.body());
});

The String /svc is the topic or an address if you prefer that we publish and consume message from. In the example above, we’re listening to the event bus for the anything sent (or published) to the address /svc. How you name you addresses is totally upto you.

Don’t forget to import io.vertx.core.eventbus.EventBus to use the event bus.

Next we’ll add code to the services to send a message on the /svc address when we wish to communicate something. Here’s the code for the HelloVerticle start method with the event bus added.

@Override
public void start() {

   EventBus evBus = vertx.eventBus();

   router.route("/hello").handler(ctx -> {
      evBus.send("/svc", "hello called");

      ctx.response()
         .putHeader("content-type", "text/plain")
         .end("Hello " + ctx.queryParam("name"));
      });

      vertx.createHttpServer()
         .requestHandler(router::accept)
         .listen(8080);

   System.out.println("HTTP server started on port 8080");
}

As you can see from the highlighted lines adding an event bus and sending messages out on it, is very simple. If we updated the WorldVerticle from the previous post also (but sending “world called”) then when run, the MainVerticle will print a line to the console every time the HelloVerticle or WorldVerticle routes are called.

Publish and Send

In the example (above) I used the event buss method send to send messages out on the event bus, but send will only be delivered to at most one of the handlers of the message.

Therefore is we added the following code to each of our service Verticles

evBus.consumer("/svc", m -> {
   System.out.println("Hello " + m.body());
});

After the declaration of the evBus variable.

we’ve now got a requirement that the message on address /svc needs to be handled by multiple consumers. Running up the application as it currently stands would result in only one of the consumers receiving the messages. In my case this was the MainVerticle, however there’s no guarantee which Verticle would receive the messages as this is determined by Vert.x in a round robin fashion.

So here’s the difference between send and publish. If you change the code from send to publish in the service Verticles. Then messages will be routed to all consumers.

Multiple Verticles

In my previous post I looked at creating my first Verticle/Vert.x application. This had a single Verticle acting as a service and running up a server against port 8080. If we therefore assume that by default a Verticle represents a single service then to create multiple service we simply create multi-Verticles.

Let’s create three Verticle’s. The first will act as the “main” verticle (or run as an application) and it will register/deploy the Verticle’s that we’re using to host our two services, the HelloVerticle and WorldVerticle.

Each service will itself create/host an HttpServer. Traditionally this would tend to mean we’d have two ports exposed, one for each service, but Vert.x allows us to create multiple HttpServer’s on the same port and uses something like “round robin” to try to locate a valid route.

Check my previous post for the required pom.xml.

Here’s MainVerticle.java

package com.putridparrot;

import io.vertx.core.AbstractVerticle;
import io.vertx.ext.web.Router;

public class MainVerticle extends AbstractVerticle {
    @Override
    public void start() {
        Router router  = Router.router(vertx);

        vertx.deployVerticle(new HelloVerticle(router));
        vertx.deployVerticle(new WorldVerticle(router));
    }
}

Notice that this Verticle’s job is to both register the other Verticle’s and acts as the main entry point to our application.

You do not need to pass the Router around in this way unless we intend to have multiple routes on the same port. So in this case we’re creating the router that will be used by both services on the same port.

Let’s look at the HelloVerticle.java service (both HelloVerticle and WorldVerticle, in this simple example, are basically the same, but I’ll reproduce all code here anyway).

package com.putridparrot;

import io.vertx.core.AbstractVerticle;
import io.vertx.ext.web.Router;

public class HelloVerticle extends AbstractVerticle {

    private Router router;

    public HelloVerticle(Router router) {
        this.router = router;
    }

    @Override
    public void start() {
        router.route("/hello").handler(ctx -> {
            ctx.response()
                    .putHeader("content-type", "text/plain")
                    .end("Hello " + ctx.queryParam("name"));
        });

        vertx.createHttpServer()
                .requestHandler(router::accept)
                .listen(8080);

        System.out.println("HTTP Hello server started on port 8080");
    }
}

There’s nothing particularly special or different here, compared to my previous posts code. So let’s look at the WorldVerticle.java

package com.putridparrot;

import io.vertx.core.AbstractVerticle;
import io.vertx.ext.web.Router;

public class WorldVerticle extends AbstractVerticle {

    private Router router;

    public WorldVerticle(Router router) {
        this.router = router;
    }

    @Override
    public void start() {
        router.route("/world").handler(ctx -> {
            ctx.response()
                    .putHeader("content-type", "text/plain")
                    .end("World " + ctx.queryParam("name"));
        });

        vertx.createHttpServer()
                .requestHandler(router::accept)
                .listen(8080);

        System.out.println("HTTP World server started on port 8080");
    }
}

What’s interesting is that both HelloVerticle and WorldVerticle create the HTTP server on the same port. As stated earlier Vert.x simply handles this for us without a port conflict and because we’re using a single router across these two Verticle’s Vert.x can correctly located the service for each of the following URL’s

http://localhost:8080/hello?name=Hello
http://localhost:8080/world?name=World

First look at Eclipse Vert.x

Eclipse Vert.x is a lightweight framework for developing web applications, microservices and more.

I’ve created a project using IntelliJ named VertxTest based upon a Maven project to try out the routing functionality in Vert.x.

Dependencies – the pom

Our pom.xml looks like this

<?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>VertxTest</groupId>
    <artifactId>VertxTest</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
        <vertx.version>3.5.0</vertx.version>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>2.4.3</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <transformers>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <manifestEntries>
                                        <Main-Class>io.vertx.core.Launcher</Main-Class>
                                        <Main-Verticle>com.putridparrot.MainVerticle</Main-Verticle>
                                    </manifestEntries>
                                </transformer>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                    <resource>META-INF/services/io.vertx.core.spi.VerticleFactory</resource>
                                </transformer>
                            </transformers>
                            <artifactSet>
                            </artifactSet>
                            <outputFile>${project.build.directory}/${project.artifactId}-${project.version}-fat.jar</outputFile>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.5.0</version>
                <configuration>
                    <mainClass>io.vertx.core.Launcher</mainClass>
                    <arguments>
                        <argument>run</argument>
                        <argument>com.putridparrot.MainVerticle</argument>
                    </arguments>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>io.vertx</groupId>
            <artifactId>vertx-core</artifactId>
            <version>${vertx.version}</version>
        </dependency>
        <dependency>
            <groupId>io.vertx</groupId>
            <artifactId>vertx-unit</artifactId>
            <version>${vertx.version}</version>
        </dependency>
        <dependency>
            <groupId>io.vertx</groupId>
            <artifactId>vertx-web</artifactId>
            <version>${vertx.version}</version>
        </dependency>
    </dependencies>
</project>

The Verticle

As you can see from this my class MainVerticle (which extends AbstractVerticle) is created in the package com.putridparrot and the code looks like this

package com.putridparrot;

import io.vertx.core.AbstractVerticle;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.BodyHandler;

public class MainVerticle extends AbstractVerticle {
    @Override
    public void start() {

        Router router = Router.router(vertx);

        router.route("/hello").handler(ctx -> {
            ctx.response()
                .putHeader("content-type", "text/plain")
                .end("Hello " + ctx.queryParam("name"));
        });

        vertx.createHttpServer()
            .requestHandler(router::accept)
            .listen(8080);

        System.out.println("HTTP server started on port 8080");
    }
}

Note: queryParam actually returns a List so in this example we would probably want to actually check the result and then get items from the list.

We extend AbstractVerticle overriding the start method to handle the setting up of our routes etc.

Building and Running

We execute mvn clean install and then mvn package to generate the executable jar. Finally we can run this using java -jar target/VertxTest-1.0-SNAPSHOT-fat.jar or similar in a configuration in an IDE (for example a JAR Application configuration within Intelli J just requires the path to the JAR listed above).

Testing and more

Now we should be able to run the following from your preferred web browser or Intelli J’s REST client (or similar in another IDE).

http://localhost:8080/hello?name=Mark

We can easily add further routes and/or handle GET or POST HTTP methods. For example here’s the addition of an error route using the get method

router.get("/error")
   .handler(this::handleGetError);

and

private void handleGetError(RoutingContext ctx) {
   ctx.response()
      .setStatusCode(500)
      .end();
}

Now browsing to

http://localhost:8080/error

will display a 500 error.

Static pages

We can also add static pages by declaring a route such as

 router.route("/pages/*")
   .handler((StaticHandler.create("pages")));

where the pages directory is located off the root off of the project folder (in this example). Simply place your HTML pages in this folder and you can access them using the following URL

http://localhost:8080/pages/index.html

Routing based upon mime type

Along with routine based upon the specific query/resource requested we can also route based upon the Content-Type within a request. For example if using HTTP POST with Content-Type application/json we would want to return JSON, likewise if Content-Type is application/xml we’d expect XML return (and so on).

To route based upon the mime type we simply write the following

router.route()
   .consumes("*/json")
   .handler(ctx -> {
      System.out.println("JSON request");
});

router.route()
   .consumes("*/xml")
   .handler(ctx -> {
      System.out.println("XML request");
});

Obviously in the examples above we’re simply routing off of the root “/” URL. Supply a path within the route method, as per previous example for other routing scenarios.

Running our Vertx application

We’ve seen we can create and run the JAR, but we can also create a Vertx application by creating a main method that looks something like this

public static void main(String[] args) {
   Vertx vertx = Vertx.vertx();

   vertx.deployVerticle(new MainVerticle());
}

We use deployVerticle along with our Verticle and Vertx does the rest.

Embedding files and/or templates within templates using Velcocity

We can embed a file or other templates within Velocity templates – this is obviously useful for reusing snippets of code/text or whatever in more than file. We still need to create the context mappings for all the template file that form out overall template – in other words we supply the mappings the container template and all of the embedded templates.

To embed a template we simply use the #include or #parse directives. #include is used to pull in a template or file without transforming it using the template engine, i.e. any variables etc. will not be transformed or rendered by Velocity whereas #parse will transform any Velocity variables or code.

Taking the template (template.txt.vm) from my previous post, which looked like this

Hello $name,

This is a $template_name template.

we might break this template into the following two templates

salutation.txt.vm

Hello $name,

and template.txt.vm becomes

#parse("templates/salutation.txt.vm")

This is a $template_name template.

This will result in the combined and transformed template.

Using the Velocity template engine

Velocity is a template engine written for Java. It allows us to take files (or strings) with embedded Velocity Template Language (VTL) code and transform the files (or strings) based upon supplied values.

Let’s create a simple template file (by default we use the extension .vm and a good convention is to append it to the original extension file type, so you know what type of file you’re transforming) then we’ll use Velocity to transform the file.

We’ll create a standard Maven layout project

  • From IntelliJ create a new project and select Maven
  • In the src/test folder add a new directory names resources
  • Mark the directory as test resources
  • Add a folder to resources named templates
  • Add the file template.txt.vm

My template.vm looks like this

Hello $name,

This is a $template_name template.

As you’ve probably guessed the $ prefix denotes a variable which we will supply to Velocity.

The first thing we need to do is create the Velocity engine and then set it up to allow us to load our files from the resources folder, here’s the code for this

VelocityEngine velocityEngine = new VelocityEngine();
velocityEngine.setProperty(
   "resource.loader", 
   "file");
velocityEngine.setProperty(
   "file.resource.loader.class", 
   "org.apache.velocity.runtime.resource.loader.FileResourceLoader");
velocityEngine.setProperty(
   "file.resource.loader.path", 
   "src/test/resources");

Next up we create a VelocityContext which we use to supply our mappings to the variable names used within the template file. We do not include the $ when supplying the variable name. We simply supply key value pairs, where the key is a String which represents the variable name and the value is what we want to replace it with (this is an Object which can be more complex than just a String). For this example our value will just be a String, so we have the following

VelocityContext velocityContext = new VelocityContext();
velocityContext.put("name", "PutridParrot");
velocityContext.put("template_name", "MyPutridParrotTemplate");

Note: If we do not add a context mapping then the result will be the original $variable_name, unchanged.

Finally, we want to actually “merge” (as Velocity calls the process) our context against the template and at the same time we’re going to convert the resultant “merged” template into a string

StringWriter writer = new StringWriter();
Template template = velocityEngine.getTemplate("templates/template.txt.vm");
template.merge(velocityContext, writer);

// to prove it worked...
System.out.println(writer.toString());

Running the above code we will get the output (as you would expect)

Hello PutridParrot,

This is a MyPutridParrotTemplate template.

Taking things a little further

As mentioned previously the value stored within the context is an Object, so we can store an array of values if we want.

Let’s assume we have the following template file

Hello $name,

My templates

#foreach( $t in $template_name)
    * $t
#end

As you can see the VTL supports foreach loops, so if we change the code that assigns the template_name to the context to look like this

ArrayList<String> list = new ArrayList<>();
list.add("Putrid");
list.add("Parrot");

velocityContext.put("template_name", list);

Our output will now be

Hello PutridParrot,

My templates

    * Putrid
    * Parrot

Take a look at the VTL reference for more options.

And finally

Finally for this post, it’s not unusual to have a string that represents the template, for example, maybe we get our templates from a web service or just load from another file location into memory.

Here’s the full code for this

String templateString = "Hello $name,\n\nThis is a $template_name template.";

RuntimeServices runtimeServices = RuntimeSingleton.getRuntimeServices();
StringReader reader = new StringReader(templateString);
SimpleNode node = runtimeServices.parse(reader, "Velocity Template");

VelocityContext velocityContext = new VelocityContext();
velocityContext.put("name", "PutridParrot");
velocityContext.put("template_name", "MyPutridParrotTemplate");

StringWriter writer = new StringWriter();
Template template = new Template();
template.setRuntimeServices(runtimeServices);
template.setData(node);
template.initDocument();

template.merge(velocityContext, writer);

// to prove it worked...
System.out.println(writer.toString());

The key differences are how we create the SimpleNode and then create the Template.

Duplicate step definitions in Gherkin & Cucumber (using IntelliJ)

Continuing from my last post Gherkin & Cucumber in Java (using IntelliJ).

Let’s assume you have a project set-up as per my previous post, delete any existing feature files and let’s create two very simple and very similar feature files

Feature: Calculator Add

  Scenario: Add two numbers
    Given Two input values, 1 and 2
    When I add the two values
    Then I expect the result 3
Feature: Calculator Subtract

  Scenario: Subtract two numbers
    Given Two input values, 1 and 2
    When I subtract the two values
    Then I expect the result -1

When we start creating our step definition files we might start with the Add feature and create something like AddStepdefs.java which includes the following code

package com.putridparrot;

import cucumber.api.PendingException;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;

public class AddStepdefs {
    @Given("^Two input values, (-?\\d+) and (-?\\d+)$")
    public void twoInputValuesAnd(int a, int b) throws Throwable {
    }

    @When("^I add the two values$")
    public void iAddTheTwoValues() throws Throwable {
    }

    @Then("^I expect the result (-?\\d+)$")
    public void iExpectTheResult(int r) throws Throwable {
    }
}

Next we might start creating the step definitions file for the Subtract feature and notice, IntelliJ shows one step as already existing (i.e. it’s not got a highlight background colour). If you press the CTRL key and move the mouse over the step which appear to exist already (i.e. Two input values, 1 and 2) a hyperlink line will appear, click this and it will take you to the previously added step in the AddStepdefs file.

What’s happening here is that whilst we might define separate classes per feature (which may well seem a logical way to write our test code/step definitions), Cucumber is actually matching to methods based upon the RegEx within the annotations, i.e. Given Two input values, 1 and 2 maps to

@Given("^Two input values, (-?\\d+) and (-?\\d+)$")
public void twoInputValuesAnd(int a, int b) throws Throwable {
}

Cucumber doesn’t actually take notice of the Given/When/Then annotations for matching the method to the line of Gherkin code.

Let us assume that we simply copy the missing step into the SubtractStepdefs.java file, we now have duplicate step definitions according to Cucumber, which is ofcourse correct if we think that each step is in essence globally scoped by Cucumber.

Or to put it another way, Cucumber will search through all the packages within the “Glue” package(s) to locate matching RegEx’s. If it finds more than one matching RegEx we get a duplicate step error. Here’s the (truncated) error that Cucumber will display for us when we try to run all features.

Exception in thread "main" cucumber.runtime.DuplicateStepDefinitionException: Duplicate step definitions in com.putridparrot.SubtractStepdefs.twoInputValuesAnd(int,int)

Handling duplicate step definitions

So how do we resolve a situation where we want to run all features and we have duplicate steps?

The easiest solution is, ensure you never have duplicate steps unless you intended to reuse the same step definition code – the general idea is to think of the language used to define a step in Gherkin as a specific task and another step using the same text is really the same task (at least when associated with the same package).

Ofcourse we can have duplicate steps in different packages, we just need to ensure we run features against on that package using the Glue option, i.e. do not reference all packages but just point to the one’s specific to the features.

If we therefore have the code like this in AddStepdefs and not in SubtractStepdefs

public class AddStepdefs {
   private int value1;
   private int value2;

   @Given("^Two input values, (-?\\d+) and (-?\\d+)$")
   public void twoInputValuesAnd(int a, int b) throws Throwable {
      value1 = a;
      value2 = b;  
   }
   // other code removed
}

the we have created another problem. The instance variables, value1 and value2 or stored in AddStepdefs and hence we’d also have similar variables stored in SubtractStepdefs (for use with the subtract scenario) however, the twoInputValuesAnd will never change the instance variables in the SubtractStepdefs for obvious reasons…

So how do we share instance data across our step definition files?

As programmers we might see a Scenario as analogous to a class but you can see that to ensure we adhere to the DRY principle we’d actually be better off creating a single class with all step definitions across all scenarios. This ofcourse is also not ideal because once we start to rack up a large number of scenarios, our class will become large and unwieldy.

So what we really want to do is create an instance of some shared state and have Cucumber pass this to each step definition class.

This is where cucumber-picocontainer comes in. If we add the following to the pom.xml

<dependency>
   <groupId>info.cukes</groupId>
   <artifactId>cucumber-picocontainer</artifactId>
   <version>1.2.5</version>
   <scope>test</scope>
</dependency>

and can “context” like this

public class ScenarioContext {
    private int value1;
    private int value2;
    private int result;

    public int getValue1() {
        return value1;
    }

    public void setValue1(int value) {
        this.value1 = value;
    }

    public int getValue2() {
        return value2;
    }

    public void setValue2(int value) {
        this.value2 = value;
    }

    public int getResult() {
        return result;
    }

    public void setResult(int value) {
        this.result = value;
    }
}

We can now change our step definitions files to look like this, first the AddStepdefs file

public class AddStepdefs {

    private ScenarioContext context;

    public AddStepdefs(ScenarioContext context) {
        this.context = context;
    }

    @Given("^Two input values, (-?\\d+) and (-?\\d+)$")
    public void twoInputValuesAnd(int a, int b) throws Throwable {
        context.setValue1(a);
        context.setValue2(b);
    }

    @When("^I add the two values$")
    public void iAddTheTwoValues() throws Throwable {
        Calculator calculator = new Calculator();

        context.setResult(calculator.add(context.getValue1(), context.getValue2()));
    }

    @Then("^I expect the result (-?\\d+)$")
    public void iExpectTheResult(int r) throws Throwable {
        Assert.assertEquals(r, context.getResult());
    }
}

and the SubtractStepdefs without any duplicated steps could look like this

public class SubtractStepdefs {

    private ScenarioContext context;

    public SubtractStepdefs(ScenarioContext context) {
        this.context = context;
    }

    @When("^I subtract the two values$")
    public void iSubtracTheTwoValues() throws Throwable {
        Calculator calculator = new Calculator();

        context.setResult(calculator.subtract(context.getValue1(), context.getValue2()));
    }
}

When a feature file is run, Cucumber will get an instance of our ScenarioContext passed to each class by the picocontainer which will them be used by the class methods.

Gherkin & Cucumber in Java (using IntelliJ)

This post will be based around implementing features etc. using IntelliJ, so your experience with tooling may differ from those experiences outlined in this post.

If you’re coming from Specflow and C# to IntelliJ and Java

I’ve used Gherkin previously when using Specflow in Visual Studio and with C#. The concepts, syntax etc. are exactly the same, however be aware that the generated code isn’t just different in terms of the language used (i.e. C# and Java for example) but also in the RegEx generated. As an example if your Gherkin has numbers then Specflow generated code allows for negatives, whereas the code generated within the IntelliJ/Java systems is a little stricter with it’s RegEx and negatives need to be added to the RegEx.

Creating our demo project

  • File | New Project
  • Select Maven project type
  • Enter the GroupId and ArtifactId

Now open the pom.xml and add the following

<dependencies>
   <dependency>
      <groupId>info.cukes</groupId>
      <artifactId>cucumber-java</artifactId>
      <version>1.2.5</version>
      <scope>test</scope>
   </dependency>
   <dependency>
      <groupId>info.cukes</groupId>
      <artifactId>cucumber-jvm</artifactId>
      <version>1.2.5</version>
      <type>pom</type>
   </dependency>
   <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
   </dependency>
</dependencies>

Creating our code

Let’s create a simple little class to run our tests against. Within src/java add a new class, mine’s named com.putridparrot.Calculator. Here’s the code that’s stored in src/main/java/com.putridparrot package

package com.putridparrot;

public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }
}

In src/test create a folder named resources and right mouse click on this folder and select Mark Directory As | Test Resources Root.

Note: the resources folder is not a requirement, more a convention.

Next, add a folder named features and within this folder create a new file named add.feature, this is a really simple example feature

Note: this post is not about writing good feature’s so this example is extremely basic.

Feature: Calculator
  
  Scenario Outline: add two numbers
    Given Two input values, <first> and <second>
    When I add the two values
    Then I expect the result <result>

  Examples:
    | first | second | result |
    | 1     | 12     | 13     |
    | -1    | 6      | 5      |

Select the end of each the Given, When and Then line and press alt+enter for each and select create steps definition. Name the file AddStepDef (mine’s created in the src/test/java/com/putridparrot folder/package) and set the file type to Java when you create your first step definition, then subsequently add step definitions to this same file.

Note: At the time of writing, selecting create all step definitions, does not seem to work as expected and simply creates a single step, not yet sure why.

Here’s what my generated steps looked like

package com.putridparrot;

import cucumber.api.PendingException;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;

public class AddStepDefs {
    @Given("^Two input values, <first> and <second>$")
    public void twoInputValuesFirstAndSecond() throws Throwable {
        // Write code here that turns the phrase above into concrete actions
        throw new PendingException();
    }

    @When("^I add the two values$")
    public void iAddTheTwoValues() throws Throwable {
        // Write code here that turns the phrase above into concrete actions
        throw new PendingException();
    }

    @Then("^I expect the result <result>$")
    public void iExpectTheResultResult() throws Throwable {
        // Write code here that turns the phrase above into concrete actions
        throw new PendingException();
    }
}

Sadly these require editing as the placeholders (the <> wrapped text) are not being passed as arguments into our methods. The simplest way to solve this is to change the placeholders to numbers (or the type we expect) delete the methods from the step definition file and then regenerate the step definitions. So here’s my “temporary” change to the feature to get valid steps generated.

Feature: Calculator

  Scenario Outline: add two numbers
    Given Two input values, 1 and 2
    When I add the two values
    Then I expect the result 3

    Examples:
      | first | second | result |
      | 1     | 12     | 13     |
      | -1    | 6      | 5      |

this gives us the following code

package com.putridparrot;

import cucumber.api.PendingException;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;

public class AddStepDefs {


    @Given("^Two input values, (\\d+) and (\\d+)$")
    public void twoInputValuesAnd(int arg0, int arg1) throws Throwable {
        // Write code here that turns the phrase above into concrete actions
        throw new PendingException();
    }

    @When("^I add the two values$")
    public void iAddTheTwoValues() throws Throwable {
        // Write code here that turns the phrase above into concrete actions
        throw new PendingException();
    }
    
    @Then("^I expect the result (\\d+)$")
    public void iExpectTheResult(int arg0) throws Throwable {
        // Write code here that turns the phrase above into concrete actions
        throw new PendingException();
    }

}

Return the feature file back to the version with placeholders.

Before we write our actual test code, let’s run the feature tests. In IntelliJ we can right mouse click on an individual feature file or the folder with the features and select Run feature or Run all features.

As we only have one feature file at the moment, select it, right mouse click and select Run: Feature Calculator, you’ll probably be hit with output in the test window along the lines of

Undefined step: Given… etc.

We need to edit the configuration for the runner and supply the Glue (in my case I have the steps in the package com.putridparrot, so I enter that in the Glue: option). Now running the feature should result in another error

Undefined step: Given Two input values, -1 and 6

As you can see, there’s a problem with the generated code as it expects a method that handles a negative number and none exist, we need to amend our RegEx for all methods to include a possible – sign. Changed all (\\d+) to (-?\\d+) now running the feature will have fixed the error.

Writing our test code

We can now write fairly standard unit testing code into the step definition file (in this case I’m using JUnit), so here’s a simple example

package com.putridparrot;

import cucumber.api.java.Before;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import org.junit.Assert;

public class AddStepDefs {

    private Calculator calculator;
    private int value1;
    private int value2;
    private int result;

    @Before
    public void before() {
        calculator = new Calculator();
    }

    @Given("^Two input values, (-?\\d+) and (-?\\d+)$")
    public void twoInputValuesAnd(int arg0, int arg1) throws Throwable {
        value1 = arg0;
        value2 = arg1;
    }

    @When("^I add the two values$")
    public void iAddTheTwoValues() throws Throwable {
        result = calculator.add(value1, value2);
    }

    @Then("^I expect the result (-?\\d+)$")
    public void iExpectTheResult(int arg0) throws Throwable {
        Assert.assertEquals(arg0, result);
    }
}

Common mistakes

Glue, glue and more glue – make sure you set up the glue.

Creating Java classes from an XML schema using Maven

I my previous post Creating Java classes from an XML schema I used xjc to generate the Java classes for a small project.

Ultimately I try to automate my tasks as much as possible and also don’t want to have to write a document with lots of steps when passing code onto others to use. So I decided it was time to get Maven to (as part of it’s process) automatically generate the classed for me using xjc.

So now when passing my app. to somebody else to take on, I just say run mvn install and it’ll do everything else for you.

To get this to work we need to use the xjc/jaxb-2 plugin.

In your pom.xml, add the following

<build>
   <pluginManagement>
      <plugins>
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-compiler-plugin</artifactId>
           <configuration>
              <source>1.7</source>
              <target>1.7</target>
           </configuration>
         </plugin>
     </plugins>
   </pluginManagement>
   <plugins>
      <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>jaxb2-maven-plugin</artifactId>
         <version>1.6</version>
         <executions>
            <execution>
               <id>request-xsd</id>
               <goals>
                  <goal>xjc</goal>
               </goals>
               <configuration>
                  <packageName>com.putridparrot.request</packageName>
                  <schemaDirectory>src/main/resources/xsd/request-xsd</schemaDirectory>
                  <clearOutputDir>false</clearOutputDir>
               </configuration>
            </execution>
            <execution>
               <id>request-xsd</id>
               <goals>
                  <goal>xjc</goal>
               </goals>
               <configuration>
                  <packageName>com.putridparrot.response</packageName>
                  <schemaDirectory>src/main/resources/xsd/response-xsd</schemaDirectory>
                  <clearOutputDir>false</clearOutputDir>
               </configuration>
            </execution>
         </executions>
      </plugin>
   </plugins>
</build>

In the above example, I actually have a request xsd and a response xsd for a webservice call. The problem (and hence why I have two separate execution sections) is that they have duplicate type names, which meant if I had them both in the same folder would end up with conflicts and an error for the class generation.

Note: The folder xsd can be named anything you like and contain the XSD’s themselves or contain folders, as I’m using.

The jaxb2-maven-plugin does all the work for us, it executes xjc, creates the package for out resultant classes (i.e. com.putridparrot.request and com.putridparrot.response). It generates the classes from the schema in the schemaDirectory (i.e. all XSD’s within that directory) and it’s doesn’t clear the output folder. This is not important if you are not outputting to the source folder or don’t want the output folder cleared when maybe not regenerating everything within it, but it’s very useful to stop you accidentally deleting all your source (as I did whilst outputting to the src/main/java folder initially!).

If you do not specify and output directory then the classes will be generated into your target folder, within target/generated-sources/jaxb/<you package names>.

These files are then compiled into your application and available to use in your source.

Spring configuration for a JSON/XML REST service in Java

In Creating a CXF service that responds with JSON or XML and Creating a CXF client which can get JSON or XML we created a service and a client application for interacting with REST requests using XML or JSON as the body for the messages.

The Java guys love spring and beans, my code was all in Java source. So I’m going to show how to convert both the server and client into spring configurations.

In your client/server code add a resources folder to /src/main and within that add a new xml file, named whatever you like, mine’s spring-client.xml and spring-server.xml (for the client and server respectively).

Changes to the server

Let’s concentrate on the server first – our code looked like this

JAXRSServerFactoryBean factoryBean = new JAXRSServerFactoryBean();
factoryBean.setResourceClasses(SampleServiceImpl.class);
factoryBean.setResourceProvider(new SingletonResourceProvider(new SampleServiceImpl()));

Map<Object, Object> extensionMappings = new HashMap<Object, Object>();
extensionMappings.put("xml", MediaType.APPLICATION_XML);
extensionMappings.put("json", MediaType.APPLICATION_JSON);
factoryBean.setExtensionMappings(extensionMappings);

List<Object> providers = new ArrayList<Object>();
providers.add(new JAXBElementProvider());
providers.add(new JacksonJsonProvider());
factoryBean.setProviders(providers);

factoryBean.setAddress("http://localhost:9000/");
Server server = factoryBean.create();

The first thing we need to do is update our pom.xml to import spring, so add the following to the properties section

<spring.version>2.5.6</spring.version>

and then these dependencies

<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context</artifactId>
   <version>${spring.version}</version>
</dependency>

<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-core</artifactId>
   <version>${spring.version}</version>
</dependency>

Now change the Java code in our main method, replacing all the code which is listed above, to

ApplicationContext context = new ClassPathXmlApplicationContext("spring-server.xml");

Now we need to add the following to our spring-server.xml file

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jaxrs="http://cxf.apache.org/jaxrs"
       xsi:schemaLocation="
         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
         http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">

    <jaxrs:server address="http://localhost:9000">
        <jaxrs:serviceBeans>
            <bean class="SampleServiceImpl" />
        </jaxrs:serviceBeans>
        <jaxrs:extensionMappings>
            <entry key="json" value="application/json"/>
            <entry key="xml" value="application/xml"/>
        </jaxrs:extensionMappings>
        <jaxrs:providers>
            <bean class="org.apache.cxf.jaxrs.provider.JAXBElementProvider" />
            <bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
        </jaxrs:providers>
    </jaxrs:server>
</beans>

We’re using the jaxrs configuration to create our service beans which means the server is automatically created for us.

That’s it for the server.

Changes to the client

Let’s look at the existing client code

List<Object> providers = new ArrayList<Object>();
providers.add(new JAXBElementProvider());
providers.add(new JacksonJsonProvider());

SampleService service = JAXRSClientFactory.create(
   "http://localhost:9000", SampleService.class, providers);

WebClient.client(service)
   .type(MediaType.APPLICATION_JSON_TYPE)
   .accept(MediaType.APPLICATION_JSON_TYPE);

First off, we need to add spring to the pom.xml as we needed for the server, so duplicate the steps for updating the pom.xml as already outlined.

Next we replace our client code (above) with the following

ApplicationContext context = new ClassPathXmlApplicationContext("spring-client.xml");
SampleService service = (SampleService)context.getBean("client");

and finally put the following into the spring-client.xml file

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jaxrs="http://cxf.apache.org/jaxrs"
       xsi:schemaLocation="
         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
         http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">

    <jaxrs:client id="client" address="http://localhost:9000" serviceClass="SampleService">
        <jaxrs:providers>
            <bean class="org.apache.cxf.jaxrs.provider.JAXBElementProvider" />
            <bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
        </jaxrs:providers>
        <jaxrs:headers>
            <entry key="Accept" value="application/json" />
        </jaxrs:headers>
    </jaxrs:client>
</beans>

and that’s it – run the server, then run the client and all should work.

Note: I’ll leave it to the reader to add the relevant import statements

Building a REST service with Spring

I’ve been doing a fair bit with SOAP, REST and Java recently using CXF. A previous post demonstrated using CXF/JAXB to create a REST style service that returned either JSON or XML, let’s look at using Spring REST services to implement the same functionality.

Let’s start (as usual) with our pom.xml

<?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>org.springframework</groupId>
    <artifactId>sample-rest-service</artifactId>
    <version>0.1.0</version>

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

    <dependencies>
        <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>
        <dependency>
            <groupId>com.jayway.jsonpath</groupId>
            <artifactId>json-path</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

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


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-releases</id>
            <url>https://repo.spring.io/libs-release</url>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>spring-releases</id>
            <url>https://repo.spring.io/libs-release</url>
        </pluginRepository>
    </pluginRepositories>
</project>

Now we create our folder structure, so create the following from the root folder

src/main/java/demo

We’re going to need to code within the demo package.

Without the package you might see a warning “Your ApplicationContext is unlikely to start due to a @ComponentScan of the default package.”

Next up, we’ll create a service, or in Spring parlance, the controller

package demo;

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

@RestController
public class SampleController {

    @RequestMapping("/purchaseOrder")
    public PurchaseOrderType getPurchaseOrder() {
        return new PurchaseOrderType(1234);
    }
}

The PurchaseOrderType is simply the following

package demo;

public class PurchaseOrderType {

    private long _id;

    public PurchaseOrderType(long id) {
        _id = id;
    }

    public long getId() {
        return _id;
    }
}

Now we need the application to start the service

package demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

To run this we can, ofcourse, set up a configuration or from the Terminal window run

mvn spring-boot:run

Now, if we navigate to http://localhost:8080/purchaseOrder/ we should see

{"id":1234}

Now, let’s extend this to allow us to return XML. We’ll need to annotate PurchaseOrderType with the @XmlRootElement, we’ll also need a default constructor and a setter for our Id property

package demo;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class PurchaseOrderType {

    private long _id;

    public PurchaseOrderType() {
    }

    public PurchaseOrderType(long id) {
        _id = id;
    }

    public long getId() {
        return _id;
    }

    public void setId(long id) {
        _id = id;
    }
}

Changing the port of the Tomcat server

You may have noticed that when running this application we get an instance of a Tomcat server running, by default it uses port 8080, but what about if we need/want to change this. We can create an EmbeddedServletContainerCustomizer, as below.

package demo;

import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.stereotype.Component;

@Component
public class ApplicationContainer implements EmbeddedServletContainerCustomizer {

    @Override
    public void customize(ConfigurableEmbeddedServletContainer configurableEmbeddedServletContainer) {
        configurableEmbeddedServletContainer.setPort(8888);
    }
}

Code is available here https://github.com/putridparrot/blog-projects/tree/master/spring-rest