Boot

Spring Boot Composite Key Example

Welcome, in this tutorial, we will see how to implement a composite key in a spring boot application. We will use the @Embeddable and @EmbeddedId annotations.

1. Introduction

Before going further in this tutorial, we will look at the common terminology such as introduction to Spring Boot and Lombok.

1.1 Spring Boot

  • Spring boot is a module that provides rapid application development feature to the spring framework including auto-configuration, standalone-code, and production-ready code
  • It creates applications that are packaged as jar and are directly started using embedded servlet container (such as Tomcat, Jetty or, Undertow). Thus, no need to deploy the war files
  • It simplifies the maven configuration by providing the starter template and helps to resolve the dependency conflicts. It automatically identifies the required dependencies and imports them into the application
  • It helps in removing the boilerplate code, extra annotations, and XML configurations
  • It provides powerful batch processing and manages the rest endpoints
  • It provides an efficient JPA-starter library to effectively connect the application with the relational databases
  • It offers a Microservice architecture and cloud configuration that manages all the application related configuration properties in a centralized manner

1.2 Lombok

  • Lombok is nothing but a small library that reduces the amount of boilerplate Java code from the project
  • Automatically generates the getters and setters for the object by using the Lombok annotations
  • Hooks in via the Annotation processor API
  • Raw source code is passed to Lombok for code generation before the Java Compiler continues. Thus, produces properly compiled Java code in conjunction with the Java Compiler
  • Under the target/classes folder you can view the compiled class files
  • Can be used with Maven, Gradle IDE, etc.

1.2.1 Lombok features

FeatureDetails
valLocal variables are declared as final
varMutable local variables
@Slf4JCreates an SLF4J logger
@CleanupWill call close() on the resource in the finally block
@GetterCreates getter methods for all properties
@SetterCreates setter for all non-final properties
@EqualsAndHashCode
  • Generates implementations of equals(Object other) and hashCode()
  • By default will use all non-static, non-transient properties
  • Can optionally exclude specific properties
@ToString
  • Generates String of class name, and each field separated by commas
  • Optional parameter to include field names
  • Optional parameter to include a call to the super toString method
@NoArgsConstructor
  • Generates no-args constructor
  • Will cause compiler error if there are final fields
  • Can optionally force, which will initialize final fields with 0/false/null var – mutable local variables
@RequiredArgsContructor
  • Generates a constructor for all fields that are final or marked @NonNull
  • The constructor will throw a NullPointerException if any @NonNull fields are null val – local variables are declared final
@AllArgsConstructor
  • Generates a constructor for all properties of the class
  • Any @NotNull properties will have null checks
@Data
  • Generates typical boilerplate code for POJOs
  • Combines – @Getter, @Setter, @ToString, @EqualsAndHashCode, @RequiredArgsConstructor
  • No constructor is generated if constructors have been explicitly declared
@Builder
  • Implements the Builder pattern for object creation
@Value
  • The immutable variant of @Data
  • All fields are made private and final by default

Let us go ahead with the tutorial implementation but before going any further I’m assuming that you’re aware of the Spring boot basics.

2. Spring Boot Composite Key Example

2.1 Tools Used for Spring boot application and Project Structure

We are using Eclipse Kepler SR2, JDK 8, and Maven. In case you’re confused about where you should create the corresponding files or folder, let us review the project structure of the spring boot application.

Spring Boot Composite Key - project structure
Fig. 1: Project structure

Let us start building the application!

3. Creating a Spring Boot application

Below are the steps involved in developing the application.

3.1 Maven Dependency

Here, we specify the dependency for the Spring boot (Web and JPA), H2 database, Java Faker (to generate the dummy data), and Lombok. The updated file will have the following code.

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
         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>2.4.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.springboot.compositekey</groupId>
    <artifactId>SpringbootCompositeKey</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>SpringbootCompositeKey</name>
    <description>Composite key in springboot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
		<dependency>
			<groupId>com.github.javafaker</groupId>
			<artifactId>javafaker</artifactId>
			<version>1.0.2</version>
		</dependency>

		<dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </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>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

3.2 Application properties file

Create a new properties file at the location: SpringbootCompositeKey/src/main/resources/ and add the following code to it. Here we will define the H2 database connection, database creation, and h2 console details. You’re free to change the application or the database details as per your wish.

application. properties

server.port=9800
spring.application.name=springboot-compositekey-tutorial
# h2 database settings
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
# db-creation settings
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.properties.hibernate.show_sql=true
## browser url for h2 console - http://localhost:9800/h2-console
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console

3.3 Java Classes

Let us write the important java class(es) involved in this application. For brevity, we will skip the following classes –

  • BookRepository.java – Repository interface that extends the CrudRepository interface to perform the SQL operations. The interface provides an explicit implementation to the findByIdentityIsbnId and findByIdentityId methods
  • BookService.java – Service class that interact with the DAO layer methods
  • DefaultBooksLoader.java – Bootstrap class to populate dummy data to the h2 database once the application is started successfully
  • FakerConfig.java – Configuration class to create the Faker object for autowired injection
  • EntityNotFound.java – Exception class for throwing the not found exception when the entity is not present in the database. The exception class is annotated with the HTTP 404 error response code

3.3.1 Implementation/Main class

Add the following code to the main class to bootstrap the application from the main method. Always remember, the entry point of the spring boot application is the class containing @SpringBootApplication annotation and the static main method.

SpringbootCompositeKeyApplication.java

package com.springboot.compositekey;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

// lombok annotation
@Slf4j
// spring annotation
@SpringBootApplication
public class SpringbootCompositeKeyApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringbootCompositeKeyApplication.class, args);
		log.info("Springboot and composite key application is started successfully.");
	}
}

3.3.2 Entity classes

In order to create a composite key relationship in spring boot, we will create two classes where the identity class would be annotated with the @Embeddable annotation and the other class would contain a parameter annotated with the @EmbeddedId annotation. Let us create the identity class where we will specify the composite relationship between two columns and the class will be annotated with @Embeddable annotation.

BookIdentity.java

package com.springboot.compositekey.entity;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.Column;
import javax.persistence.Embeddable;
import java.io.Serializable;

//class contain more than 1 primary key columns.

//lombok annotations
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
//spring jpa annotation
@Embeddable
public class BookIdentity implements Serializable {

    @Column(nullable = false)
    int id;
    @Column(name = "isbn_id", nullable = false)
    String isbnId;
}

Let us create the entity class. The class will contain the attribute annotated with the EmbeddedId annotation and specifies the composite key.

Book.java

package com.springboot.compositekey.entity;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;

import javax.persistence.*;
import java.time.LocalDateTime;

//entity class to ber persisted in the db

//spring jpa annotations
@Entity
@Table(name = "book")
//lombok annotations
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
//spring annotation
@Component
public class Book {

    //composite primary key
    @EmbeddedId
    BookIdentity identity;
    String title;
    String author;
    String genre;
    String publisher;
    int quantity;
    @Column(name = "published_on")
    LocalDateTime publishedOn;
}

3.3.3 Controller class

Add the following code to the controller class to specify the different endpoints to fetch the data from the database.

BookController.java

package com.springboot.compositekey.controller;

import com.springboot.compositekey.entity.Book;
import com.springboot.compositekey.exception.EntityNotFound;
import com.springboot.compositekey.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import java.util.List;

//spring annotations
@RestController
@RequestMapping("/api")
public class BookController {

    @Autowired
    BookService service;

    //get all books
    //URL - http://localhost:9800/api/books
    @GetMapping("/books")
    @ResponseStatus(HttpStatus.OK)
    public List<Book> getBooks() {
        return service.getAll();
    }

    //get book my composite key
    //URL - http://localhost:9800/api/book-by-composite-key?id=1&isbn-id=56d015bc-2b6f-4de0-a0a7-23cf1cda80f0
    @GetMapping("/book-by-composite-key")
    @ResponseStatus(HttpStatus.OK)
    public Book getBookByCompositeKey(@RequestParam(name = "id") final int id,
                                      @RequestParam(name = "isbn-id") final String isbnId)
            throws EntityNotFound {
        return service.findByBookAndIsbnId(id, isbnId);
    }

    //find all books by isbn id
    //URL - http://localhost:9800/api/book-by-isbn-id?isbn-id=56d015bc-2b6f-4de0-a0a7-23cf1cda80f0
    @GetMapping("/book-by-isbn-id")
    @ResponseStatus(HttpStatus.OK)
    public Book getBookByIsbnId(@RequestParam(name = "isbn-id") final String isbnId)
            throws EntityNotFound {
        return service.findByIdentityIsbnId(isbnId);
    }

    //find all books by id
    //URL - http://localhost:9800/api/books-by-id?id=1
    @GetMapping("/books-by-id")
    @ResponseStatus(HttpStatus.OK)
    public List<Book> getBooksById(@RequestParam(name = "id") final int id) {
        return service.findByIdentityId(id);
    }
}

4. Run the Application

To execute the application, right-click on the SpringbootCompositeKeyApplication.java class, Run As -> Java Application.

Spring Boot Composite Key - run the app
Fig. 2: Run the Application

5. Project Demo

When the application is started, open the Postman tool to hit the application endpoints. You are free to choose any tool of your choice. You can hit the get-all-books endpoint to fetch the dummy details and can later use the other HTTP GET endpoints to fetch the details by specifying the query parameter values.

Application endpoints

-- HTTP GET endpoints –
//get all books
http://localhost:9800/api/books

//get book my composite key
http://localhost:9800/api/book-by-composite-key?id=1&isbn-id=56d015bc-2b6f-4de0-a0a7-23cf1cda80f0

//find all books by isbn id
http://localhost:9800/api/book-by-isbn-id?isbn-id=56d015bc-2b6f-4de0-a0a7-23cf1cda80f0

//find all books by id
http://localhost:9800/api/books-by-id?id=1

That is all for this tutorial and I hope the article served you whatever you were looking for. Happy Learning and do not forget to share!

6. Summary

In this section, you learned,

  • Spring boot and Lombok introduction
  • Steps to implement composite key in a spring boot application

You can download the sample application as an Eclipse project in the Downloads section.

7. Download the Project

This was an example of implementing a composite key in a spring boot application.

Download
You can download the full source code of this example here: Spring Boot Composite Key Example

Yatin

An experience full-stack engineer well versed with Core Java, Spring/Springboot, MVC, Security, AOP, Frontend (Angular & React), and cloud technologies (such as AWS, GCP, Jenkins, Docker, K8).
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
abe
abe
2 years ago

i do th same but i got error

Back to top button