Showing posts with label Maven. Show all posts
Showing posts with label Maven. Show all posts
Saturday, June 22, 2024

Integrate Swagger 3 with Spring Boot Rest API

 What is Swagger:

Swagger (now known as OpenAPI) is a specification for describing and documenting a REST API. It specifies the format of the REST web services including URL, resources, methods, etc. Swagger generates documentation from the application code and handles the rendering part as well.

In this post, I will integrate Swagger 3 documentation into a Spring Boot 3 based REST web service using Spring Doc OpenAPI. If you need guidance on running or building a Spring Boot project, please refer to my previous post.

Thursday, June 20, 2024

Building a RESTful Service with Spring Boot 3

 This blog post is an upgraded version of my 2017 guide on building RESTful services using Spring Boot. It includes updates for the latest Spring Boot version, best practices, and enhanced code examples. 

Creating Spring boot project is straightforward, You can create the structure of your project using "Spring Initialiser," an online tool where you can add all the desired dependencies to your project's POM file. Since I am a big fan of Maven, I generated a Maven project.

In the Spring Initializer UI, you can choose the Language, Spring Boot Version, Project Group ID, artifact name, etc. Please refer below screenshot for information I have provided while generating the project.


Spring Initialiser

When clicking on "Generate Project", it will download zipped maven project into your computer. Unzip it and import into an IDE. The initial project structure is like below.

Spring Boot Project Structure

In my HelloWorld REST service implementation, it accepts user's name as a path parameter(or URL parameter) and returns a greeting JSON payload(response). So I am expecting to invoke my REST service by calling below URL: APP_NAME/api/hello/chandana.

The @RestController is a way to implement RESTFul service using Spring. So, this new controller class is going to name as HelloWorldController. @RequestMapping annotation maps HTTP requests to the handler. This @RequestMapping annotation can be used in class-level and/or method-level as well. If you have multiple request mappings for a method or class, you can add one @RequestMapping annotation with a list of values. So my HelloWorldController class looks like below.

package com.chandana.helloworld;

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

@RestController
@RequestMapping("/api")
public class HelloWorldController {
    @RequestMapping("/")
    public String welcome() {// Welcome page, non-rest
        return "Welcome to RestTemplate Example.";
    }

    @RequestMapping("/hello/{name}")
    public Greeting message(@PathVariable String name) {
        Greeting msg = new Greeting(name, "Hello " + name);
        return msg;
    }

    @GetMapping("/greeting/{name}/{message}")
    public Greeting message(@PathVariable String name, @PathVariable String message) {
        Greeting msg = new Greeting(name, message);
        return msg;
    }

}


You can use @GetMapping, @PostMapping, @PutMapping, @DeleteMapping, @PatchMapping annotations as well, these are variation of @RequestMapping to support each HTTP methods. 


So everything is in place. you can build and run Spring Boot project using below maven command. It will compile the project and run it.

mvn spring-boot:run

Once the Spring Boot DispatcherServlet is started, you can invoke the following API URLs:

http://localhost:8080/api/hello/Alex - This API supports all HTTP methods.
http://localhost:8080/api/greeting/Alex/WelCome - This API only supports the HTTP GET method.


Final Project Structure:

Spring Boot Final Project Structure

Greeting POJO class:

package com.chandana.helloworld;

public class Greeting {
    private String player;
    private String message;

    public Greeting(String player, String message) {
        this.player = player;
        this.message = message;
    }

    public String getPlayer() {
        return player;
    }

    public void setPlayer(String player) {
        this.player = player;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}


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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.0</version>
        <relativePath/>
        <!-- lookup parent from repository -->
    </parent>
    <groupId>com.chandana</groupId>
    <artifactId>helloworld</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>Hello World</name>
    <description>Demo project for Spring Boot</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>17</java.version>
    </properties>
    <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>
    </dependencies>

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

</project>


HelloWorldController class: 

package com.chandana.helloworld;

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

@RestController
@RequestMapping("/api")
public class HelloWorldController {
    @RequestMapping("/")
    public String welcome() {// Welcome page, non-rest
        return "Welcome to RestTemplate Example.";
    }

    @RequestMapping("/hello/{name}")
    public Greeting message(@PathVariable String name) {
        Greeting msg = new Greeting(name, "Hello " + name);
        return msg;
    }

    @GetMapping("/greeting/{name}/{message}")
    public Greeting message(@PathVariable String name, @PathVariable String message) {
        Greeting msg = new Greeting(name, message);
        return msg;
    }

}


Please refrain from copying content to other websites
Saturday, October 14, 2017

Secure Spring Boot REST API using Basic Authentication

This is the third post of my Spring Boot Blog post series. In the very first post, I talked about my experience with creating RESTFul Services using Spring Boot. Then I have expanded the sample to integrate with Swagger documentation. In this post, I am going to expand above sample with security aspect.

What is API Security

API Security is a wide area with many different definitions, meanings, and solutions. The main key terms in API security are Authorization, Authentication, Encryption, Federation, and Delegation. However, I am not going to talk about each of them here.

What is Authentication

Authentication is used to reliably determine the identity of an end user and give access to the resources based on the correctly identified user.

What is Basic Authentication

Basic Authentication is the simplest way to enforce access controling to resources. Here, the HTTP user agent provides the username and the password when making a request. The string containing the username and password separated by a colon is Base64 encoded before sending to the backend when authentication is required.

How to Invoke Basic Auth Protected API

Option 1: Send Authorization header. This value is base64 encoded username:password

Ex: "Authorization: Basic Y2hhbmRhbmE6Y2hhbmRhbmE="

curl -X GET http://localhost:8080/admin/hello/chandana -H 'authorization: Basic Y2hhbmRhbmE6Y2hhbmRhbmE='

Option 2: Using URL:

curl -X GET -u username:password  http://localhost:8080/admin/hello/chandana


OK, we talked about basic stuff. So let's move to see how to secure a REST API using Spring Security. You can download the initial sample code from my GitHub repo(Swagger Spring Boot Project source code)

To enhance our previous sample with basic auth security, first I am going to add "spring-boot-starter-security" and "spring-boot-starter-tomcat" dependencies into the pom file.

        <!-- -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>

Next step is that our configuration class is annotated with @EnableWebSecurity annotation and configuration class is extended from the WebSecurityConfigurerAdapter. The EnableWebSecurity annotation will enable Spring-Security web security support.

@Configuration
@EnableSwagger2
@EnableWebSecurity
public class ApplicationConfig extends WebSecurityConfigurerAdapter {

Overridden configure(HttpSecurity) method is used to define which URL paths should be secured and which should not be. In my example "/" and "/api" paths are not required any authentication and any other paths(ex:  "admin") should be authenticated with basic auth.

@Override
protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.authorizeRequests().antMatchers("/", "/api/**").permitAll()
        .anyRequest().authenticated();
        http.httpBasic().authenticationEntryPoint(basicAuthenticationPoint);
}

In the configureGlobal(AuthenticationManagerBuilder) method, I have created an in-memory user store with a user called 'chandana'. There I have added username, password, and userole for the in-memory user.

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("chandana").password("chandana").roles("USER");
    }

In Addition to that, you can see that I have added autowired BasicAuthenticationPoint, into my config class. Purpose of the BasicAuthenticationEntryPoint class is to set the "WWW-Authenticate" header to the response. So, web browsers will display a dialog to enter usename and password based on basic authentication mechanism(WWW-Authenticate header)

Then you can run the sample using "mvn spring-boot:run". When you are accessing "localhost:8080/api/hello/chandana" basic authentication is not required to invoke the api. However, if you try to access the "localhost:8080/admin/hello/chandana" it will be required to provide basic auth credentials to access the resource.

AppConfig class:

 package com.chandana.helloworld.config;  
 import org.springframework.beans.factory.annotation.Autowired;  
 import org.springframework.context.annotation.Bean;  
 import org.springframework.context.annotation.Configuration;  
 import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;  
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;  
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;  
 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;  
 import springfox.documentation.builders.ApiInfoBuilder;  
 import springfox.documentation.builders.PathSelectors;  
 import springfox.documentation.builders.RequestHandlerSelectors;  
 import springfox.documentation.service.ApiInfo;  
 import springfox.documentation.service.Contact;  
 import springfox.documentation.spi.DocumentationType;  
 import springfox.documentation.spring.web.plugins.Docket;  
 import springfox.documentation.swagger2.annotations.EnableSwagger2;  
 @Configuration  
 @EnableSwagger2  
 @EnableWebSecurity  
 public class ApplicationConfig extends WebSecurityConfigurerAdapter {  
   @Autowired  
   private BasicAuthenticationPoint basicAuthenticationPoint;  
   @Bean  
   public Docket api() {  
     return new Docket(DocumentationType.SWAGGER_2)  
         .apiInfo(getApiInfo())  
         .select()  
         .apis(RequestHandlerSelectors.basePackage("com.chandana.helloworld.controllers"))  
         .paths(PathSelectors.any())  
         .build();  
   }  
   @Override  
   protected void configure(HttpSecurity http) throws Exception {  
     http.csrf().disable();  
     http.authorizeRequests().antMatchers("/", "/api/**").permitAll()  
     .anyRequest().authenticated();  
     http.httpBasic().authenticationEntryPoint(basicAuthenticationPoint);  
   }  
   private ApiInfo getApiInfo() {  
     Contact contact = new Contact("Chandana Napagoda", "http://blog.napagoda.com", "cnapagoda@gmail.com");  
     return new ApiInfoBuilder()  
         .title("Example Api Title")  
         .description("Example Api Definition")  
         .version("1.0.0")  
         .license("Apache 2.0")  
         .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0")  
         .contact(contact)  
         .build();  
   }  
   @Autowired  
   public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {  
     auth.inMemoryAuthentication().withUser("chandana").password("chandana").roles("USER");  
   }  
 }  

BasicAuthenticationEntryPoint  class:

 package com.chandana.helloworld.config;  
 import org.springframework.security.core.AuthenticationException;  
 import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;  
 import org.springframework.stereotype.Component;  
 import java.io.IOException;  
 import java.io.PrintWriter;  
 import javax.servlet.ServletException;  
 import javax.servlet.http.HttpServletRequest;  
 import javax.servlet.http.HttpServletResponse;  
 @Component  
 public class BasicAuthenticationPoint extends BasicAuthenticationEntryPoint {  
   @Override  
   public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authEx)  
       throws IOException, ServletException {  
     response.addHeader("WWW-Authenticate", "Basic realm=" +getRealmName());  
     response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);  
     PrintWriter writer = response.getWriter();  
     writer.println("HTTP Status 401 - " + authEx.getMessage());  
   }  
   @Override  
   public void afterPropertiesSet() throws Exception {  
     setRealmName("Chandana");  
     super.afterPropertiesSet();  
   }  
 }  

You can download Spring Boot Basic Auth Project source code from my GitHub repo as well.

Tuesday, September 12, 2017

Integrating Swagger with Spring Boot REST API

Update Notice: This blog post was published on 2017 and may contain outdated information. For the most up-to-date guide on integrating Swagger with Spring Boot REST API, please refer to my latest post : https://blog.napagoda.com/2024/06/integrate-swagger-3-with-spring-boot3-api.html 

In the last post, I talked about my experience with creating RESTFul Services using Spring Boot. When creating a REST API, proper documentation is a mandatory part of it.

What is Swagger?

Swagger(Swagger 2) is a specification for describing and documenting a REST API. It specifies the format of the REST web services including URL, Resources, methods, etc. Swagger will generate documentation from the application code and handle the rendering part as well.

In this post, I am going to integrate Swagger 2 documentation into a Spring Boot based REST web service. So I am going to use Springfox implementation to generate the swagger documentation. If you want to know how to run/build Spring Boot project, please refer my previous post.

Springfox provides two dependencies to generate API Doc and Swagger UI. If you are not expecting to integrate Swagger UI into your API level, no need to add  Swagger UI dependency.

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.7.0</version>
</dependency>

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.7.0</version>
</dependency>


@EnableSwagger2 annotation enables Springfox Swagger support in the class.  To document the service, Springfox uses a Docket. The Docket helps to configure a subset of the services to be documented and group them by a name, etc. The most hidden concept is that the Springfox works by examining an application at runtime using API semantics based on spring configurations. In other words, you have to create a Spring Java Configuration class which uses spring’s @Configuration

In My example, I am generating a swagger documentation based on the RestController classes I have added.



import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class ApplicationConfig {

    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.chandana.helloworld.controllers"))
                .paths(PathSelectors.any())
                .build();
    }
}


Since I have added two controllers, this will group(tag) each controller related APIs separately.

Generated Swagger UI


Out of the box, Springfox  provides five predicates and they are any, none, withClassAnnotation, withMethodAnnotation and basePackage.

ApiInfo

Swagger provides some default values such as “API Documentation”, “Created by Contact Email”, “Apache 2.0”. So you can change these default values by adding apiInfo(ApiInfo apiInfo) method. The ApiInfo class contains custom information about the API.


@Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(getApiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.chandana.helloworld.controllers"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo getApiInfo() {
        Contact contact = new Contact("Chandana Napagoda", "http://blog.napagoda.com", "cnapagoda@gmail.com");
        return new ApiInfoBuilder()
                .title("Example Api Title")
                .description("Example Api Definition")
                .version("1.0.0")
                .license("Apache 2.0")
                .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0")
                .contact(contact)
                .build();
    }


Once ApiInfo is added, the generated documentation looks similar to this:

Swagger UI with App Info


Controller and POJO Level Documentation

@Api annotation is used to explain each rest controller class.
@ApiOperation annotation is used to explain to describe the resources and methods.
@ApiResponse annotation  is used to explain to describe other responses that can be returned by the operation.ex: 200 ok or 202 accepted, etc.
 @ApiModelProperty annotation to describe the properties of the POJO(Bean) class.

After adding above annotation, final generated swagger documentation looks like below:

Complex and Beautiful REST Documentation with Swagger


Spring RestController class:


package com.chandana.helloworld.controllers;

import com.chandana.helloworld.bean.Greeting;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
@Api(value = "user", description = "Rest API for user operations", tags = "User API")
public class HelloWorldController {

    @RequestMapping(value = "/hello/{name}", method = RequestMethod.GET, produces = "application/json")
    @ApiOperation(value = "Display greeting message to non-admin user", response = Greeting.class)
    @ApiResponses(value = {
            @ApiResponse(code = 200, message = "OK"),
            @ApiResponse(code = 404, message = "The resource not found")
    }
    )
    public Greeting message(@PathVariable String name) {
        Greeting msg = new Greeting(name, "Hello " + name);
        return msg;
    }
}

Greeting model class:


package com.chandana.helloworld.bean;

import io.swagger.annotations.ApiModelProperty;

public class Greeting {

    @ApiModelProperty(notes = "Provided user name", required =true)
    private String player;

    @ApiModelProperty(notes = "The system generated greeting message" , readOnly =true)
    private String message;

    public Greeting(String player, String message) {
        this.player = player;
        this.message = message;
    }

    public String getPlayer() {
        return player;
    }

    public void setPlayer(String player) {
        this.player = player;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

AppConfig class:


package com.chandana.helloworld.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class ApplicationConfig {

    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(getApiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.chandana.helloworld.controllers"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo getApiInfo() {
        Contact contact = new Contact("Chandana Napagoda", "http://blog.napagoda.com", "cnapagoda@gmail.com");
        return new ApiInfoBuilder()
                .title("Example Api Title")
                .description("Example Api Definition")
                .version("1.0.0")
                .license("Apache 2.0")
                .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0")
                .contact(contact)
                .build();
    }
}

You can download Swagger Spring Boot Project source code from my GitHub repo as well.

Friday, September 08, 2017

Building a RESTFul Service using Spring Boot

Update Notice: This blog post was published on 2017 and may contain outdated information. For the most up-to-date guide on developing RESTful services with Spring Boot, please refer to my latest post: https://blog.napagoda.com/2024/06/building-restful-service-spring-boot-3.html Thank you!

Everyone is talking about Microservices such as WSO2 Microservice Framework, Spring Boot, etc. Since I haven't worked on any Spring related project since a very long time, I thought to implement a simple RESTFul service using Spring Boot.

So I started with Spring documentation. It is straightforward.  You can create the structure of your project using "Spring Initializr". This is an online tool where you can add all the desired dependencies to your project POM file. Since I am a big fan of Maven, I am generating a maven project.

In the Spring Initializr UI, you can choose the Language, Spring Boot Version, Project Group ID, artifact name, etc. Please refer below screenshot for information I have provided while generating the project.

Spring Initializr view


When clicking on "Generate Project", it will download zipped maven project into your computer. Unzip it and import into an IDE. The initial project structure is like below.


Spring Boot project view

In my HelloWorld REST service implementation, it accepts user's name as a path parameter(or URL parameter) and returns a greeting JSON payload(response). So I am expecting to invoke my REST service by calling below URL: APP_NAME/api/hello/chandana.

The @RestController is a way to implement RESTFul service using Spring. So, this new controller class is going to name as HelloWorldController. @RequestMapping annotation maps HTTP requests to the handler. This @RequestMapping annotation can be used in class-level and/or method-level as well. If you have multiple request mappings for a method or class, you can add one @RequestMapping annotation with a list of values. So my HelloWorldController class looks like below.


package com.chandana.helloworld;

import com.chandana.helloworld.bean.Greeting;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class HelloWorldController {

    @RequestMapping("/")
    public String welcome() {//Welcome page, non-rest
        return "Welcome to RestTemplate Example.";
    }

    @RequestMapping("/hello/{name}")
    public Greeting message(@PathVariable String name) {

        Greeting  msg = new Greeting(name, "Hello " + name);
        return msg;
    }

}

Note: If you notice Spring Boot 1.5.6 not importing classes correctly and displaying an error message as "Cannot resolve symbol RestController" in your IDE, you need to downgrade the spring version that is used in the project. Spring Boot 1.5.6 by default uses Spring 4.3.10.RELEASE dependency and it need to be downgraded to 4.3.9.RELEASE. So please add <spring.version>4.3.9.RELEASE</spring.version> on the properties section of your POM file.

So everything is in place. I can build and run Spring Boot project using below maven command. It will compile the project and run it.

mvn spring-boot:run

While starting the server you can notice registered REST service URL in the console like below

INFO 9556 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/api/hello/{name}]}" onto public com.chandana.helloworld.bean.Greeting com.chandana.helloworld.HelloWorldController.message(java.lang.String)
INFO 9556 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/api/]}" onto public java.lang.String com.chandana.helloworld.HelloWorldController.welcome()2017-0
Finally, Can invoke REST Service by accessing this URL: http://localhost:8080/api/hello/NAME

Final Project Structure:

Spring Boot REST API project view


Greeting POJO class:


package com.chandana.helloworld.bean;

public class Greeting {

    private String player;
    private String message;

    public Greeting(String player, String message) {
        this.player = player;
        this.message = message;
    }

    public String getPlayer() {
        return player;
    }

    public void setPlayer(String player) {
        this.player = player;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

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>com.chandana</groupId>
 <artifactId>helloworld</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>jar</packaging>

 <name>helloworld</name>
 <description>Demo project for Spring Boot</description>

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

 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  <java.version>1.8</java.version>
  <spring.version>4.3.9.RELEASE</spring.version>
 </properties>

 <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>
 </dependencies>

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


</project>

HelloWorldController class:


package com.chandana.helloworld;

import com.chandana.helloworld.bean.Greeting;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class HelloWorldController {

    @RequestMapping("/")
    public String welcome() {//Welcome page, non-rest
        return "Welcome to RestTemplate Example.";
    }

    @RequestMapping("/hello/{name}")
    public Greeting message(@PathVariable String name) {

        Greeting  msg = new Greeting(name, "Hello " + name);
        return msg;
    }

}

Conclusion: As it seems, it is very straightforward to implement RESTFul services using Spring Boot. So I got an idea to implement backend of my “Yield Price Sri Lanka” android app using Spring Boot. Besides, hoping to implement an Admin UI to manage price and commodity information and also a public web UI to display price details for users who don't have an Android app. Keep in touch.

Wednesday, August 10, 2016

Maven Compiler Plugin

The Maven Compiler Plugin is used to compile the Java source code of your project. The default compiler is `javac`, which is used to compile Java sources. By modifying the `pom.xml` file, you can customize the default behavior of the Maven Compiler Plugin.

Using Maven Compiler Plugin, you can compile the source code of a certain project to a different version of JVM than what you are currently using. EX: compile using JDK 1.8 and target JVM is 1.7. Default source setting is JDK 1.5, and the default target setting is JDK 1.5

Example configuration is as below: 

<build>
    <plugins>
        <plugin>
           <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.5.1</version>
            <configuration>
                <source>1.7</source>
                <target>1.7</target>
            </configuration>
        </plugin>
    </plugins>
</build>
Wednesday, February 11, 2015

Writing a Create API Executor for API.RXT

One of the use cases of the WSO2 Governance Registry is storing metadata information of different artifacts. In an Organization, there can be different metadata of different artifacts such their REST APIs, SOAP Services etc. In such a scenario you can use API and Service RXT which are available in the WSO2 Governance Registry to store metadata information.

With the use of API metadata which is stored in the WSO2 Governance Registry, you can publish APIs into WSO2 API Manager without accessing the web interface of the API Manager. This API creation is handled through lifecycle executor of the WSO2 Governance Registry. Once lifecycle state of the api publisher is reached, the executor will invoke Publisher REST API of the WSO2 API Manager and create the API. "Integrating with WSO2 API Manager" documentation explains about how to create an API using SOAP service meta data information.

If you want to create an API using the REST API metadata information available in the WSO2 Governance Registry, you have to write your own executor to achieve this. So I have written an example Implementation of the lifecycle executor which can used to create API's in the API Manager.

Wednesday, October 08, 2014

Maven excludes all transitive dependencies

Transitive dependencies are a new feature in Maven 2.0. This feature allows you to avoid the need to discover and specify the libraries that your own dependencies require, as they are included automatically.

I encountered a problem where some dependencies were available at runtime, but they weren't available in the public Nexus repositories. For example, Hibernate depends on the Sun JTA API JAR, which is not available in the central Maven repository because it cannot be freely redistributed. Consequently, when building the project, it tried to download transitive dependencies and failed.

To address this issue, I looked for a way to ignore all transitive dependencies and found that we can ignore all associated dependencies of a given dependency. There we can exclude all transitive dependencies without specifying groupId and artifactId of the dependencies. So need to use astric(*) character as groupid and artifactid of the dependency.

<dependency>
    <groupId>sample.ProjectA</groupId>
    <artifactId>Project-A</artifactId>
    <version>1.0</version>
    <scope>compile</scope>
    <exclusions>
        <exclusion>
            <groupId>*</groupId>
            <artifactId>*</artifactId>
        </exclusion>
    </exclusions>
</dependency>


This wildcard transitive dependencies ignoring is available with maven 3.2.1 release. So it's worth to upgrade into latest maven version.
Wednesday, June 20, 2012

Build Maven Multi Module Project and Run using one Command

When we have maven multi module project, there will be dependency between sub project. Therefor if you need to build all projects need tp navigate to parent directory and run the mvn clean install command.

If we have web based multi module project, currently most people doing is go to parent directory and build the all projects using mvn install or mvn clean install command, after that navigate to web project and start web container.

Ex: Projects are P1(parent project), Core and Web. When we building project go to P1 and build the all subprojects, after that go to web project and start jetty server using mvn jetty:run

But that approach wasting you time little bit and when we doing same thing all the time it will become boring  task to do(build parent and go to child folder and run the server)

For avoid this issue I am going to show how to run web project with out navigate to child project.

following command will help you to run specific project without moving to sub project folder.

mvn -amd clean install -pl WebProject jetty:run-exploded


Tuesday, May 15, 2012

Change Jetty Server Running Port ( 2026 Update)

Update (September 2026): This post was originally written in May 2012 and the original content is preserved below, with the current instructions for 2026 added after it.

Jetty is one one of the best development server which I have ever used. It is easy to work with jetty server and its light weight

Here I am going to show how to change jetty server running port.  Jetty server default running port is 8080.
Wednesday, April 04, 2012

Maven add jar without install

I have some problem with adding external jar in to maven project without install it. If I install JAR file other people who working on same project, have to install same JAR. them I want to avoid that issue.

First need to place jar file inside lib folder. After that using following POM entry we can use it as dependency.

<dependency>
   <groupId>com.chandana</groupId>
   <artifactId>example</artifactId>
   <version>0.1</version>
   <scope>system</scope>
   <systemPath>${basedir}/lib/example.0.1.jar</systemPath>
</dependency>


Ex:
<dependency>
   <groupId>com.sun</groupId>
   <artifactId>tools</artifactId>
   <version>1.5.0</version>
   <scope>system</scope>
   <systemPath>${JAVA_HOME}/lib/tools.jar</systemPath>
</dependency>

 Here very important option is <scope>system</scope>. It's say dependency provide with system, no need to look at repository. More about System Dependency




Friday, February 17, 2012

Maven commands and hint

svn checkout without subfolders

svn co --depth immediates URL
maven without internet(Without downloading)

mvn -o install
mvn --offline install

Force the check of the latest dependency jars
mvn -U install
mvn --update-snapshots install

*** -U option to update your snapshots

Skip the tests

mvn install -DskipTests

also use the maven.test.skip property to skip compiling the tests

mvn install -Dmaven.test.skip=true

Remote Debug

mvnDebug test
mvnDebug install


To avoid OutOfMemoryError

To avoid OutOfMemoryError when running maven, set environment variable MAVEN_OPTS as below

MAVEN_OPTS=-Xmx1024m -XX:MaxPermSize=256m


If you have issue with Maven does not find JUnit test cases to run:
By default Maven runs tests class which names start with Test or end with Test or TestCase.Do not messed up the naming convention

Friday, November 11, 2011

How to debug using Maven Jetty

Debugging is a better approach to find out bugs in our programs. Here is a way to debug a maven project, and I am going to run my web application in the Jetty server.

First you need to add the following environmental variables on your Windows/Linux environment.

MAVEN_OPTS = -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=4000,server=y,suspend=y

Now go to your maven web project location through command line and start the jetter server -> mvn jetty:run



Now in eclipse debug configuration, add a remote Java application instance on port 4000. Then Add some debug points to your codes  and start the remote app instance on debug mode. You can see the steps from following screen shots.





In this manner you can debug your java web apps and find out the bugs. With this way you can debug your java web app.

if you are using maven latest version( Maven 2.0.8 or later)

run the
 mvnDebug  
command instead of
 mvn 
and attach a debugger on port 8000.

Love to hear from you! feedback(comments) are always welcome 
Thursday, January 28, 2010

Spring-Hibernate Maven project- Part 3

Hibernate Configuration and Project Deployment


In the previous post I created the hibernate mapping files for the Person-Address domain classes. In here we are going to create the hibernate configuration file which creates the database connection according to the defined URL, credentials and other properties.

On the deplyment of the project, the hibernate configuration file is executed through the commands in pom.xml.

We have to put the hibernate configuration file inside the src/main/resources directory. For that right cick on the directory, select new, select other. From there expand the hibernate icon and select Hibernate Configuration file (cfg.xml).

Click Next

Keep the default name "hibernate.cfg.xml" same and click Next
Give the values in the appeared window give the values as follows.

Make sure to verify your mysql username and password, and enter the corret one according to your mysql configuration.

hibernate.cfg.xml
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">
com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.password">
root</property>
        <property name="hibernate.connection.url">
jdbc:mysql://localhost:3306/testdb1</property>
        <property name="hibernate.connection.username">
root</property>
        <property name="hibernate.dialect">
org.hibernate.dialect.MySQLDialect</property>
        
        <mapping resource="hibernate/Person.hbm.xml">
        <mapping resource="hibernate/Address.hbm.xml">
    </mapping>
</mapping>
</session-factory></hibernate-configuration>
Add the mapping resource entries to your hibernate.cfg.xml file as above.
Here is the directory structureof the project after the hibernate.config.xml file is being added.



Let's add the build elements to the pom.xml file to execute the mapping files and create the tables accordingly.

append the following etries to the pom.xml file inside the project tags.
 <build>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
     <source>1.5</source>
     <target>1.5</target>
    </configuration>
   </plugin>
   <plugin>
    <artifactId>maven-resources-plugin</artifactId>
   </plugin>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-eclipse-plugin</artifactId>
    <version>2.7</version>
   </plugin>
   <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>hibernate3-maven-plugin</artifactId>
   </plugin>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-source-plugin</artifactId>
    <version>3.0.1</version>
    <configuration>
     <outputDirectory>target</outputDirectory>
     <finalName>
      <attach>false</attach>
     </finalName>
     <executions>
      <execution>
       <id>make-source-jar</id>
       <phase>package</phase>
       <goals>
        <goal>jar</goal>
       </goals>
      </execution>
     </executions>
    </configuration>
    <plugin>
     <groupId>org.codehaus.mojo</groupId>
     <artifactId>hibernate3-maven-plugin</artifactId>
     <version>2.2</version>
     <executions>
      <execution>
       <phase>process-classes</phase>
       <goals>
        <goal>hbm2ddl</goal>
       </goals>
      </execution>
     </executions>
     <dependencies>
      <dependency>
       <groupId>hsqldb</groupId>
       <artifactId>hsqldb</artifactId>
       <version>1.8.0.7</version>
      </dependency>
      <dependency>
       <groupId>mysql</groupId>
       <artifactId>mysql-connector-java</artifactId>
       <version>5.1.6</version>
      </dependency>
     </dependencies>
     <configuration>
      <component>
       <name>hbm2ddl</name>
      </component>
      <componentproperties>
       <configurationfile>target/classes/hibernate.cfg.xml
       </configurationfile>
       <outputfilename>schema.sql</outputfilename>
       <export>true</export>
       <format>true</format>
       <drop>true</drop>
       <haltonerror>false</haltonerror>
      </componentproperties>
     </configuration>
    </plugin>
    <plugin>
     <artifactId>maven-checkstyle-plugin</artifactId>
    </plugin>
   </plugin>
  </plugins>
 </build>

It is ready to execute the project and one more thing left. Go to mysql command line and create a database called testdb1.


Deploying the project

Right click on the project and goto run as--maven install

In the maven console you can examine the execution. It will display the sql of the tables created. If you have followed the things correctly at the end it will display BUILD SUCCESSFUL.


Inside the target directory hibernate/sql will contain the scema.sql file which is a dump file of the created tables. Also the jar files are created. (testapp-0.0.1-SNAPSHOT.jar and tetsapp-0.0.1-SNAPSHOT-source.jar is created)

 
The tables can be viewed through mysql command line.



Comments and Questions are wel come

View Counts

Followers