How to setup a basic SpringBoot application

I spent some time trying to figure out how SpringBoot worked recently. I thought I would document the steps I took to get a project up and running.

Here is the final repository in Github.

Setup Steps

  1. First, create a workspace.

    mkdir -p ~/projects

    cd ~/projects

    mvn archetype:generate -DgroupId=com.tonyzampogna -DartifactId=base-springboot-app -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

    cd ~/projects/base-springboot-app

  2. In the pom.xml, add the Spring Boot dependencies. First, add the parent block. I put it above the dependencies block.

      <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
      </parent>
    

  3. Then, in the dependencies block, add the following 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>
    

  4. Add the plugin for building SpringBoot with maven. This goes either above or below the dependencies block. This solves an error stating: "no main manifest attribute".

      <build>
        <plugins>
          <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <executions>
              <execution>
                <goals>
                  <goal>repackage</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
    

  5. Move the App.java file in src/main/java/com/tonyzampogna to a new package called "main".

    mkdir -p src/main/java/com/tonyzampogna/main

    mv src/main/java/com/tonyzampogna/App.java src/main/java/com/tonyzampogna/main

  6. Replace the contents of the App.java file with the text below.

      package com.tonyzampogna.main;
    
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      import org.springframework.context.annotation.ComponentScan;
    
      /**
       * Main application file.
       */
      @SpringBootApplication
      @ComponentScan("com.tonyzampogna")
      public class App {
        private static final Logger logger = LoggerFactory.getLogger(App.class);
    
        /////////////////////////////////////////////////
        // Application Start Methods
        /////////////////////////////////////////////////
    
        /**
         * This method runs on applications start.
         */
        public static void main(String[] args) {
          logger.info("Starting application");
          SpringApplication.run(App.class, args);
        }
      }
    

  7. Make a controller so that we can test our server. First, create the package directory.

    mkdir -p src/main/java/com/tonyzampogna/controller

  8. Then, add HomeController.java code to the controller package.

      package com.tonyzampogna.controller;
    
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
    
      @RestController
      public class HomeController {
    
        @RequestMapping("/home")
        public String getHome() {
          return "Hello";
        }
      }
    

  9. Create a resources directory for a log4j properties file.

    mkdir -p src/main/resources

  10. Add the log4.properties file below to src/main/resources.

      #################################################################
      ## Log Levels
      #################################################################
    
      log4j.rootLogger=INFO, STDOUT
      log4j.logger.com.tonyzampogna=DEBUG, STDOUT, FILE
    
    
      #################################################################
      ## Appenders
      #################################################################
    
      # Console
      log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender
      log4j.appender.STDOUT.layout=org.apache.log4j.PatternLayout
      log4j.appender.STDOUT.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
    
      # File
      log4j.appender.FILE=org.apache.log4j.RollingFileAppender
      log4j.appender.FILE.File=application.log
      log4j.appender.FILE.MaxFileSize=10MB
      log4j.appender.FILE.MaxBackupIndex=10
      log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
      log4j.appender.FILE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
    

To run the project (from either Eclipse, Intellij, or the command line):

From the command line

  1. In the project directory, package the jar file and then run it.

    mvn package

    java -jar target/base-springboot-app-1.0-SNAPSHOT.jar

From Eclipse

  1. First, run the maven eclipse target to setup some essential eclipse files.

    mvn eclipse:eclipse

  2. Open Eclipse. Make sure you get the SpringSource Tool Suite from the Eclipse Marketplace. Then, import the project into the workspace as an existing eclipse project.

  3. Now, you can right-click on the project and choose either "Run as SpringBoot application" or "Debug as SpringBoot application".

From Intellij

  1. Open Intellij and choose File -> New Project.

  2. Select Java project and choose Next.

  3. For project name, type in base-springboot-app. For project location, type in ~/projects/base-springboot-app.

  4. In the Run menu, choose Edit Configurations. Click the plus sign and select JAR Application. Fill in the information below.

    • Name: Server
    • Path to JAR: ~/projects/base-springboot-app/target/base-springboot-app-1.0-SNAPSHOT.jar
    • VM Arguments: -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1044
    • Working directory: ~/projects/base-springboot-app
  5. Select ok.

  6. Now, from the Run menu, you can choose either

Selecting Popup Windows in Selenium

This example shows how to start a Selenium Server and run a Selenium client in Java. The example opens up a popup window by clicking on the link in index.html. It then selects the popup window by first using the "name=popupWindowName" option for selectWindow. It then grabs the original window (using "name=null"). And, finally, it grabs the popup again by using the global javascript variable option in selectWindow ("var=popupWindowVar").

In order to run this test, you will need the following three jar files on your classpath.

  • junit-4.8.2.jar
  • selenium-java-2.17.0.jar
  • selenium-server-standalone-2.17.0.jar

Unit Test

package org.example;

import static org.junit.Assert.assertEquals;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.openqa.selenium.server.RemoteControlConfiguration;
import org.openqa.selenium.server.SeleniumServer;

import com.thoughtworks.selenium.DefaultSelenium;

public class SeleniumIntegrationTest {
	private static SeleniumServer server = null;
	private DefaultSelenium selenium = null;

	@BeforeClass
	public static void oneTimeSetUp() throws Exception {
		// Create a configuration to override defaults.
		RemoteControlConfiguration rcc = new RemoteControlConfiguration();
		rcc.setTimeoutInSeconds(60);
		rcc.setPort(4444);
		rcc.setSingleWindow(true); // Support Popups
		rcc.setTrustAllSSLCertificates(true); // Trust SSL

		// Start the Selenium Server.
		server = new SeleniumServer(false, rcc);
		server.start();
	}

	@AfterClass
	public static void oneTimeTearDown() throws Exception  {
		server.stop();
	}

	@Before
	public void setUp() throws Exception {
//		// Create a Selenium thread.
//		// Open in Chrome
//		selenium = new DefaultSelenium("localhost", 4444,
//				"*googlechrome",
//				"http://localhost:8080/GrailsDefault/");
//		// Open in Safari
//		selenium = new DefaultSelenium("localhost", 4444,
//				"*safari C:\\Program Files (x86)\\Safari\\Safari.exe",
//				"http://localhost:8080/GrailsDefault/");
//		// Open in IE
//		selenium = new DefaultSelenium("localhost", 4444,
//				"*iexplore",
//				"http://localhost:8080/GrailsDefault/");
		// Open in Firefox
		selenium = new DefaultSelenium("localhost", 4444,
				"*firefox3",
				"http://localhost:8080/GrailsDefault/");

		// Start the server
		selenium.start();
	}

	@After
	public void tearDown() {
		// Stop the Selenium thread.
		selenium.stop();
	}

	@Test
	public void popupWindowExample() {
		// Open the base window.
		selenium.open("index.html");
		assertEquals(selenium.getTitle(), "Popup Window Example");

		// Click button to popup new window.
		selenium.click("id=popupButton");
		// Select the popup window.
		// popupWindowID is the ID given in the window.open javascript.
		selenium.waitForPopUp("popupWindowID", "30000");
		selenium.selectWindow("name=popupWindowID");
		assertEquals(selenium.getTitle(), "Popped Up Window");

		// Click a link to google on the popup.
		selenium.click("link=This link goes to google");
		selenium.waitForPageToLoad("30000");
		assertEquals(selenium.getTitle(), "Google");

		// Select the original window.
		selenium.selectWindow("null");
		assertEquals(selenium.getTitle(), "Popup Window Example");

		// Select the window by a javascript variable.
		selenium.selectWindow("var=popupWindowVar");
		assertEquals(selenium.getTitle(), "Google");
	}

}

index.html

<html>
<head>
<title>Popup Window Example</title>

<script>
function popupNewWindow() {
	window.popupWindowVar = window.open("popup.html", "popupWindowID");
}
function popupNewWindow2() {
	window.popupWindowVar2 = window.open("popup.html", "popupWindowID2");
}
</script>

</head>

<body>
	<div id="header">
		<button id="popupButton" onclick="popupNewWindow()">Popup Window</button>
		<button id="popupButton2" onclick="popupNewWindow2()">Popup Window 2</button>
	</div>
</body>
</html>

popup.html

<html>
<head>
<title>Popped Up Window</title>
</head>

<body>
	<div id="header">
		This is a popup window.
	</div>
	<div id="links">
		<a href="http://www.google.com">This link goes to google</a>.
	</div>
</body>
</html>

I found a bug in the variation of selectWindow that tries to grab the window from a JavaScript variable (i.e "var=foo"). It works in Chrome and IE. However, I could not get it working with Firefox 9.0.1 with Windows 7. The error is below. I've opened up a defect. The bug is listed here: http://code.google.com/p/selenium/issues/detail?id=3270.

com.thoughtworks.selenium.SeleniumException: ERROR: Window does not exist. If this looks like a Selenium bug, make sure to read http://seleniumhq.org/docs/04_selenese_commands.html#alerts-popups-and-multiple-windows for potential workarounds.
        at com.thoughtworks.selenium.HttpCommandProcessor.throwAssertionFailureExceptionOrError(HttpCommandProcessor.java:112)
        at com.thoughtworks.selenium.HttpCommandProcessor.doCommand(HttpCommandProcessor.java:106)
        at com.thoughtworks.selenium.DefaultSelenium.selectWindow(DefaultSelenium.java:370)
        at org.example.SeleniumIntegrationTest.popupWindowExample(SeleniumIntegrationTest.java:99)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

How to get JAX-WS Web Service Method Name

I'm not sure if this will always work, but here is some sample code that I put into a Handler to log the web service method name that is being called. I wanted to be able to track each method, and see which ones were getting use.

This web service was running on IBM WebSphere 6.1.


public boolean handleMessage(LogicalMessageContext context) {
	String webMethodOperationName = null;
	try {
		Field mepCtxField = context.getMessage().getClass().getDeclaredField("mepCtx");
		mepCtxField.setAccessible(true);
		Object mepCtx = mepCtxField.get(context.getMessage());
		
		Field requestMCField = mepCtx.getClass().getDeclaredField("requestMC");
		requestMCField.setAccessible(true);
		Object requestMC = requestMCField.get(mepCtx);
		
		Field operationDescField = requestMC.getClass().getDeclaredField("operationDesc");
		operationDescField.setAccessible(true);
		Object operationDesc = operationDescField.get(requestMC);
		
		Field webMethodOperationNameField = operationDesc.getClass().getDeclaredField("webMethodOperationName");
		webMethodOperationNameField.setAccessible(true);
		webMethodOperationName = (String) webMethodOperationNameField.get(operationDesc);
	}
	catch (Exception e) {
		log.warn("Cannot find method name of operation.");
	}
	
	System.out.println(webMethodOperationName);
	
	return true;
}